From 4befcf757e1361dea854bc3221ed8cb7d6c76f2c Mon Sep 17 00:00:00 2001 From: Felix Eckhofer <felix@eckhofer.com> Date: Sat, 21 Dec 2024 02:02:26 +0100 Subject: [PATCH] Restrict signups to shiftcoordinator role --- app/controllers/application_controller.rb | 6 ++++++ app/controllers/assignments_controller.rb | 1 + app/controllers/candidates_controller.rb | 2 ++ app/helpers/application_helper.rb | 1 + app/javascript/controllers/session_controller.js | 4 ++++ app/views/assignments/_user_avatar.html.erb | 2 +- app/views/candidates/_user_avatar.html.erb | 2 +- app/views/sessions/_session.html.erb | 1 + .../20241220201657_add_shiftcoordinator_to_users.rb | 5 +++++ db/schema.rb | 8 ++++---- 10 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20241220201657_add_shiftcoordinator_to_users.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index fde1425..a470bde 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -6,4 +6,10 @@ class ApplicationController < ActionController::Base def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:invitation_token]) end + + def authorize_shiftcoordinator + unless current_user.shiftcoordinator? + render plain: 'Forbidden', status: :forbidden + end + end end diff --git a/app/controllers/assignments_controller.rb b/app/controllers/assignments_controller.rb index 878c06c..6270499 100644 --- a/app/controllers/assignments_controller.rb +++ b/app/controllers/assignments_controller.rb @@ -1,6 +1,7 @@ require 'icalendar/tzinfo' class AssignmentsController < ApplicationController + before_action :authorize_shiftcoordinator, except: [:index, :by_user] before_action :set_session, :set_users def index diff --git a/app/controllers/candidates_controller.rb b/app/controllers/candidates_controller.rb index 0907937..94bff98 100644 --- a/app/controllers/candidates_controller.rb +++ b/app/controllers/candidates_controller.rb @@ -1,6 +1,8 @@ require 'icalendar/tzinfo' class CandidatesController < ApplicationController + before_action :authorize_shiftcoordinator, except: [:create, :destroy_self] + def create @session = Session.find_by(ref_id: params[:session_ref_id]) @conference = Conference.find_by(slug: params[:conference_slug]) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6a2eda1..2dd6bf2 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -2,6 +2,7 @@ module ApplicationHelper def body_data_attributes attributes = {} attributes[:loggedin_uid] = current_user.id if user_signed_in? + attributes[:is_shiftcoordinator] = 1 if current_user&.shiftcoordinator? { data: attributes } end end diff --git a/app/javascript/controllers/session_controller.js b/app/javascript/controllers/session_controller.js index e58fcfd..a3a9872 100644 --- a/app/javascript/controllers/session_controller.js +++ b/app/javascript/controllers/session_controller.js @@ -14,6 +14,7 @@ export default class extends Controller { connect() { const uid = document.body.dataset.loggedinUid; const isCandidate = this.candidatesTarget.querySelector(`a.candidate[data-candidate-uid="${uid}"]`); + const isShiftcoordinator = document.body.dataset.isShiftcoordinator; this.element.querySelectorAll('.only-loggedin').forEach(el => { hide(el, !uid); @@ -27,6 +28,9 @@ export default class extends Controller { this.element.querySelectorAll('.only-no-candidate').forEach(el => { hide(el, isCandidate); }); + this.element.querySelectorAll('.only-shiftcoordinator').forEach(el => { + hide(el, !isShiftcoordinator); + }); } submitWithPrompt(event) { diff --git a/app/views/assignments/_user_avatar.html.erb b/app/views/assignments/_user_avatar.html.erb index 8f1cc9b..a22856e 100644 --- a/app/views/assignments/_user_avatar.html.erb +++ b/app/views/assignments/_user_avatar.html.erb @@ -1,7 +1,7 @@ <% user = assignment.user %> <span class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10" style="background-color: <%= user.avatar_color %>" title="<%= user.name %>"> <span style="color: <%= user.text_color %>"><%= user.name %></span> - <button type="button" class="group relative -mr-1 size-3.5 rounded-sm hover:bg-gray-500/20"> + <button type="button" class="only-shiftcoordinator hidden group relative -mr-1 size-3.5 rounded-sm hover:bg-gray-500/20"> <%= link_to conference_session_assignment_path(assignment.session.conference, assignment.session, assignment), data: { turbo_method: :delete, confirm: 'Are you sure?' }, method: :delete do %> <span class="sr-only">Remove</span> <svg viewBox="0 0 14 14" class="size-3.5 stroke-gray-600/50 group-hover:stroke-gray-600/75" style="stroke: <%= user.text_color %>"> diff --git a/app/views/candidates/_user_avatar.html.erb b/app/views/candidates/_user_avatar.html.erb index 8d2c0c8..382cef8 100644 --- a/app/views/candidates/_user_avatar.html.erb +++ b/app/views/candidates/_user_avatar.html.erb @@ -2,7 +2,7 @@ <% session = candidate.session %> <span class="gap-x-0.5 rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10" style="background-color: <%= user.avatar_color %>" title="<%= user.name %>"> <span style="color: <%= user.text_color %>"><%= user.name %></span> - <button type="button" class="group relative -mr-1 size-3.5 rounded-sm hover:bg-gray-500/20"> + <button type="button" class="only-shiftcoordinator hidden group relative -mr-1 size-3.5 rounded-sm hover:bg-gray-500/20"> <%= link_to conference_session_assignments_path(session.conference, session, user_id: user.id), class: "candidate", data: { turbo_method: :post, turbo_frame: dom_id(session), candidate_uid: user.id } do %> <span class="sr-only">Add</span> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16" stroke-width="1" class="size-3.5 stroke-gray-600/50 group-hover:stroke-gray-600/75 fill-gray-600/50" style="stroke: <%= user.text_color %>; fill: <%= user.text_color %>"> diff --git a/app/views/sessions/_session.html.erb b/app/views/sessions/_session.html.erb index c220a44..c4df7da 100644 --- a/app/views/sessions/_session.html.erb +++ b/app/views/sessions/_session.html.erb @@ -83,6 +83,7 @@ </ul> <% end %> </div> + <div class="only-shiftcoordinator hidden"> <hr> <small>unassigned (<%= unassigned_users.length %>)</small> <%= render partial: 'assignments/filteredlist', locals: { session: session, users: [] } %> diff --git a/db/migrate/20241220201657_add_shiftcoordinator_to_users.rb b/db/migrate/20241220201657_add_shiftcoordinator_to_users.rb new file mode 100644 index 0000000..228d1eb --- /dev/null +++ b/db/migrate/20241220201657_add_shiftcoordinator_to_users.rb @@ -0,0 +1,5 @@ +class AddShiftcoordinatorToUsers < ActiveRecord::Migration[7.1] + def change + add_column :users, :shiftcoordinator, :boolean, null: false, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index d37ec25..8a993e7 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_12_20_161958) do +ActiveRecord::Schema[7.1].define(version: 2024_12_20_212328) do create_table "assignments", force: :cascade do |t| t.integer "user_id", null: false t.integer "session_id", null: false @@ -270,15 +270,15 @@ ActiveRecord::Schema[7.1].define(version: 2024_12_20_161958) do create_table "users", force: :cascade do |t| t.string "name" - t.string "email", default: "", null: false + t.string "email" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "avatar_color" t.string "telegram_username" - t.string "password_digest" t.string "encrypted_password", default: "", null: false t.datetime "remember_created_at" - t.index ["email"], name: "index_users_on_email", unique: true + t.boolean "shiftcoordinator", default: false, null: false + t.string "invitation_token" end add_foreign_key "assignments", "sessions" -- GitLab