diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index fde14255b2424bf2460f3febfa4c87ae3b3308cc..a470bdedadba99cd58b7522fe8b557ca999cf6c2 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 878c06c19386d46da9c86027b391ace0d6d1521f..6270499f07cfcbb7a2b4da89578e88b959ffb69a 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 09079378d13377fd62ee1a5384b8abb09d6c7ac8..94bff982598118290861808d7f42796fe433fb8e 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 6a2eda15af99efbbfddf78c8234fd76ef8f2005d..2dd6bf2df1723d243ba95ee622f7f32684f046eb 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 e58fcfda4da894fe59306587c0cef29808a6f3ad..a3a9872c73276cc8d2b999da8e492599108d1f46 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 8f1cc9b938307ce8705c82ca4ce420b8939ff7a6..a22856edc9601909d4cf88525706a5894a68b045 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 8d2c0c89b2ff318b7ce80cbfc22667ba80075513..382cef8dddc6bb9b8b7c61d6c5b8664218197d5f 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 c220a4435a8a5a20b2e2be268067283a02dbc905..c4df7dad0fb4947a7aa17b43d6e10a522f8e19d3 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 0000000000000000000000000000000000000000..228d1ebe43931402ccfb129a259dca6cb972e5e6 --- /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 d37ec25374513331a99c1d86d95b59d1acbf3a5a..8a993e726cf15f3a5dc9fdbc8a68dd096be2c1f2 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"