From d5558f27cb52eab8cacdcee8173f1cccbb9e7724 Mon Sep 17 00:00:00 2001 From: Jaxon Avena Date: Sat, 1 Jun 2024 10:39:47 -0400 Subject: [PATCH] =?UTF-8?q?Fixes:=20#773=E2=80=A8=20The=20goal=20of=20this?= =?UTF-8?q?=20ticket=20was=20to=20add=20the=20ability=20for=20staff=20to?= =?UTF-8?q?=20deactivate=20=E2=80=98fosterer=E2=80=99=20accounts=20just=20?= =?UTF-8?q?like=20how=20=E2=80=98staff=E2=80=99=20accounts=20can=20already?= =?UTF-8?q?=20be=20deactivated.=20A=20migration=20was=20generated=20to=20a?= =?UTF-8?q?dd=20=E2=80=98deactivated=5Fat=E2=80=99=20to=20the=20=E2=80=98a?= =?UTF-8?q?dopter=5Ffoster=5Faccount=E2=80=99=20table.=20Since=20this=20fu?= =?UTF-8?q?nctionality=20was=20going=20to=20be=20repeated=20in=20multiple?= =?UTF-8?q?=20places=20I=20decided=20to=20refactor.=20I=20pulled=20out=20t?= =?UTF-8?q?he=20=E2=80=99staff/staff/=5Fdeactivate=5Ftoggle.html.erb?= =?UTF-8?q?=E2=80=99=20partial=20and=20put=20it=20in=20=E2=80=98app/views/?= =?UTF-8?q?partials=E2=80=99=20so=20it=20was=20more=20accessible.=20I=20th?= =?UTF-8?q?en=20refactored=20this=20to=20be=20more=20generic=20so=20multip?= =?UTF-8?q?le=20roles=20could=20use=20it.=20Related=20files=20were=20added?= =?UTF-8?q?/edited=20to=20make=20this=20work.=20For=20example,=20=E2=80=98?= =?UTF-8?q?update.turbo=5Fstream.erb=E2=80=99=20was=20added=20to=20the=20?= =?UTF-8?q?=E2=80=98staff/fosterers=E2=80=99=20directory,=20and=20the=20on?= =?UTF-8?q?e=20within=20=E2=80=98staff/staff=E2=80=99=20was=20edited=20to?= =?UTF-8?q?=20fit=20the=20refactor.=20I=E2=80=99m=20not=20sure=20if=20ther?= =?UTF-8?q?e=20is=20potential=20to=20refactor=20these=20turbo=20files=20to?= =?UTF-8?q?=20keep=20the=20code=20even=20more=20DRY.=20Also,=20=E2=80=98de?= =?UTF-8?q?activate=E2=80=99,=20=E2=80=98activate=E2=80=99,=20=E2=80=98upd?= =?UTF-8?q?ate=5Factivation=E2=80=99,=20and=20=E2=80=98set=5Ffosterer?= =?UTF-8?q?=E2=80=99=20were=20all=20added=20to=20the=20=E2=80=98fosterers?= =?UTF-8?q?=5Fcontroller.rb=E2=80=99=20to=20facilitate=20the=20new=20behav?= =?UTF-8?q?ior.=20=E2=80=98set=5Ffosterer=E2=80=99=20involved=20authentica?= =?UTF-8?q?tion=20with=20=E2=80=98Action=20Policy=E2=80=99.=20Shoutout=20t?= =?UTF-8?q?o=20@jmilljr24=20for=20hardcore=20carrying=20me=20on=20the=20ba?= =?UTF-8?q?ck=20half=20of=20this=20PR=20with=20all=20things=20related=20to?= =?UTF-8?q?=20the=20policies=20and=20routes.=20I=E2=80=99ve=20yet=20to=20a?= =?UTF-8?q?dd=20tests=20for=20this,=20but=20the=20behavior=20is=20function?= =?UTF-8?q?ing.=E2=80=A8=E2=80=A8Extra=20tidbit:=20Added=20a=20new=20gem?= =?UTF-8?q?=20to=20the=20gem=20file=20called=20"binding=5Fof=5Fcaller"=20t?= =?UTF-8?q?hat=20enables=20the=20REPL=20and=20local/instance=20variable=20?= =?UTF-8?q?inspection=20when=20an=20error=20blows=20up=20the=20website.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile | 3 ++ Gemfile.lock | 4 +++ .../staff/fosterers_controller.rb | 33 +++++++++++++++++++ app/models/adopter_foster_account.rb | 13 ++++++++ app/models/concerns/authorizable.rb | 1 + .../adopter_foster_account_policy.rb | 6 ++++ .../staff/fosterers/index.html.erb | 7 ++++ .../staff/fosterers/update.turbo_stream.erb | 2 ++ .../staff/staff/_deactivate_toggle.html.erb | 10 ------ .../organizations/staff/staff/index.html.erb | 4 +-- .../staff/staff/update.turbo_stream.erb | 4 +-- .../partials/_deactivate_toggle.html.erb | 27 +++++++++++++++ config/routes.rb | 7 +++- ...activated_at_to_adopter_foster_accounts.rb | 5 +++ db/schema.rb | 3 +- 15 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 app/views/organizations/staff/fosterers/update.turbo_stream.erb delete mode 100644 app/views/organizations/staff/staff/_deactivate_toggle.html.erb create mode 100644 app/views/partials/_deactivate_toggle.html.erb create mode 100644 db/migrate/20240531155857_add_deactivated_at_to_adopter_foster_accounts.rb diff --git a/Gemfile b/Gemfile index ea7b5bf5b..4632b57e1 100644 --- a/Gemfile +++ b/Gemfile @@ -171,3 +171,6 @@ gem "rails-controller-testing" # Use Action Policy for authorization framework gem "action_policy", "~> 0.6.9" + +# enable the REPL and local/instance variable inspection +gem "binding_of_caller" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 35c6f90cf..8e378aa8e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -111,6 +111,8 @@ GEM rouge (>= 1.0.0) bigdecimal (3.1.8) bindex (0.8.1) + binding_of_caller (1.0.1) + debug_inspector (>= 1.2.0) bootsnap (1.18.3) msgpack (~> 1.2) bootstrap (5.3.3) @@ -154,6 +156,7 @@ GEM debug (1.9.2) irb (~> 1.10) reline (>= 0.3.8) + debug_inspector (1.2.0) devise (4.9.4) bcrypt (~> 3.0) orm_adapter (~> 0.1) @@ -511,6 +514,7 @@ DEPENDENCIES annotate azure-storage-blob (~> 2.0) better_errors (~> 2.9, >= 2.9.1) + binding_of_caller bootsnap bootstrap bootstrap_form (~> 5.4) diff --git a/app/controllers/organizations/staff/fosterers_controller.rb b/app/controllers/organizations/staff/fosterers_controller.rb index 6a4c5e4e1..d7c1cfa78 100644 --- a/app/controllers/organizations/staff/fosterers_controller.rb +++ b/app/controllers/organizations/staff/fosterers_controller.rb @@ -1,9 +1,42 @@ class Organizations::Staff::FosterersController < Organizations::BaseController layout "dashboard" + before_action :set_fosterer, only: %i[update_activation] def index authorize! AdopterFosterAccount, context: {organization: Current.organization} @fosterer_accounts = authorized_scope(AdopterFosterAccount.fosterers) end + + def deactivate + @fosterer_account.deactivate + respond_to do |format| + format.html { redirect_to staff_fosterers_index_path, notice: "Fosterer account deactivated." } + format.turbo_stream { render "organizations/staff/fosterers/update" } + end + end + + def activate + @fosterer_account.activate + respond_to do |format| + format.html { redirect_to staff_fosterers_index_path, notice: "Fosterer account activated." } + format.turbo_stream { render "organizations/staff/fosterers/update" } + end + end + + def update_activation + if @fosterer_account.deactivated_at + activate + else + deactivate + end + end + + private + + def set_fosterer + @fosterer_account = AdopterFosterAccount.find(params[:fosterer_id]) + + authorize! @fosterer_account + end end diff --git a/app/models/adopter_foster_account.rb b/app/models/adopter_foster_account.rb index 47cd6c03b..952a8af8c 100644 --- a/app/models/adopter_foster_account.rb +++ b/app/models/adopter_foster_account.rb @@ -3,6 +3,7 @@ # Table name: adopter_foster_accounts # # id :bigint not null, primary key +# deactivated_at :datetime # created_at :datetime not null # updated_at :datetime not null # organization_id :bigint not null @@ -33,4 +34,16 @@ class AdopterFosterAccount < ApplicationRecord scope :fosterers, -> { joins(user: :roles).where(roles: {name: "fosterer"}) } + + def deactivate + update(deactivated_at: Time.now) unless deactivated_at + end + + def activate + update(deactivated_at: nil) if deactivated_at + end + + def deactivated? + !!deactivated_at + end end diff --git a/app/models/concerns/authorizable.rb b/app/models/concerns/authorizable.rb index 16dcb18b7..289dda7ff 100644 --- a/app/models/concerns/authorizable.rb +++ b/app/models/concerns/authorizable.rb @@ -39,6 +39,7 @@ manage_tasks view_organization_dashboard manage_faqs + manage_adopter_foster_accounts ] ).freeze diff --git a/app/policies/organizations/adopter_foster_account_policy.rb b/app/policies/organizations/adopter_foster_account_policy.rb index b79a8be66..d1508f1d3 100644 --- a/app/policies/organizations/adopter_foster_account_policy.rb +++ b/app/policies/organizations/adopter_foster_account_policy.rb @@ -2,7 +2,13 @@ class Organizations::AdopterFosterAccountPolicy < ApplicationPolicy pre_check :verify_organization! pre_check :verify_active_staff! + alias_rule :deactivate?, :update_activation?, to: :activate? + def index? permission?(:view_adopter_foster_accounts) end + + def activate? + permission?(:manage_adopter_foster_accounts) + end end diff --git a/app/views/organizations/staff/fosterers/index.html.erb b/app/views/organizations/staff/fosterers/index.html.erb index 61ff4a71d..391e2ee2a 100644 --- a/app/views/organizations/staff/fosterers/index.html.erb +++ b/app/views/organizations/staff/fosterers/index.html.erb @@ -50,6 +50,10 @@ Joined <%= fosterer.created_at.strftime("%d %B, %Y") %> +
+ Deactivate + <%= render "partials/deactivate_toggle", account: fosterer, role: 'fosterer' %> +
@@ -90,6 +94,9 @@ <%= fosterer.created_at.strftime("%d %B, %Y") %> + + <%= render "partials/deactivate_toggle", account: fosterer, role: 'fosterer' %> +
diff --git a/app/views/organizations/staff/fosterers/update.turbo_stream.erb b/app/views/organizations/staff/fosterers/update.turbo_stream.erb new file mode 100644 index 000000000..561bd2ddc --- /dev/null +++ b/app/views/organizations/staff/fosterers/update.turbo_stream.erb @@ -0,0 +1,2 @@ +<%= turbo_stream.replace_all ".deactivate_toggle_#{@fosterer_account.id}", partial: "partials/deactivate_toggle", +locals: {account: @fosterer_account, role: "fosterer"} %> \ No newline at end of file diff --git a/app/views/organizations/staff/staff/_deactivate_toggle.html.erb b/app/views/organizations/staff/staff/_deactivate_toggle.html.erb deleted file mode 100644 index 1c37945c8..000000000 --- a/app/views/organizations/staff/staff/_deactivate_toggle.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -
> - <%= form_with model: staff, url: staff_staff_update_activation_path(staff), method: "post" do |form| %> -
-
- <%= form.check_box :deactivated?,{ class: "form-check-input", - role: "switch", id: "flexSwitchCheckChecked", onchange: "this.form.requestSubmit()"}, true, false %> -
-
- <% end %> -
\ No newline at end of file diff --git a/app/views/organizations/staff/staff/index.html.erb b/app/views/organizations/staff/staff/index.html.erb index d5c409e57..fb810cd54 100644 --- a/app/views/organizations/staff/staff/index.html.erb +++ b/app/views/organizations/staff/staff/index.html.erb @@ -56,7 +56,7 @@
Deactivate - <%= render "deactivate_toggle", staff: staff %> + <%= render "partials/deactivate_toggle", account: staff, role: 'staff'%>
@@ -104,7 +104,7 @@ <%= staff.created_at.strftime("%d %B, %Y") %> - <%= render "deactivate_toggle", staff: staff %> + <%= render "partials/deactivate_toggle", account: staff, role: 'staff' %>
diff --git a/app/views/organizations/staff/staff/update.turbo_stream.erb b/app/views/organizations/staff/staff/update.turbo_stream.erb index c5c87df6d..6a5c533c6 100644 --- a/app/views/organizations/staff/staff/update.turbo_stream.erb +++ b/app/views/organizations/staff/staff/update.turbo_stream.erb @@ -1,2 +1,2 @@ -<%= turbo_stream.replace_all ".staff_deactivate_toggle_#{@staff_account.id}", partial: "deactivate_toggle", -locals: {staff: @staff_account} %> \ No newline at end of file +<%= turbo_stream.replace_all ".staff_deactivate_toggle_#{@staff_account.id}", partial: "partials/deactivate_toggle", +locals: {account: @staff_account, role: "staff"} %> \ No newline at end of file diff --git a/app/views/partials/_deactivate_toggle.html.erb b/app/views/partials/_deactivate_toggle.html.erb new file mode 100644 index 000000000..36e5a61c7 --- /dev/null +++ b/app/views/partials/_deactivate_toggle.html.erb @@ -0,0 +1,27 @@ +
> + <%= form_with model: account, url: send("staff_#{role}_update_activation_path", account), method: "post" do |form| %> +
+
+ <%= form.check_box :deactivated?, { class: "form-check-input", + role: "switch", id: "flexSwitchCheckChecked", onchange: "this.form.requestSubmit()" }, true, false %> +
+
+ <% end %> +
+ +<%# url: url_for([role.to_sym, account, :update_activation]) +fosterer_adopter_foster_account_update_activation_path %> + + +<%# +
+
+ <%= form.check_box :deactivated?,{ class: "form-check-input", + role: "switch", id: "flexSwitchCheckChecked", onchange: "this.form.requestSubmit()"}, true, false +
+
+ <% end +
+%> \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 14b738f90..8c64cefdc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -30,7 +30,11 @@ resources :adoption_application_reviews, only: %i[index edit update] resources :manage_fosters, only: %i[new create index edit update destroy] - resources :fosterers, only: %i[index] + resources :fosterers, only: %i[index] do + post "deactivate", to: "fosterers#deactivate" + post "activate", to: "fosterers#activate" + post "update_activation", to: "fosterers#update_activation" + end resources :staff do post "deactivate", to: "staff#deactivate" post "activate", to: "staff#activate" @@ -54,6 +58,7 @@ resources :dashboard, only: [:index] resources :likes, only: [:index, :create, :destroy] resources :adopter_applications, path: "applications", only: %i[index create update] + end end diff --git a/db/migrate/20240531155857_add_deactivated_at_to_adopter_foster_accounts.rb b/db/migrate/20240531155857_add_deactivated_at_to_adopter_foster_accounts.rb new file mode 100644 index 000000000..1904347b3 --- /dev/null +++ b/db/migrate/20240531155857_add_deactivated_at_to_adopter_foster_accounts.rb @@ -0,0 +1,5 @@ +class AddDeactivatedAtToAdopterFosterAccounts < ActiveRecord::Migration[7.1] + def change + add_column :adopter_foster_accounts, :deactivated_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index fccb93c88..af3221670 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_05_22_160107) do +ActiveRecord::Schema[7.1].define(version: 2024_05_31_155857) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -62,6 +62,7 @@ t.datetime "updated_at", null: false t.bigint "user_id", null: false t.bigint "organization_id", null: false + t.datetime "deactivated_at" t.index ["organization_id"], name: "index_adopter_foster_accounts_on_organization_id" t.index ["user_id"], name: "index_adopter_foster_accounts_on_user_id" end