diff --git a/app/controllers/admin/shifts_controller.rb b/app/controllers/admin/shifts_controller.rb index c0d893d69..4cfaa496c 100644 --- a/app/controllers/admin/shifts_controller.rb +++ b/app/controllers/admin/shifts_controller.rb @@ -10,6 +10,7 @@ class Admin::ShiftsController < AdminAreaController def index @staff = User + .staff .where(id: StaffSpace.where(space_id: @space_id).pluck(:user_id)) .order("LOWER(name) ASC") .pluck(:name, :id) @@ -20,14 +21,13 @@ def index StaffSpace .joins(:user) .where(space_id: @space_id) + .merge( + User.staff + ) # NOTE why isn't this the default scope? Ask Alex *again* sometime later lol .order("users.name") .each do |staff| if !staff.nil? && !staff.user.nil? - @colors << { - id: staff.user.id, - name: staff.user.name, - color: staff.color - } + @colors << { user: staff.user, color: staff.color } end end end @@ -35,6 +35,7 @@ def index def shifts @staff = User + .staff .where(id: StaffSpace.where(space_id: @space_id).pluck(:user_id)) .order("LOWER(name) ASC") .pluck(:name, :id) @@ -44,6 +45,7 @@ def shifts StaffSpace .joins(:user) .where(space_id: @space_id) + .merge(User.staff) .order("users.name") .each do |staff| if !staff.nil? && !staff.user.nil? && !staff.user_id.nil? diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index b5ed3fa3b..19847e44f 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -215,35 +215,40 @@ def toggle_lock_user # user_ids: [array of ids], role: role # for space management: # Takes a hash of { user_id: [space_id array]} - def set_role # Update user roles + # All user ids sent in this query get set to the same role # Keep staff spaces attached, even if demoted - params["user_ids"]&.each do |user_id| - user = User.find(user_id) - user.role = params[:role] - user.save + if params[:role].present? && params[:user_ids].is_a?(Array) + params[:user_ids].each do |user_id| + user = User.find(user_id) + user.role = params[:role] + user.save + end end # Update user staff spaces - params["spaces"]&.each do |user_id, spaces| - user = User.find(user_id) - if user.present? && user.staff? - space_list = spaces.present? ? spaces : [] + if params[:spaces].present? + params["spaces"]&.each do |user_id, spaces| + user = User.find(user_id) + if user.present? && user.staff? + space_list = spaces.present? ? spaces : [] - space_list.each do |space| - StaffSpace.find_or_create_by(space_id: space, user: user) - end + space_list.each do |space| + StaffSpace.find_or_create_by(space_id: space, user: user) + end - user.staff_spaces.where.not(space_id: space_list).destroy_all + user.staff_spaces.where.not(space_id: space_list).destroy_all - flash[:notice] = "Successfully changed spaces for the user." + flash[:notice] = "Successfully changed spaces for the user." + end end end # response is js respond_to do |format| format.html { redirect_back(fallback_location: root_path) } + format.json { head :ok } format.js { render layout: false } format.all { redirect_back(fallback_location: root_path) } end diff --git a/app/javascript/entrypoints/admin_availability_calendar.js b/app/javascript/entrypoints/admin_availability_calendar.js index 5a7e363bf..2afc48520 100644 --- a/app/javascript/entrypoints/admin_availability_calendar.js +++ b/app/javascript/entrypoints/admin_availability_calendar.js @@ -530,7 +530,7 @@ saveButton.addEventListener("click", () => createCalendarEvent()); const openModal = (arg) => { // Reset defaults modalTitle.innerText = "New Unavailability"; - recurringInput.checked = false; + recurringInput.checked = true; wholeDayCheckbox.checked = false; // Reset checkbox state unavailabilityId.value = ""; switchInputVisibility(recurringInput.checked); diff --git a/app/javascript/entrypoints/users.js b/app/javascript/entrypoints/users.js index 859030837..2ca819d25 100644 --- a/app/javascript/entrypoints/users.js +++ b/app/javascript/entrypoints/users.js @@ -126,4 +126,28 @@ document.addEventListener("turbo:load", function () { }, }); }); + + document.querySelectorAll("input.set-user-space-button").forEach((i) => { + i.addEventListener("change", (event) => { + // Get total space list + let space_list = [ + ...i.parentElement.querySelectorAll("input.set-user-space-button"), + ].reduce(function (result, element) { + if (element.checked) { + result.push(element.dataset.spaceId); + } + return result; + }, []); + let body = { user_ids: [i.dataset.userId], spaces: {} }; + body["spaces"][i.dataset.userId] = space_list; + fetch("/admin/users/set_role/", { + method: "PATCH", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + }); + }); }); diff --git a/app/views/admin/shifts/index.html.erb b/app/views/admin/shifts/index.html.erb index 6c091d25d..7e2f53e89 100644 --- a/app/views/admin/shifts/index.html.erb +++ b/app/views/admin/shifts/index.html.erb @@ -20,7 +20,7 @@ <% @colors.each do |user| %>
- +
diff --git a/app/views/admin/users/_user_table.html.erb b/app/views/admin/users/_user_table.html.erb index 261b78b0f..747fcd274 100644 --- a/app/views/admin/users/_user_table.html.erb +++ b/app/views/admin/users/_user_table.html.erb @@ -17,7 +17,9 @@
<% @space_list.each do |space| %> <%# use check_box_tag, not check_box, to avoid sending a 'ghost value'. In this case we do want values to be left out%> - <%= check_box_tag "spaces[#{admin.id}][]", space.id, (user_spaces[admin.id].include? space.id), form: space_form_id, class: 'btn-check', id: "space-#{space.name.parameterize.underscore}-#{admin.id}" %> + <%= check_box_tag "spaces[#{admin.id}][]", space.id, (user_spaces[admin.id].include? space.id), + form: space_form_id, class: 'btn-check set-user-space-button', id: "space-#{space.name.parameterize.underscore}-#{admin.id}", + data: { user_id: admin.id, space_id: space.id } %> <%= label_tag "space-#{space.name.parameterize.underscore}-#{admin.id}", space.name, class: "btn btn-outline-primary btn-outline-#{space.name}" %> <% end %>
diff --git a/app/views/users/tabs/_roles.html.erb b/app/views/users/tabs/_roles.html.erb index c08771f35..069f970c9 100644 --- a/app/views/users/tabs/_roles.html.erb +++ b/app/views/users/tabs/_roles.html.erb @@ -3,7 +3,8 @@
- <%= form_tag set_role_admin_users_path(@user, user_ids: [@repo_user.id]), method: :patch do %> + <%= form_tag set_role_admin_users_path, method: :patch do %> + <%= hidden_field_tag :'user_ids[]', @repo_user.id %>

