summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/controllers/users_controller.rb27
-rw-r--r--app/helpers/users_helper.rb9
-rw-r--r--app/models/user.rb51
-rw-r--r--app/views/users/_user.html.erb13
-rw-r--r--app/views/users/edit.html.erb14
-rw-r--r--app/views/users/index.html.erb55
-rw-r--r--app/views/users/new.html.erb14
-rw-r--r--app/views/users/show.html.erb6
8 files changed, 135 insertions, 54 deletions
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index cb71db23..95dff220 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -9,14 +9,20 @@ class UsersController < ApplicationController
9 9
10 layout 'admin' 10 layout 'admin'
11 11
12 ROLE_PRESETS = {
13 "editor" => [],
14 "redaktion" => ["redaktion"],
15 "admin" => ["admin", "redaktion"]
16 }.freeze
17
18 GROUP_ORDER = [:admin, :redaktion, :editor, :alumni].freeze
19
12 def index 20 def index
13 @users = User.order("login ASC").all.group_by do |user| 21 @users = User.order("login ASC").all.group_by(&:role_group)
14 user.admin? ? :admin : :user
15 end
16 end 22 end
17 23
18 def new 24 def new
19 @user = User.new(admin: params[:admin].present?) 25 @user = User.new(:roles => ROLE_PRESETS.fetch(params[:preset], []))
20 end 26 end
21 27
22 def create 28 def create
@@ -35,8 +41,7 @@ class UsersController < ApplicationController
35 41
36 def update 42 def update
37 permitted = user_params 43 permitted = user_params
38 permitted.delete(:admin) unless current_user.is_admin? 44
39
40 if @user.update(permitted) 45 if @user.update(permitted)
41 flash[:notice] = t("flash.users.updated", :login => @user.login) 46 flash[:notice] = t("flash.users.updated", :login => @user.login)
42 redirect_to user_path(@user) 47 redirect_to user_path(@user)
@@ -63,9 +68,13 @@ class UsersController < ApplicationController
63 private 68 private
64 69
65 def user_params 70 def user_params
66 allowed = [:login, :email, :password, :password_confirmation] 71 permitted = params.fetch(:user, {})
67 allowed << :admin if current_user.admin? 72 .permit(:login, :email, :password, :password_confirmation,
68 params.fetch(:user, {}).permit(allowed) 73 :roles => [])
74 # Checkbox arrays post a leading blank from the hidden field.
75 permitted[:roles] = Array(permitted[:roles]).reject(&:blank?) if permitted.key?(:roles)
76 permitted.delete(:roles) unless current_user.is_admin?
77 permitted
69 end 78 end
70 79
71 def find_user 80 def find_user
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
deleted file mode 100644
index ff031387..00000000
--- a/app/helpers/users_helper.rb
+++ /dev/null
@@ -1,9 +0,0 @@
1module UsersHelper
2 def user_list_by_admin_status
3 if current_user && current_user.admin
4 render :partial => 'admin_user_item', :collection => @users
5 else
6 render :partial => 'user_item', :collection => @users
7 end
8 end
9end
diff --git a/app/models/user.rb b/app/models/user.rb
index e1eff059..2e9da86c 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -9,6 +9,8 @@ class User < ApplicationRecord
9 include Authentication 9 include Authentication
10 include Authentication::ByPassword 10 include Authentication::ByPassword
11 11
12 ROLES = %w[redaktion admin alumni].freeze
13
12 # Validations 14 # Validations
13 validates_presence_of :login 15 validates_presence_of :login
14 validates_length_of :login, :within => 1..40 16 validates_length_of :login, :within => 1..40
@@ -22,6 +24,8 @@ class User < ApplicationRecord
22 validates_format_of :email, :with => Authentication.email_regex, 24 validates_format_of :email, :with => Authentication.email_regex,
23 :message => Authentication.bad_email_message 25 :message => Authentication.bad_email_message
24 26
27 validate :roles_are_known
28
25 # Authenticates a user by their login name and unencrypted password. Returns the user or nil. 29 # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
26 def self.authenticate(login, password) 30 def self.authenticate(login, password)
27 return if login.blank? || password.blank? 31 return if login.blank? || password.blank?
@@ -60,7 +64,45 @@ class User < ApplicationRecord
60 end 64 end
61 65
62 def is_admin? 66 def is_admin?
63 !!admin 67 roles.include?("admin")
68 end
69
70 # Compatibility shims for the users form, which posts user[admin] as a
71 # checkbox. Goes away when that form learns about roles.
72 def admin
73 is_admin?
74 end
75
76 def admin?
77 is_admin?
78 end
79
80 def admin=(value)
81 if ActiveModel::Type::Boolean.new.cast(value)
82 self.roles = (roles | ["admin"])
83 else
84 self.roles = (roles - ["admin"])
85 end
86 end
87
88 def redaktion?
89 roles.include?("redaktion")
90 end
91
92 def alumni?
93 roles.include?("alumni")
94 end
95
96 def role_group
97 return :alumni if alumni?
98 return :admin if is_admin?
99 return :redaktion if redaktion?
100 :editor
101 end
102
103 # Human-readable role names, for the list and the forms.
104 def role_labels
105 roles.map { |r| I18n.t("users.roles.#{r}", :default => r) }
64 end 106 end
65 107
66 # otp_secret present == enrolled. otp_pending_secret holds the secret 108 # otp_secret present == enrolled. otp_pending_secret holds the secret
@@ -133,4 +175,11 @@ class User < ApplicationRecord
133 end 175 end
134 true 176 true
135 end 177 end
178
179 private
180
181 def roles_are_known
182 unknown = roles.to_a - ROLES
183 errors.add(:roles, :unknown, :list => unknown.join(", ")) if unknown.any?
184 end
136end 185end
diff --git a/app/views/users/_user.html.erb b/app/views/users/_user.html.erb
index 9c6466a2..04884be8 100644
--- a/app/views/users/_user.html.erb
+++ b/app/views/users/_user.html.erb
@@ -1,11 +1,16 @@
1<% users.each do |user| %> 1<% users.each do |user| %>
2<tr> 2<tr>
3 <td class="user_login"><%= user.login %></td> 3 <td class="user_login"><%= user.login %></td>
4 <td><%= link_to "show", user_path(user) %></td> 4 <td class="user_roles">
5 <% if current_user.admin? || current_user == user %> 5 <% if user.roles.any? %>
6 <td> 6 <%= user.role_labels.join(", ") %>
7 <%= link_to "edit", edit_user_path(user) %> 7 <% else %>
8 <span class="field_hint"><%= t(".no_roles") %></span>
9 <% end %>
8 </td> 10 </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>
9 <td> 14 <td>
10 <%= button_to user_path(user), method: :delete, 15 <%= button_to user_path(user), method: :delete,
11 form: { data: { confirm: t(".confirm_destroy", :login => user.login) }, class: 'button_to destructive' } do %> 16 form: { data: { confirm: t(".confirm_destroy", :login => user.login) }, class: 'button_to destructive' } do %>
diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb
index 9df93815..ad2e0891 100644
--- a/app/views/users/edit.html.erb
+++ b/app/views/users/edit.html.erb
@@ -21,8 +21,18 @@
21 <div class="layout_row_content"><%= f.password_field :password_confirmation, :autocomplete => "new-password" %></div> 21 <div class="layout_row_content"><%= f.password_field :password_confirmation, :autocomplete => "new-password" %></div>
22 22
23 <% if current_user.admin? %> 23 <% if current_user.admin? %>
24 <div class="layout_row_label"><%= t("users.labels.admin") %></div> 24 <div class="layout_row_label"><%= t("users.labels.roles") %></div>
25 <div class="layout_row_content"><%= f.check_box :admin %></div> 25 <div class="layout_row_content">
26 <% User::ROLES.each do |role| %>
27 <label class="role_choice">
28 <%= check_box_tag "user[roles][]", role, @user.roles.include?(role),
29 :id => "user_roles_#{role}" %>
30 <%= t("users.roles.#{role}") %>
31 <span class="field_hint"><%= t("users.role_hints.#{role}") %></span>
32 </label>
33 <% end %>
34 <%= hidden_field_tag "user[roles][]", "" %>
35 </div>
26 <% end %> 36 <% end %>
27 37
28 <div class="layout_row_label"></div> 38 <div class="layout_row_label"></div>
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb
index 0a003cb1..854811a2 100644
--- a/app/views/users/index.html.erb
+++ b/app/views/users/index.html.erb
@@ -1,27 +1,32 @@
1<h1><%= t(".admins") %></h1> 1<h1><%= t(".title") %></h1>
2<%= link_to new_user_path(admin: true), class: 'action_button' do %> 2
3 <%= icon("plus", library: "tabler", "aria-hidden": true) %> <%= t(".create_admin") %> 3<p class="button_row">
4<% end %> 4 <% UsersController::ROLE_PRESETS.each_key do |preset| %>
5<table class="user_table"> 5 <%= link_to new_user_path(:preset => preset), class: 'action_button' do %>
6 <tr class="header"> 6 <%= icon("plus", library: "tabler", "aria-hidden": true) %>
7 <th><%= t("users.labels.login") %></th> 7 <%= t(".create_#{preset}") %>
8 <th></th> 8 <% end %>
9 <th></th> 9 <% end %>
10 <th></th> 10</p>
11 </tr>
12 <%= render :partial => "user", :locals => {:users => @users[:admin] ||= []} %>
13</table>
14 11
15<h1><%= t(".users") %></h1> 12<% UsersController::GROUP_ORDER.each do |group| %>
16<%= link_to new_user_path, class: 'action_button' do %> 13 <% members = @users[group] || [] %>
17 <%= icon("plus", library: "tabler", "aria-hidden": true) %> <%= t(".create_user") %> 14 <h2 class="user_group_heading <%= "user_group_alumni" if group == :alumni %>">
15 <%= t(".group_#{group}") %>
16 <span class="dashboard_widget_meta"><%= members.size %></span>
17 </h2>
18 <% if members.any? %>
19 <table class="user_table <%= "user_table_alumni" if group == :alumni %>">
20 <tr class="header">
21 <th><%= t("users.labels.login") %></th>
22 <th><%= t("users.labels.roles") %></th>
23 <th></th>
24 <th></th>
25 <th></th>
26 </tr>
27 <%= render :partial => "user", :locals => { :users => members } %>
28 </table>
29 <% else %>
30 <p class="field_hint"><%= t(".group_empty") %></p>
31 <% end %>
18<% end %> 32<% end %>
19<table class="user_table">
20 <tr class="header">
21 <th><%= t("users.labels.login") %></th>
22 <th></th>
23 <th></th>
24 <th></th>
25 </tr>
26 <%= render :partial => "user", :locals => {:users => @users[:user] ||= []} %>
27</table>
diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb
index 776e6e96..8d99fd92 100644
--- a/app/views/users/new.html.erb
+++ b/app/views/users/new.html.erb
@@ -21,8 +21,18 @@
21 <div class="layout_row_label"><%= t("users.labels.confirm") %></div> 21 <div class="layout_row_label"><%= t("users.labels.confirm") %></div>
22 <div class="layout_row_content"><%= f.password_field :password_confirmation %></div> 22 <div class="layout_row_content"><%= f.password_field :password_confirmation %></div>
23 23
24 <div class="layout_row_label"><%= t("users.labels.admin") %></div> 24 <div class="layout_row_label"><%= t("users.labels.roles") %></div>
25 <div class="layout_row_content"><%= f.check_box :admin %></div> 25 <div class="layout_row_content">
26 <% User::ROLES.each do |role| %>
27 <label class="role_choice">
28 <%= check_box_tag "user[roles][]", role, @user.roles.include?(role),
29 :id => "user_roles_#{role}" %>
30 <%= t("users.roles.#{role}") %>
31 <span class="field_hint"><%= t("users.role_hints.#{role}") %></span>
32 </label>
33 <% end %>
34 <%= hidden_field_tag "user[roles][]", "" %>
35 </div>
26 36
27 <div class="layout_row_label"></div> 37 <div class="layout_row_label"></div>
28 <div class="layout_row_content"><%= f.submit t("admin.common.create") %></div> 38 <div class="layout_row_content"><%= f.submit t("admin.common.create") %></div>
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb
index 44976800..a320e53e 100644
--- a/app/views/users/show.html.erb
+++ b/app/views/users/show.html.erb
@@ -19,7 +19,9 @@
19 <div class="layout_row_label"><%= t("users.labels.email") %></div> 19 <div class="layout_row_label"><%= t("users.labels.email") %></div>
20 <div class="layout_row_content"><%= @user.email %></div> 20 <div class="layout_row_content"><%= @user.email %></div>
21 21
22 <div class="layout_row_label"><%= t("users.labels.admin") %></div> 22 <div class="layout_row_label"><%= t("users.labels.roles") %></div>
23 <div class="layout_row_content"><%= @user.admin ? t("admin.common.yes") : t("admin.common.no") %></div> 23 <div class="layout_row_content">
24 <%= @user.roles.any? ? @user.role_labels.join(", ") : t("users.no_roles") %>
25 </div>
24 </div> 26 </div>
25</div> 27</div>