summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/controllers/users_controller.rb23
-rw-r--r--app/helpers/node_actions_helper.rb14
-rw-r--r--app/models/node_action.rb5
-rw-r--r--app/models/user.rb20
-rw-r--r--app/views/users/_user.html.erb22
5 files changed, 71 insertions, 13 deletions
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 95dff220..7bf23f17 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -4,7 +4,7 @@ class UsersController < ApplicationController
4 # Private 4 # Private
5 5
6 before_action :login_required 6 before_action :login_required
7 before_action :find_user, :only => [:show, :edit, :update, :destroy, :reset_otp] 7 before_action :find_user, :only => [:show, :edit, :update, :reset_otp, :deactivate, :reactivate]
8 before_action :verify_status, :except => [:index, :show] 8 before_action :verify_status, :except => [:index, :show]
9 9
10 layout 'admin' 10 layout 'admin'
@@ -53,8 +53,25 @@ class UsersController < ApplicationController
53 def show 53 def show
54 end 54 end
55 55
56 def destroy 56 def deactivate
57 @user.destroy if @user 57 return deny_user_access unless current_user.is_admin?
58
59 if @user == current_user
60 flash[:error] = t("flash.users.cannot_deactivate_self")
61 elsif @user.deactivate!(:actor => current_user)
62 flash[:notice] = t("flash.users.deactivated", :login => @user.login)
63 end
64
65 redirect_to users_path
66 end
67
68 def reactivate
69 return deny_user_access unless current_user.is_admin?
70
71 if @user.reactivate!(:actor => current_user)
72 flash[:notice] = t("flash.users.reactivated", :login => @user.login)
73 end
74
58 redirect_to users_path 75 redirect_to users_path
59 end 76 end
60 77
diff --git a/app/helpers/node_actions_helper.rb b/app/helpers/node_actions_helper.rb
index 4cbe741c..f57ef84f 100644
--- a/app/helpers/node_actions_helper.rb
+++ b/app/helpers/node_actions_helper.rb
@@ -18,7 +18,9 @@ module NodeActionsHelper
18 "asset_destroy" => "file-x", 18 "asset_destroy" => "file-x",
19 "otp_enroll" => "shield-lock", 19 "otp_enroll" => "shield-lock",
20 "otp_disable" => "shield-off", 20 "otp_disable" => "shield-off",
21 "otp_reset" => "shield-x" 21 "otp_reset" => "shield-x",
22 "user_deactivate" => "user-off",
23 "user_reactivate" => "user-check"
22 }.freeze 24 }.freeze
23 25
24 def verb_icon action 26 def verb_icon action
@@ -271,4 +273,14 @@ module NodeActionsHelper
271 t("node_actions.otp_reset", :actor => actor_ref(action), 273 t("node_actions.otp_reset", :actor => actor_ref(action),
272 :target => user_participant_ref(action)).html_safe 274 :target => user_participant_ref(action)).html_safe
273 end 275 end
276
277 def summarize_user_deactivate action
278 t("node_actions.user_deactivate", :actor => actor_ref(action),
279 :target => user_participant_ref(action)).html_safe
280 end
281
282 def summarize_user_reactivate action
283 t("node_actions.user_reactivate", :actor => actor_ref(action),
284 :target => user_participant_ref(action)).html_safe
285 end
274end 286end
diff --git a/app/models/node_action.rb b/app/models/node_action.rb
index fec5a062..d619aac5 100644
--- a/app/models/node_action.rb
+++ b/app/models/node_action.rb
@@ -98,8 +98,9 @@ class NodeAction < ApplicationRecord
98 # "detached_from" -- array of unique_names, only when any 98 # "detached_from" -- array of unique_names, only when any
99 # "headline_removed_from" -- array of unique_names, only when any 99 # "headline_removed_from" -- array of unique_names, only when any
100 # 100 #
101 # "otp_enroll" / "otp_disable" / "otp_reset" (second-factor lifecycle; 101 # "otp_enroll" / "otp_disable" / "otp_reset" / "user_deactivate" /
102 # node column nil; participants: the affected User -- the table's first 102 # "user_reactivate" (second-factor lifecycle; node column nil;
103 # participants: the affected User
103 # User-typed subject. otp_disable is self-service; otp_reset is an 104 # User-typed subject. otp_disable is self-service; otp_reset is an
104 # administrator clearing someone else's factor, where actor and 105 # administrator clearing someone else's factor, where actor and
105 # participant differ): 106 # participant differ):
diff --git a/app/models/user.rb b/app/models/user.rb
index 2e9da86c..1728521a 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -105,6 +105,26 @@ class User < ApplicationRecord
105 roles.map { |r| I18n.t("users.roles.#{r}", :default => r) } 105 roles.map { |r| I18n.t("users.roles.#{r}", :default => r) }
106 end 106 end
107 107
108 def deactivate!(actor:)
109 return false if alumni?
110 transaction do
111 update_column(:roles, (roles | ["alumni"]).sort)
112 NodeAction.record!(:participants => [self], :user => actor,
113 :action => "user_deactivate", :target_login => login)
114 end
115 true
116 end
117
118 def reactivate!(actor:)
119 return false unless alumni?
120 transaction do
121 update_column(:roles, (roles - ["alumni"]).sort)
122 NodeAction.record!(:participants => [self], :user => actor,
123 :action => "user_reactivate", :target_login => login)
124 end
125 true
126 end
127
108 # otp_secret present == enrolled. otp_pending_secret holds the secret 128 # otp_secret present == enrolled. otp_pending_secret holds the secret
109 # between QR display and first-code confirmation. otp_consumed_timestep 129 # between QR display and first-code confirmation. otp_consumed_timestep
110 # makes every accepted code single-use (replay guard within the drift 130 # makes every accepted code single-use (replay guard within the drift
diff --git a/app/views/users/_user.html.erb b/app/views/users/_user.html.erb
index 04884be8..ff9d4e37 100644
--- a/app/views/users/_user.html.erb
+++ b/app/views/users/_user.html.erb
@@ -9,14 +9,22 @@
9 <% end %> 9 <% end %>
10 </td> 10 </td>
11 <td><%= link_to t("admin.common.show"), user_path(user) %></td> 11 <td><%= link_to t("admin.common.show"), user_path(user) %></td>
12 <% if current_user.admin? || current_user == user %>
13 <td><%= link_to t("admin.common.edit"), edit_user_path(user) %></td>
14 <td> 12 <td>
15 <%= button_to user_path(user), method: :delete, 13 <% if current_user.admin? || current_user == user %>
16 form: { data: { confirm: t(".confirm_destroy", :login => user.login) }, class: 'button_to destructive' } do %> 14 <%= link_to t("admin.common.edit"), edit_user_path(user) %>
17 <%= icon("trash", library: "tabler", "aria-hidden": true) %> <%= t("admin.common.destroy") %> 15 <% end %>
18 <% end %> 16 </td>
17 <td>
18 <% if current_user.admin? && current_user != user %>
19 <% if user.alumni? %>
20 <%= button_to t(".reactivate"), reactivate_user_path(user), method: :put,
21 form: { class: 'button_to state_changing' } %>
22 <% else %>
23 <%= button_to t(".deactivate"), deactivate_user_path(user), method: :put,
24 form: { data: { confirm: t(".confirm_deactivate", :login => user.login) },
25 class: 'button_to destructive' } %>
26 <% end %>
27 <% end %>
19 </td> 28 </td>
20 <% end %>
21</tr> 29</tr>
22<% end %> 30<% end %>