<%= radio_button_tag :role, 'admin', @repo_user.admin?, class: 'form-check-input role-button', id: 'role_admin' %> @@ -19,7 +20,7 @@ <% @space_list.each do |space| %> <% color = space.assigned_color %>
- <%= check_box_tag 'space[]', space.id, @staff_spaces.include?(space.id), class: 'form-check-input', id: "space_#{space.id}" %> + <%= check_box_tag "spaces[#{@repo_user.id}][]", space.id, @staff_spaces.include?(space.id), class: 'form-check-input', id: "space_#{space.id}" %> <%= label_tag "space_#{space.id}", space.name, class: 'form-check-label' %>
<% end %> diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index adcc6f95e..95914fdff 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -1,6 +1,13 @@ require "rails_helper" RSpec.describe Admin::UsersController, type: :controller do + before(:each) do + @admin = create(:user, :admin) + session[:user_id] = @admin.id + session[:expires_at] = Time.zone.now + 10_000 + @space = create(:space) + end + describe "GET /index" do context "logged in as regular user" do it "should redirect to root" do @@ -14,10 +21,6 @@ context "logged in as admin" do before(:each) do - @admin = create(:user, :admin) - session[:user_id] = @admin.id - session[:expires_at] = Time.zone.now + 10_000 - @space = create(:space) PiReader.create( pi_mac_address: "12:34:56:78:90", pi_location: @space.name @@ -95,4 +98,67 @@ # end end end + + describe "PATCH /set_role" do + context "setting roles" do + it "should make one user into staff" do + @user = create(:user, :regular_user) + patch :set_role, params: { user_ids: [@user.id], role: "staff" } + + @user.reload + # keep staff role + expect(@user.role).to eq "staff" + # no spaces + expect(@user.staff_spaces).not_to exist + end + + it "should make multiple users into staff" do + @user_one = create :user, :regular_user + @user_two = create :user, :regular_user + patch :set_role, + params: { + user_ids: [@user_one.id, @user_two.id], + role: "staff" + } + + [@user_one, @user_two].each do |user| + user.reload + expect(user.role).to eq "staff" + expect(user.staff_spaces).not_to exist + end + end + + it "should keep assigned spaces when demoted" do + user = create :user, :staff, :with_staff_spaces + assigned_spaces = user.staff_spaces + patch :set_role, params: { user_ids: [user.id], role: "regular_user" } + user.reload + expect(user.role).to eq "regular_user" + expect(user.staff_spaces).to eq assigned_spaces + end + end + + context "assigning spaces to staff" do + it "should assign and remove a space to different users" do + @user_one = create :user, :with_staff_spaces, :staff + @user_two = create :user, :with_staff_spaces, :staff + prev_staff_spaces = @user_one.staff_spaces.pluck(:space_id) + additional_space = create(:space).id + patch :set_role, + params: { + spaces: { + @user_two.id => [], + @user_one.id => prev_staff_spaces << additional_space + } + }, + as: :json # to keep the empty array + [@user_one, @user_two].each do |user| + user.reload + expect(user.role).to eq "staff" + end + expect(@user_one.staff_spaces.pluck :space_id).to eq(prev_staff_spaces) + expect(@user_two.staff_spaces.pluck :space_id).to eq [] + end + end + end end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 043350bf2..cda829290 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -99,6 +99,15 @@ student_id { Faker::Number.number(digits: 9) } end + trait :with_staff_spaces do + # https://thoughtbot.github.io/factory_bot/cookbook/has_many-associations.html + # Make two spaces + #create_list(:staff_spaces, 2, user: instance) + after(:create) do |user| + 2.times { StaffSpace.new(user:, space: create(:space)).save! } + end + end + factory :user_with_announcements do transient { announcements_count { 5 } } after(:create) do |user, evaluator|