diff --git a/app/assets/javascripts/manage/lib/setupDataTables.js b/app/assets/javascripts/manage/lib/setupDataTables.js index ad23dfdf8..f9418bc3c 100644 --- a/app/assets/javascripts/manage/lib/setupDataTables.js +++ b/app/assets/javascripts/manage/lib/setupDataTables.js @@ -36,7 +36,7 @@ var setupDataTables = function () { ], }); - $('.datatable.admins').DataTable({ + $('.datatable.staff').DataTable({ order: [2, 'asc'], columns: [ { orderable: true, data: 'id', visible: false }, diff --git a/app/assets/javascripts/validate.js b/app/assets/javascripts/validate.js index 6eec34797..8da91b2f8 100644 --- a/app/assets/javascripts/validate.js +++ b/app/assets/javascripts/validate.js @@ -40,6 +40,15 @@ document.addEventListener('turbolinks:load', function() { } } break; + case 'phone': + if (value) { + var phoneReg = /^[\+]?[0-9]{0,3}[-\s\.]?[(]?[0-9]{1,3}[)]?[-\s\.]?[0-9]{1,3}[-\s\.]?[0-9]{4,6}$/; + if (!phoneReg.test(value)) { + notify(this, 'Please enter a valid phone number'); + success = false; + } + } + break; case 'file-max-size': if ( this.files && diff --git a/app/assets/stylesheets/application.sass b/app/assets/stylesheets/application.sass index bf1d19b10..3a4b95ddb 100644 --- a/app/assets/stylesheets/application.sass +++ b/app/assets/stylesheets/application.sass @@ -25,6 +25,7 @@ @import general/table @import forms/forms @import forms/confirmation +@import forms/autocomplete @import general/theming-editor diff --git a/app/assets/stylesheets/forms/_autocomplete.sass b/app/assets/stylesheets/forms/_autocomplete.sass new file mode 100644 index 000000000..05e044650 --- /dev/null +++ b/app/assets/stylesheets/forms/_autocomplete.sass @@ -0,0 +1,24 @@ + +// jquery ui override +.ui-autocomplete + @include css4 + background: var(--input--background--focus) + border: 1px solid var(--input--border-color--focus) + color: var(--input--text--focus) + list-style: none + padding: 0 + .ui-menu-item div + padding: 2px 5px + display: block + cursor: pointer + overflow: hidden + text-overflow: ellipsis + white-space: nowrap + &:hover + @include css4 + background: var(--primary) + @include css4 + color: var(--white) +// needed for ellipsis in text to work and acts as a min-width +.ui-menu + width: 50px diff --git a/app/assets/stylesheets/forms/_forms.sass b/app/assets/stylesheets/forms/_forms.sass index 547db9e6e..f3f635423 100644 --- a/app/assets/stylesheets/forms/_forms.sass +++ b/app/assets/stylesheets/forms/_forms.sass @@ -61,6 +61,11 @@ hr .btn margin-bottom: 30px +.text-overflow-center + text-align: center + display: flex + justify-content: center + .simple_form @include css4 color: var(--grey) @@ -253,30 +258,6 @@ input[type=submit] margin-bottom: 3px -// jquery ui override -.ui-autocomplete - @include css4 - background: var(--input--background--focus) - border: 1px solid var(--input--border-color--focus) - color: var(--input--text--focus) - list-style: none - padding: 0 - .ui-menu-item div - padding: 2px 5px - display: block - cursor: pointer - overflow: hidden - text-overflow: ellipsis - white-space: nowrap - &:hover - @include css4 - background: var(--primary) - @include css4 - color: var(--white) -// needed for ellipsis in text to work and acts as a min-width -.ui-menu - width: 50px - // form wizard .wizard-stage display: none diff --git a/app/assets/stylesheets/manage.sass b/app/assets/stylesheets/manage.sass index e08c1596e..087c35ffa 100644 --- a/app/assets/stylesheets/manage.sass +++ b/app/assets/stylesheets/manage.sass @@ -3,6 +3,9 @@ @import manage/selectize-fix @import vendor/simplemde.min @import vendor/codemirror +@import general/variables +@import general/css4 +@import manage/autocomplete $grey-dark: #555 $grey-med: #999 @@ -172,6 +175,7 @@ $grey-med: #999 .sidebar-mobile .sidebar-sticky height: auto + /* * Datatable changes */ diff --git a/app/assets/stylesheets/manage/_autocomplete.sass b/app/assets/stylesheets/manage/_autocomplete.sass new file mode 100644 index 000000000..f5e716fea --- /dev/null +++ b/app/assets/stylesheets/manage/_autocomplete.sass @@ -0,0 +1,12 @@ + +@import ../forms/autocomplete + +// jquery ui override +.ui-autocomplete + background: white + border: 1px solid #333 + color: #222 + .ui-menu-item div + &:hover + background: #999 + color: white diff --git a/app/controllers/manage/application_controller.rb b/app/controllers/manage/application_controller.rb index cced5e844..111f68f62 100644 --- a/app/controllers/manage/application_controller.rb +++ b/app/controllers/manage/application_controller.rb @@ -1,27 +1,30 @@ class Manage::ApplicationController < ApplicationController before_action :logged_in - before_action :require_admin_or_limited_admin - before_action :limit_write_access_to_admins, only: ["edit", "update", "new", "create", "destroy", "convert_to_admin", "deliver", "merge", "perform_merge", "toggle_bus_captain", "duplicate", "update_acc_status", "send_update_email", "live_preview"] + before_action :require_director_or_organizer_or_volunteer + before_action :limit_write_access_to_directors, only: ["edit", "update", "new", "create", "destroy", "deliver", "merge", "perform_merge", "toggle_bus_captain", "duplicate", "update_acc_status", "send_update_email", "live_preview"] skip_before_action :verify_authenticity_token, if: :json_request? def logged_in authenticate_user! end - def require_full_admin - return redirect_to root_path unless current_user.try(:admin?) + def require_director + return redirect_to manage_checkins_path if current_user.volunteer? + return redirect_to manage_root_path if current_user.organizer? + return redirect_to root_path unless current_user.try(:director?) end - def require_admin_or_limited_admin - return redirect_to root_path unless current_user.try(:admin?) || current_user.try(:admin_limited_access?) + def require_director_or_organizer + return redirect_to manage_checkins_path if current_user.volunteer? + return redirect_to root_path unless current_user.organizing_staff? end - def require_admin_or_limited_admin_or_event_tracking - redirect_to root_path unless current_user.try(:admin?) || current_user.try(:admin_limited_access?) || current_user.try(:event_tracking?) + def require_director_or_organizer_or_volunteer + redirect_to root_path unless current_user.staff? end - def limit_write_access_to_admins - redirect_to url_for(controller: controller_name, action: :index) unless current_user.try(:admin?) + def limit_write_access_to_directors + redirect_to url_for(controller: controller_name, action: :index) unless current_user.try(:director?) end def json_request? diff --git a/app/controllers/manage/configs_controller.rb b/app/controllers/manage/configs_controller.rb index e5d8eedc9..e7b9884de 100644 --- a/app/controllers/manage/configs_controller.rb +++ b/app/controllers/manage/configs_controller.rb @@ -1,5 +1,5 @@ class Manage::ConfigsController < Manage::ApplicationController - before_action :limit_access_admin + before_action :require_director before_action :get_config, only: [:edit, :update, :update_only_css_variables] respond_to :html, :json @@ -69,7 +69,4 @@ def get_config end end - def limit_access_admin - redirect_to root_path unless current_user.admin? - end end diff --git a/app/controllers/manage/dashboard_controller.rb b/app/controllers/manage/dashboard_controller.rb index 7b2f822e0..96dcd0f65 100644 --- a/app/controllers/manage/dashboard_controller.rb +++ b/app/controllers/manage/dashboard_controller.rb @@ -1,6 +1,5 @@ class Manage::DashboardController < Manage::ApplicationController - skip_before_action :require_admin_or_limited_admin - before_action :require_admin_or_limited_admin + before_action :require_director_or_organizer def index end diff --git a/app/controllers/manage/data_exports_controller.rb b/app/controllers/manage/data_exports_controller.rb index a20b89db8..4142d1d9d 100644 --- a/app/controllers/manage/data_exports_controller.rb +++ b/app/controllers/manage/data_exports_controller.rb @@ -1,6 +1,5 @@ class Manage::DataExportsController < Manage::ApplicationController - skip_before_action :require_admin_or_limited_admin - before_action :require_full_admin + before_action :require_director before_action :set_data_export, only: [:destroy] diff --git a/app/controllers/manage/messages_controller.rb b/app/controllers/manage/messages_controller.rb index 245e2b07f..e84908fd4 100644 --- a/app/controllers/manage/messages_controller.rb +++ b/app/controllers/manage/messages_controller.rb @@ -1,7 +1,8 @@ class Manage::MessagesController < Manage::ApplicationController + before_action :require_director_or_organizer before_action :set_message, only: [:show, :edit, :update, :destroy, :deliver, :preview, :duplicate] before_action :check_message_access, only: [:edit, :update, :destroy] - before_action :limit_template_access_to_admins, only: [:template, :template_preview, :template_update, :template_replace_with_default] + before_action :limit_template_access_to_directors, only: [:template, :template_preview, :template_update, :template_replace_with_default] respond_to :html, :json @@ -106,9 +107,9 @@ def template_replace_with_default private - def limit_template_access_to_admins + def limit_template_access_to_directors # From Manage::ApplicationController - limit_write_access_to_admins + limit_write_access_to_directors end def message_params diff --git a/app/controllers/manage/questionnaires_controller.rb b/app/controllers/manage/questionnaires_controller.rb index ca14c9d85..ce2ed1218 100644 --- a/app/controllers/manage/questionnaires_controller.rb +++ b/app/controllers/manage/questionnaires_controller.rb @@ -1,7 +1,7 @@ class Manage::QuestionnairesController < Manage::ApplicationController include QuestionnairesControllable - before_action :set_questionnaire, only: [:show, :edit, :update, :destroy, :check_in, :convert_to_admin, :update_acc_status] + before_action :set_questionnaire, only: [:show, :edit, :update, :destroy, :check_in, :update_acc_status] respond_to :html, :json @@ -95,14 +95,14 @@ def check_in redirect_to index_redirect_path end - def convert_to_admin - user = @questionnaire.user - @questionnaire.destroy - user.update_attributes(role: :admin) - redirect_to edit_manage_user_path(user) - end - def destroy + if @questionnaire.is_bus_captain + directors = User.where(role: :director) + directors.each do |user| + StaffMailer.bus_captain_left(@questionnaire.bus_list_id, @questionnaire.user_id, user.id).deliver_later + end + end + @questionnaire.destroy respond_with(:manage, @questionnaire) end diff --git a/app/controllers/manage/stats_controller.rb b/app/controllers/manage/stats_controller.rb index 459285f71..5426424e1 100644 --- a/app/controllers/manage/stats_controller.rb +++ b/app/controllers/manage/stats_controller.rb @@ -1,4 +1,5 @@ class Manage::StatsController < Manage::ApplicationController + before_action :require_director_or_organizer respond_to :html, :json diff --git a/app/controllers/manage/trackable_events_controller.rb b/app/controllers/manage/trackable_events_controller.rb index 1bd812fb5..28cb7059b 100644 --- a/app/controllers/manage/trackable_events_controller.rb +++ b/app/controllers/manage/trackable_events_controller.rb @@ -1,9 +1,6 @@ class Manage::TrackableEventsController < Manage::ApplicationController - skip_before_action :require_admin_or_limited_admin - before_action :require_admin_or_limited_admin_or_event_tracking - before_action :set_trackable_event, only: [:show, :edit, :update, :destroy] - before_action :scope_limited_admin_access, only: [:edit, :update, :destroy] + before_action :scope_organizer_access, only: [:edit, :update, :destroy] respond_to :html, :json @@ -81,13 +78,13 @@ def trackable_event_params params.require(:trackable_event).permit(:band_id, :trackable_tag_id) end - # Permit limited-access admins (overrides Manage::ApplicationController#limit_write_access_to_admins) - def limit_write_access_to_admins + # Permit limited-access directors (overrides Manage::ApplicationController#limit_write_access_to_directors) + def limit_write_access_to_directors end - # If the user isn't a full admin, scope changes only to those they created - def scope_limited_admin_access - return if current_user.admin? || @trackable_event.blank? || @trackable_event.user.blank? + # If the user isn't a director, scope changes only to those they created + def scope_organizer_access + return if current_user.director? || @trackable_event.blank? || @trackable_event.user.blank? redirect_to manage_trackable_events_path, notice: 'You may not view events you did not create.' if @trackable_event.user != current_user end end diff --git a/app/controllers/manage/trackable_tags_controller.rb b/app/controllers/manage/trackable_tags_controller.rb index 525643772..852ea9f5d 100644 --- a/app/controllers/manage/trackable_tags_controller.rb +++ b/app/controllers/manage/trackable_tags_controller.rb @@ -1,7 +1,4 @@ class Manage::TrackableTagsController < Manage::ApplicationController - skip_before_action :require_admin_or_limited_admin - before_action :require_admin_or_limited_admin_or_event_tracking - before_action :set_trackable_tag, only: [:show, :edit, :update, :destroy] respond_to :html, :json diff --git a/app/controllers/manage/users_controller.rb b/app/controllers/manage/users_controller.rb index e64fad0e0..e5d743166 100644 --- a/app/controllers/manage/users_controller.rb +++ b/app/controllers/manage/users_controller.rb @@ -1,19 +1,19 @@ class Manage::UsersController < Manage::ApplicationController - before_action :require_full_admin + before_action :require_director before_action :find_user, only: [:show, :edit, :update, :destroy] respond_to :html, :json def index - respond_with(:manage, User.where(role: [:admin, :admin_limited_access, :event_tracking])) + respond_with(:manage, User.where(role: [:director, :organizer, :volunteer])) end def user_datatable render json: UserDatatable.new(params, view_context: view_context) end - def admin_datatable - render json: AdminDatatable.new(params, view_context: view_context) + def staff_datatable + render json: StaffDatatable.new(params, view_context: view_context) end def show diff --git a/app/controllers/questionnaires_controller.rb b/app/controllers/questionnaires_controller.rb index 633547842..3cb3763b6 100644 --- a/app/controllers/questionnaires_controller.rb +++ b/app/controllers/questionnaires_controller.rb @@ -58,6 +58,7 @@ def create if current_user.reload.questionnaire.present? return redirect_to questionnaires_path, notice: 'Application already exists.' end + return unless HackathonConfig['accepting_questionnaires'] @questionnaire = Questionnaire.new(convert_school_name_to_id(questionnaire_params)) @questionnaire.user_id = current_user.id @@ -93,8 +94,14 @@ def update # DELETE /apply # DELETE /apply.json def destroy - @questionnaire.destroy + if @questionnaire.is_bus_captain + directors = User.where(role: :director) + directors.each do |user| + StaffMailer.bus_captain_left(@questionnaire.bus_list_id, @questionnaire.user_id, user.id).deliver_later + end + end + @questionnaire.destroy respond_to do |format| format.html { redirect_to questionnaires_url } format.json { head :no_content } diff --git a/app/controllers/rsvps_controller.rb b/app/controllers/rsvps_controller.rb index 32cfc9881..85a61defd 100644 --- a/app/controllers/rsvps_controller.rb +++ b/app/controllers/rsvps_controller.rb @@ -43,6 +43,10 @@ def deny # rubocop:disable CyclomaticComplexity # rubocop:disable PerceivedComplexity def update + # save to check if bus status changes after rsvp + bus = @questionnaire.bus_list_id + acc_status = @questionnaire.acc_status + unless @questionnaire.update_attributes(params.require(:questionnaire).permit(:agreement_accepted, :phone)) flash[:alert] = @questionnaire.errors.full_messages.join(", ") redirect_to rsvp_path @@ -58,6 +62,17 @@ def update update_acc_status update_bus_list + bus_after_rsvp = @questionnaire.bus_list_id + acc_status_after_rsvp = @questionnaire.acc_status + + if bus != nil && (acc_status != acc_status_after_rsvp || bus != bus_after_rsvp) && @questionnaire.is_bus_captain == true + @questionnaire.is_bus_captain = false + directors = User.where(role: :director) + directors.each do |user| + StaffMailer.bus_captain_left(@questionnaire.bus_list_id, @questionnaire.user_id, user.id).deliver_later + end + end + unless @questionnaire.save flash[:alert] = @questionnaire.errors.full_message.join(", ") redirect_to rsvp_path diff --git a/app/datatables/questionnaire_datatable.rb b/app/datatables/questionnaire_datatable.rb index 48f04cc8e..6ff70041c 100644 --- a/app/datatables/questionnaire_datatable.rb +++ b/app/datatables/questionnaire_datatable.rb @@ -35,7 +35,7 @@ def note(record) def bus_captain(record) return "No" unless record.bus_list_id? - return record.is_bus_captain? ? 'Yes' : "No" unless current_user.admin? + return record.is_bus_captain? ? 'Yes' : "No" unless current_user.director? if record.is_bus_captain? link_to("Remove", toggle_bus_captain_manage_bus_list_path(record.bus_list_id, questionnaire_id: record.id, bus_captain: "0"), method: "post", class: "text-danger") @@ -47,7 +47,7 @@ def bus_captain(record) def data records.map do |record| { - bulk: current_user.admin? ? "".html_safe : "", + bulk: current_user.director? ? "".html_safe : "", link: link_to(''.html_safe, manage_questionnaire_path(record)), note: note(record), id: record.id, diff --git a/app/datatables/admin_datatable.rb b/app/datatables/staff_datatable.rb similarity index 94% rename from app/datatables/admin_datatable.rb rename to app/datatables/staff_datatable.rb index d34cb8a61..01c39c922 100644 --- a/app/datatables/admin_datatable.rb +++ b/app/datatables/staff_datatable.rb @@ -1,4 +1,4 @@ -class AdminDatatable < ApplicationDatatable +class StaffDatatable < ApplicationDatatable def_delegators :@view, :link_to, :manage_user_path, :bold, :display_datetime def view_columns @@ -43,6 +43,6 @@ def data end def get_raw_records - User.where(role: [:admin, :admin_limited_access, :event_tracking]) + User.where(role: [:director, :organizer, :volunteer]) end end diff --git a/app/jobs/bulk_message_job.rb b/app/jobs/bulk_message_job.rb index 2989e6564..3af60748e 100644 --- a/app/jobs/bulk_message_job.rb +++ b/app/jobs/bulk_message_job.rb @@ -27,11 +27,11 @@ def self.build_recipients(recipient_types) def self.user_ids(type) case type when "all" - # Everyone, including admins that completed a questionnaire - User.non_admins.pluck(:id) + Questionnaire.pluck(:user_id) + # Everyone, including organizers that completed a questionnaire + User.non_organizer.pluck(:id) + Questionnaire.pluck(:user_id) when "incomplete" - # Incomplete applications, excluding admins that don't have a questionnaire - User.non_admins.pluck(:id) - Questionnaire.pluck(:user_id) + # Incomplete applications, excluding organizers that don't have a questionnaire + User.non_organizer.pluck(:id) - Questionnaire.pluck(:user_id) when "complete" Questionnaire.pluck(:user_id) when "accepted" diff --git a/app/jobs/admin_weekly_report_job.rb b/app/jobs/staff_weekly_report_job.rb similarity index 71% rename from app/jobs/admin_weekly_report_job.rb rename to app/jobs/staff_weekly_report_job.rb index 5c3f7b0c5..5e78e0fa7 100644 --- a/app/jobs/admin_weekly_report_job.rb +++ b/app/jobs/staff_weekly_report_job.rb @@ -1,11 +1,11 @@ -class AdminWeeklyReportJob < ApplicationJob +class StaffWeeklyReportJob < ApplicationJob queue_as :default def perform # Queue all eligible users and let the is_active (or other) logic determine if they should really receive it users = User.where(receive_weekly_report: true) users.each do |user| - AdminMailer.weekly_report(user.id).deliver_later + StaffMailer.weekly_report(user.id).deliver_later end end end diff --git a/app/mailers/mail_preview.rb b/app/mailers/mail_preview.rb index d29bda648..18d63abf8 100644 --- a/app/mailers/mail_preview.rb +++ b/app/mailers/mail_preview.rb @@ -5,8 +5,8 @@ def bulk_message_email UserMailer.bulk_message_email(message, User.first.id) end - def admin_weekly_report - AdminMailer.weekly_report(User.first.id) + def staff_weekly_report + StaffMailer.weekly_report(User.first.id) end end end diff --git a/app/mailers/admin_mailer.rb b/app/mailers/staff_mailer.rb similarity index 79% rename from app/mailers/admin_mailer.rb rename to app/mailers/staff_mailer.rb index 2fd2d8bb6..5c08c4cd9 100644 --- a/app/mailers/admin_mailer.rb +++ b/app/mailers/staff_mailer.rb @@ -1,8 +1,8 @@ -class AdminMailer < ApplicationMailer +class StaffMailer < ApplicationMailer include Roadie::Rails::Automatic add_template_helper(HackathonManagerHelper) - layout "admin_mailer" + layout "staff_mailer" def weekly_report(user_id) # Don't send emails more than 7 days after event starts @@ -42,6 +42,17 @@ def weekly_report(user_id) ) end + def bus_captain_left(bus_list_id, former_captain_id, user_id) + @bus_route = BusList.find_by_id(bus_list_id) + @former_captain = User.find_by_id(former_captain_id) + @user = User.find_by_id(user_id) + + mail( + to: pretty_email(@user.full_name, @user.email), + subject: "Bus Captain Left Bus Route: " + @bus_route.name, + ) + end + private def report_metric(query_base, new_query_field) diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 42cc88df2..ef1d03cf2 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -16,8 +16,15 @@ def bulk_message_email(message_id, user_id, message = nil, use_examples = false) def incomplete_reminder_email(user_id) @user = User.find_by_id(user_id) - return if @user.blank? || @user.admin? || @user.questionnaire || Time.now.to_date > Date.parse(HackathonConfig["last_day_to_apply"]) + return if @user.blank? || @user.director? || @user.questionnaire || Time.now.in_time_zone.to_date > Date.parse(HackathonConfig["last_day_to_apply"]).in_time_zone.to_date Message.queue_for_trigger("user.24hr_incomplete_application", @user.id) end + + def rsvp_reminder_email(user_id) + @user = User.find_by_id(user_id) + return if @user.blank? || !@user.questionnaire.acc_status == "accepted" || Time.now.in_time_zone.to_date > Date.parse(HackathonConfig["event_start_date"]).in_time_zone.to_date + + Message.queue_for_trigger("questionnaire.rsvp_reminder", @user.id) + end end diff --git a/app/models/message.rb b/app/models/message.rb index f98ee83bf..a25dfec09 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -37,6 +37,7 @@ class Message < ApplicationRecord "questionnaire.late_waitlist" => "Questionnaire Status: Waitlisted, Late", "questionnaire.rsvp_confirmed" => "Questionnaire Status: RSVP Confirmed", "questionnaire.rsvp_denied" => "Questionnaire Status: RSVP Denied", + "questionnaire.rsvp_reminder" => "Questionnaire: RSVP Reminder", "user.24hr_incomplete_application" => "User: Incomplete application (24 hours later)", "bus_list.new_captain_confirmation" => "Bus List: New captain confirmation", "bus_list.notes_update" => "Bus List: Updated notes (manually triggered)" diff --git a/app/models/questionnaire.rb b/app/models/questionnaire.rb index 973b96dad..1cb47671e 100644 --- a/app/models/questionnaire.rb +++ b/app/models/questionnaire.rb @@ -10,6 +10,7 @@ class Questionnaire < ApplicationRecord before_validation :clean_negative_dietary_restrictions after_create :queue_triggered_email_create after_update :queue_triggered_email_update + after_update :queue_triggered_email_rsvp_reminder after_save :update_school_questionnaire_count after_destroy :update_school_questionnaire_count @@ -137,6 +138,12 @@ def vcs_url=(value) super value end + def phone=(value) + # strips the string to just numbers for standardization + value = value.try(:tr, '^0-9', '') + super value + end + def school School.find(school_id) if school_id end @@ -249,4 +256,18 @@ def queue_triggered_email_update def queue_triggered_email_create Message.queue_for_trigger("questionnaire.#{acc_status}", user_id) end + + def queue_triggered_email_rsvp_reminder + if saved_change_to_acc_status? && acc_status == "accepted" + days_remaining = Date.parse(HackathonConfig["event_start_date"]).in_time_zone.to_date - Time.now.in_time_zone.to_date + if days_remaining > 14 + deliver_date = 7.days.from_now + elsif days_remaining > 10 + deliver_date = 5.days.from_now + elsif days_remaining > 3 + deliver_date = 2.days.from_now + end + UserMailer.rsvp_reminder_email(user_id).deliver_later(wait_until: deliver_date) if deliver_date.present? + end + end end diff --git a/app/models/user.rb b/app/models/user.rb index 3b5de0bd2..00f16f4d6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -23,7 +23,7 @@ class User < ApplicationRecord after_create :queue_reminder_email after_initialize :set_default_role, if: :new_record? - enum role: { user: 0, event_tracking: 1, admin_limited_access: 2, admin: 3 } + enum role: { user: 0, volunteer: 1, organizer: 2, director: 3 } def set_default_role self.role ||= :user @@ -56,6 +56,14 @@ def full_name "#{first_name} #{last_name}" end + def staff? + director? || organizer? || volunteer? + end + + def organizing_staff? + director? || organizer? + end + def self.from_omniauth(auth) matching_provider = where(provider: auth.provider, uid: auth.uid) matching_email = where(email: auth.info.email) @@ -75,11 +83,11 @@ def self.from_omniauth(auth) current_user end - def self.non_admins - User.where.not(role: :admin).where.not(role: :admin_limited_access) + def self.non_organizer + User.where.not(role: :director).where.not(role: :organizer) end def self.without_questionnaire - non_admins.left_outer_joins(:questionnaire).where(questionnaires: { id: nil }) + non_organizer.left_outer_joins(:questionnaire).where(questionnaires: { id: nil }) end end diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml index 76f92f72b..4a866a98e 100644 --- a/app/views/devise/passwords/edit.html.haml +++ b/app/views/devise/passwords/edit.html.haml @@ -2,7 +2,7 @@ .form-container.password .section-title.center Change Your - %span.emphasized Password + .emphasized Password = simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| = f.error_notification = f.input :reset_password_token, as: :hidden diff --git a/app/views/devise/passwords/new.html.haml b/app/views/devise/passwords/new.html.haml index 18281428a..b856f1727 100644 --- a/app/views/devise/passwords/new.html.haml +++ b/app/views/devise/passwords/new.html.haml @@ -2,6 +2,6 @@ .form-container.password %h1.section-title.center Reset Your - %span.emphasized Password + .emphasized Password = render 'form' diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index e0e19883e..50d55651b 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -2,7 +2,7 @@ .form-container.signup %h1.section-title.center Register for - %span.emphasized= HackathonConfig['name'] + .emphasized.text-overflow-center= HackathonConfig['name'] - if !HackathonConfig['accepting_questionnaires'] || HackathonConfig['disclaimer_message'].present? #disclaimer diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 822d2b20f..b9bb3896c 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -2,5 +2,5 @@ .form-container.login %h1.section-title.center Sign in to - %span.emphasized= HackathonConfig['name'] + .emphasized.text-overflow-center= HackathonConfig['name'] = render 'form' diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index a44fe61d7..91427e44d 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -10,6 +10,8 @@ = btn_link_to "Home", homepage_url .header-nav - if user_signed_in? - - if current_user.admin? or current_user.admin_limited_access? + - if current_user.organizing_staff? = btn_link_to "Manage", manage_root_path + - elsif current_user.volunteer? + = btn_link_to "Manage", manage_checkins_path = btn_link_to "Sign Out", destroy_user_session_path, method: :delete diff --git a/app/views/layouts/manage/_page_title.html.haml b/app/views/layouts/manage/_page_title.html.haml index 4affee59c..d4b2a0e3c 100644 --- a/app/views/layouts/manage/_page_title.html.haml +++ b/app/views/layouts/manage/_page_title.html.haml @@ -4,5 +4,5 @@ - if defined?(subtitle) && subtitle.present? %small.text-muted= subtitle - - if current_user.try(:admin?) + - if current_user.try(:director?) = yield diff --git a/app/views/layouts/manage/application.html.haml b/app/views/layouts/manage/application.html.haml index 730a76151..c529658dd 100644 --- a/app/views/layouts/manage/application.html.haml +++ b/app/views/layouts/manage/application.html.haml @@ -28,20 +28,32 @@ %h6.sidebar-heading.d-flex.justify-content-between.align-items-center.px-3.mt-4.mb-1.text-muted %span = t(:overview, scope: 'layouts.manage.navigation') - %ul.nav.flex-column.mb-2 - %li.nav-item - = active_link_to manage_root_path, class: "nav-link", active_children: false do - .fa.fa-area-chart.fa-fw.icon-space-r-half - = t(:title, scope: 'pages.manage.dashboard') - %li.nav-item - = active_link_to manage_questionnaires_path, class: "nav-link" do - .fa.fa-inbox.fa-fw.icon-space-r-half - = t(:title, scope: 'pages.manage.questionnaires') - %li.nav-item - = active_link_to manage_messages_path, class: "nav-link" do - .fa.fa-bullhorn.fa-fw.icon-space-r-half - = t(:title, scope: 'pages.manage.messages') + - if current_user.organizing_staff? + %ul.nav.flex-column.mb-2 + %li.nav-item + = active_link_to manage_root_path, class: "nav-link", active_children: false do + .fa.fa-area-chart.fa-fw.icon-space-r-half + = t(:title, scope: 'pages.manage.dashboard') + %li.nav-item + = active_link_to manage_questionnaires_path, class: "nav-link" do + .fa.fa-inbox.fa-fw.icon-space-r-half + = t(:title, scope: 'pages.manage.questionnaires') + %li.nav-item + = active_link_to manage_messages_path, class: "nav-link" do + .fa.fa-bullhorn.fa-fw.icon-space-r-half + = t(:title, scope: 'pages.manage.messages') + - elsif current_user.volunteer? + %ul.nav.flex-column.mb-2 + %li.nav-item + = active_link_to manage_checkins_path, class: "nav-link" do + .fa.fa-drivers-license-o.fa-fw.icon-space-r-half + = t(:title, scope: 'pages.manage.check-in') + %li.nav-item + = active_link_to manage_questionnaires_path, class: "nav-link" do + .fa.fa-inbox.fa-fw.icon-space-r-half + = t(:title, scope: 'pages.manage.questionnaires') + - if current_user.organizing_staff? %h6.sidebar-heading.d-flex.justify-content-between.align-items-center.px-3.mt-4.mb-1.text-muted %span = t(:logistics, scope: 'layouts.manage.navigation') @@ -59,20 +71,20 @@ .fa.fa-tag.fa-fw.icon-space-r-half = t(:title, scope: 'pages.manage.trackable-tags') - %h6.sidebar-heading.d-flex.justify-content-between.align-items-center.px-3.mt-4.mb-1.text-muted - %span - = t(:travel, scope: 'layouts.manage.navigation') - %ul.nav.flex-column.mb-2 - %li.nav-item - = active_link_to manage_bus_lists_path, class: "nav-link" do - .fa.fa-bus.fa-fw.icon-space-r-half - = t(:title, scope: 'pages.manage.bus-lists') - %li.nav-item - = active_link_to manage_schools_path, class: "nav-link" do - .fa.fa-home.fa-fw.icon-space-r-half - = t(:title, scope: 'pages.manage.schools') + %h6.sidebar-heading.d-flex.justify-content-between.align-items-center.px-3.mt-4.mb-1.text-muted + %span + = t(:travel, scope: 'layouts.manage.navigation') + %ul.nav.flex-column.mb-2 + %li.nav-item + = active_link_to manage_bus_lists_path, class: "nav-link" do + .fa.fa-bus.fa-fw.icon-space-r-half + = t(:title, scope: 'pages.manage.bus-lists') + %li.nav-item + = active_link_to manage_schools_path, class: "nav-link" do + .fa.fa-home.fa-fw.icon-space-r-half + = t(:title, scope: 'pages.manage.schools') - - if current_user.admin? + - if current_user.director? %h6.sidebar-heading.d-flex.justify-content-between.align-items-center.px-3.mt-4.mb-1.text-muted %span = t(:administration, scope: 'layouts.manage.navigation') diff --git a/app/views/layouts/admin_mailer.html.erb b/app/views/layouts/staff_mailer.html.erb similarity index 100% rename from app/views/layouts/admin_mailer.html.erb rename to app/views/layouts/staff_mailer.html.erb diff --git a/app/views/manage/application/_questionnaire_datatable.html.haml b/app/views/manage/application/_questionnaire_datatable.html.haml index 61f33683c..a985b3d44 100644 --- a/app/views/manage/application/_questionnaire_datatable.html.haml +++ b/app/views/manage/application/_questionnaire_datatable.html.haml @@ -19,7 +19,7 @@ %thead %tr %th{'data-table': { orderable: 'false', data: 'bulk', visible: bulk_actions ? 'true' : 'false' }} - - if current_user.admin? + - if current_user.director? %input{ type: "checkbox", name: "select_allc", value: "1", data: { bulk_row_select: "" } } %th{'data-table': { orderable: 'false', data: 'link', visible: visible.call('link', columns) }} %th{'data-table': { orderable: 'false', data: 'note', visible: visible.call('note', columns) }} diff --git a/app/views/manage/bus_lists/show.html.haml b/app/views/manage/bus_lists/show.html.haml index d13c65b9c..1bc51c05b 100644 --- a/app/views/manage/bus_lists/show.html.haml +++ b/app/views/manage/bus_lists/show.html.haml @@ -59,7 +59,7 @@ %th Email %th Phone Number %th School - - if current_user.admin? + - if current_user.director? %th Actions %tbody - @bus_list.passengers.select { |q| q.bus_captain_interest }.each do |p| @@ -70,7 +70,7 @@ %td= p.email %td= phone_link_to p.phone %td= link_to p.school.name, manage_school_path(p.school) - - if current_user.admin? + - if current_user.director? %td - if p.is_bus_captain? = link_to "Remove Bus Captain", toggle_bus_captain_manage_bus_list_path(@bus_list, questionnaire_id: p.id, bus_captain: '0'), method: 'post', class: 'text-danger' diff --git a/app/views/manage/configs/edit.html.haml b/app/views/manage/configs/edit.html.haml index 45919bdcf..3a2dda9e7 100644 --- a/app/views/manage/configs/edit.html.haml +++ b/app/views/manage/configs/edit.html.haml @@ -1,6 +1,6 @@ :ruby text_field_vars = %w() - markdown_field_vars = %w(bus_captain_notes thanks_for_rsvp_message thanks_for_applying_message disclaimer_message) + markdown_field_vars = %w(bus_captain_notes thanks_for_rsvp_message thanks_for_applying_message questionnaires_closed_message disclaimer_message) css_field_vars = %w(custom_css) form_field_vars = %w(disabled_fields) diff --git a/app/views/manage/messages/_message_template_status.haml b/app/views/manage/messages/_message_template_status.haml index 6677e267f..971ee2c82 100644 --- a/app/views/manage/messages/_message_template_status.haml +++ b/app/views/manage/messages/_message_template_status.haml @@ -5,7 +5,7 @@ %span.badge.badge-danger.mb-1 Using customized template %br Not in sync with HackathonManager - - if current_user.try(:admin?) + - if current_user.try(:director?) %br %small = link_to template_replace_with_default_manage_messages_path, method: :post, data: { confirm: 'Are you sure? This will permanently erase the existing template and replace it with the HackathonManager default. This action is irreversible.'} do diff --git a/app/views/manage/messages/index.html.haml b/app/views/manage/messages/index.html.haml index 7c8299518..8fd7b7a12 100644 --- a/app/views/manage/messages/index.html.haml +++ b/app/views/manage/messages/index.html.haml @@ -19,7 +19,7 @@ = render 'triggered_email_summary' -- if current_user.try(:admin?) +- if current_user.try(:director?) .mb-4 %h3.pb-2.mb-3.border-bottom#triggered-email-overview Message Template %p The message template is used for all outgoing emails. If desired, it may be customized to your needs. diff --git a/app/views/manage/questionnaires/_form.html.haml b/app/views/manage/questionnaires/_form.html.haml index 189d88215..b52c22783 100644 --- a/app/views/manage/questionnaires/_form.html.haml +++ b/app/views/manage/questionnaires/_form.html.haml @@ -11,23 +11,25 @@ .card-body - if @questionnaire&.user&.provider == 'mlh' %h6.card-subtitle.mb-2 - %span.badge.badge-info Provided by My MLH + %span.badge.badge-info Provided by MyMLH = f.simple_fields_for :user, @questionnaire.user do |u| = u.input :first_name, input_html: { "data-validate" => "presence" }, label: "First Name", autofocus: true = u.input :last_name, input_html: { "data-validate" => "presence" }, label: "Last Name" = f.input :email, input_html: { "data-validate" => "presence email", value: @questionnaire.user.try(:email) }, required: true, hint: 'Can be an existing user (without a questionnaire) or a new user. If this is a new user, they will receive a randomly-generated password that they must request a password reset for.' = f.input :phone, input_html: { "data-validate" => "presence" } = f.input :date_of_birth, start_year: Date.today.year - 18, end_year: Date.today.year - 90, order: [:month, :day, :year], input_html: { "data-validate" => "presence" } - = f.input :school_id, as: :school_selection, input_html: { "data-validate" => "presence" } = f.input :level_of_study, input_html: { "data-validate" => "presence" } = f.input :major, input_html: { "data-validate" => "presence" } - = f.input :shirt_size, as: :select, collection: Questionnaire::POSSIBLE_SHIRT_SIZES, include_blank: "(select one...)", input_html: { "data-validate" => "presence" } = f.input :gender, input_html: { "data-validate" => "presence" } - = f.input :dietary_restrictions, label: "Dietary restrictions" - = f.input :special_needs, label: "Special needs" .col-xl-6 + .card.mb-4 + .card-header Special notices + .card-body + = f.input :shirt_size, as: :select, collection: Questionnaire::POSSIBLE_SHIRT_SIZES, include_blank: "(select one...)", input_html: { "data-validate" => "presence" } + = f.input :dietary_restrictions, label: "Dietary restrictions" + = f.input :special_needs, label: "Special needs" .card.mb-4 .card-header Resume .card-body diff --git a/app/views/manage/questionnaires/show.html.haml b/app/views/manage/questionnaires/show.html.haml index 54d910fa9..eceae3356 100644 --- a/app/views/manage/questionnaires/show.html.haml +++ b/app/views/manage/questionnaires/show.html.haml @@ -9,14 +9,8 @@ = render 'check_in_badge' .btn-group{role: "group"} - - if current_user.admin? + - if current_user.director? = link_to 'Edit', edit_manage_questionnaire_path(@questionnaire), class: 'btn btn-sm btn-outline-secondary' - - if current_user.admin? - .btn-group{role: "group"} - %button.btn.btn-sm.btn-outline-secondary.dropdown-toggle#title-actions{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", type: "button"} - .fa.fa-cog - .dropdown-menu.dropdown-menu-right{"aria-labelledby" => "title-actions"} - = link_to 'Convert to Admin', convert_to_admin_manage_questionnaire_path(@questionnaire), method: :patch, data: { confirm: "Are you sure? The questionnaire for \"#{@questionnaire.user.full_name}\" will be permanently erased, and \"#{@questionnaire.email}\" will become an admin. This action is irreversible." }, class: 'dropdown-item' = render 'overview' @@ -40,7 +34,7 @@ - else = "(no author)" = @questionnaire.acc_status_date ? display_datetime(@questionnaire.acc_status_date, in_sentence: true) : "(no date)" - - if current_user.admin? + - if current_user.director? = bs_vertical_simple_form @questionnaire, url: url_for(action: "update_acc_status", controller: "questionnaires") do |f| = f.input :acc_status, as: :select, collection: Questionnaire::POSSIBLE_ACC_STATUS.invert, include_blank: false, label: "Acceptance Status:", hint: "Updating this status may trigger an automatic email to the applicant - see #{link_to('messages', manage_messages_path(anchor: 'triggered-email-overview'))} for details.".html_safe = f.button :submit, value: "Update Status", class: 'btn-primary' diff --git a/app/views/manage/trackable_events/index.html.haml b/app/views/manage/trackable_events/index.html.haml index ae63ad9ca..8a4f51b77 100644 --- a/app/views/manage/trackable_events/index.html.haml +++ b/app/views/manage/trackable_events/index.html.haml @@ -28,7 +28,7 @@ %td= trackable_event.trackable_tag.name %td= trackable_event.user.email %td= link_to 'Show', manage_trackable_event_path(trackable_event) - - if current_user.admin? || current_user == trackable_event.user + - if current_user.director? || current_user == trackable_event.user %td= link_to 'Edit', edit_manage_trackable_event_path(trackable_event) %td= link_to 'Destroy', manage_trackable_event_path(trackable_event), method: :delete, data: { confirm: 'Are you sure?' } - else diff --git a/app/views/manage/trackable_tags/show.html.haml b/app/views/manage/trackable_tags/show.html.haml index c9ad2ece3..a25899c6f 100644 --- a/app/views/manage/trackable_tags/show.html.haml +++ b/app/views/manage/trackable_tags/show.html.haml @@ -34,7 +34,7 @@ %td= trackable_event.band_id %td= trackable_event.user.email %td - - if current_user.admin? || current_user == trackable_event.user + - if current_user.director? || current_user == trackable_event.user = link_to 'Edit', edit_manage_trackable_event_path(trackable_event) .row.mt-2.mb-4 diff --git a/app/views/manage/users/index.html.haml b/app/views/manage/users/index.html.haml index 6a0a96855..0b9b8a286 100644 --- a/app/views/manage/users/index.html.haml +++ b/app/views/manage/users/index.html.haml @@ -27,7 +27,7 @@ .col %h5.dashboard-container-title = t(:staff, scope: 'pages.manage.users', hackathon_name: HackathonConfig['name']) - %table.admins.datatable.table.table-striped.table-hover{ "data-source" => admin_datatable_manage_users_path(format: :json) } + %table.staff.datatable.table.table-striped.table-hover{ "data-source" => staff_datatable_manage_users_path(format: :json) } %thead %tr %th= t(:id, scope: 'pages.manage.users.table') diff --git a/app/views/questionnaires/_form.html.haml b/app/views/questionnaires/_form.html.haml index 4e8c45f8c..b895acebe 100644 --- a/app/views/questionnaires/_form.html.haml +++ b/app/views/questionnaires/_form.html.haml @@ -10,7 +10,7 @@ = markdown(HackathonConfig['disclaimer_message']) .form-inputs - = f.input :phone, label: "Phone number", input_html: { "data-validate" => "presence" } + = f.input :phone, label: "Phone number", input_html: { "data-validate" => ["presence", "phone"] } = f.input :date_of_birth, start_year: Date.today.year - 5, end_year: Date.today.year - 90, order: [:month, :day, :year], input_html: { "data-validate" => "presence" } = f.input :school_id, as: :school_selection, input_html: { "data-validate" => "presence" } diff --git a/app/views/questionnaires/new.html.haml b/app/views/questionnaires/new.html.haml index 45cd8202d..6d389312f 100644 --- a/app/views/questionnaires/new.html.haml +++ b/app/views/questionnaires/new.html.haml @@ -1,7 +1,23 @@ -- title "Apply" -.form-container - %h1.section-title - Apply for - %span.emphasized= HackathonConfig['name'] +- title "Application" +- if HackathonConfig['accepting_questionnaires'] + .form-container + %h1.section-title + Apply for + %span.emphasized= HackathonConfig['name'] + = render 'form' +- else + .form-container + #disclaimer + %h1.section-title + Applications Closed + %p + - if HackathonConfig['questionnaires_closed_message'].present? + = markdown(HackathonConfig['questionnaires_closed_message']) + - else + Sorry, we are no longer accepting new applications to + %strong + #{HackathonConfig['name']}. + %br + %p.session-link.right + Don't need your account? #{link_to "Delete my account", user_registration_path, data: { confirm: "Are you sure? Your account and any related data will be permanently erased." }, method: :delete} -= render 'form' diff --git a/app/views/staff_mailer/bus_captain_left.html.haml b/app/views/staff_mailer/bus_captain_left.html.haml new file mode 100644 index 000000000..7df0d04e8 --- /dev/null +++ b/app/views/staff_mailer/bus_captain_left.html.haml @@ -0,0 +1 @@ +%p Alert #{@former_captain.full_name} (#{@former_captain.email}) is no longer a bus captain for #{@bus_route.name} diff --git a/app/views/admin_mailer/weekly_report.haml b/app/views/staff_mailer/weekly_report.haml similarity index 100% rename from app/views/admin_mailer/weekly_report.haml rename to app/views/staff_mailer/weekly_report.haml diff --git a/config/app.yml b/config/app.yml index 69c47d4fe..23057decb 100644 --- a/config/app.yml +++ b/config/app.yml @@ -21,6 +21,7 @@ defaults: &defaults disclaimer_message: "" thanks_for_applying_message: "" thanks_for_rsvp_message: "" + questionnaires_closed_message: "" bus_captain_notes: "" custom_css: "" diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 591199ccb..1109083b9 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -18,7 +18,7 @@ # every time somebody will try to access the admin web interface. admin_authenticator do if current_user - head :forbidden unless current_user.admin? || current_user.admin_limited_access? + head :forbidden unless current_user.director? || current_user.organizer? else redirect_to new_user_session_url end diff --git a/config/locales/en.yml b/config/locales/en.yml index 5e62ea3fa..d3bd02c54 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -47,7 +47,7 @@ en: user: role: Limited access prevents the admin from adding, modifying, or deleting any records; modifications through the check-in process are allowed. Event tracking limits to only event tracking. is_active: Deactivating a user will prevent them from logging in. Their access will be immediately revoked from the admin and application pages. - receive_weekly_report: A weekly email report on admissions, bus lists, and messages. Only sent when there are weekly updates up until 7 days past the event. Disabled for inactive admins. + receive_weekly_report: A weekly email report on admissions, bus lists, and messages. Only sent when there are weekly updates up until 7 days past the event. Disabled for inactive staff members. message: type: Bulk emails are sent once, manually. Automated emails are sent upon a desired trigger/event. name: A friendly name to recognize this email. Applicants won't see this. @@ -55,7 +55,7 @@ en: school: is_home: The "home" school is separated from all other schools on dashboard metrics. hackathon_config: - accepting_questionnaires: Specify that questionnaires are being accepted. This does not block applying; it only changes messaging around it. + accepting_questionnaires: Specify and allow questionnaires to be accepted. last_day_to_apply: 'Last date to apply to your hackathon (format: YYYY-MM-DD)' event_start_date: 'Start date of your hackathon (format: YYYY-MM-DD)' auto_late_waitlist: Automatically set application status to "late waitlist" for new applications @@ -72,6 +72,7 @@ en: disclaimer_message: Optional message that appears before signing up & applying. Supports markdown. thanks_for_applying_message: Optional message that appears after completing an application. Supports markdown. thanks_for_rsvp_message: Optional message that appears after RSVP'ing as attending. Supports markdown. + questionnaires_closed_message: Message that replaces the new questionnaire form. Supports markdown. bus_captain_notes: Optional message that appears on the bus captain's bus list page. Supports markdown. custom_css: CSS to inject into the <head> of every public page placeholders: @@ -117,6 +118,7 @@ en: custom_css: Custom CSS homepage_url: Homepage URL thanks_for_rsvp_message: Thanks For RSVP Message + questionnaires_closed_message: Questionnaires Closed Message pages: manage: dashboard: diff --git a/config/routes.rb b/config/routes.rb index c2ae2a80b..ae9b07283 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,7 +19,7 @@ end end - authenticate :user, ->(u) { u.admin? } do + authenticate :user, ->(u) { u.director? } do mount Sidekiq::Web => "/sidekiq" mount Blazer::Engine, at: "blazer" end @@ -41,7 +41,15 @@ end namespace :manage do - root to: "dashboard#index" + authenticate :user, ->(u) { u.director? } do + root to: "dashboard#index" + end + authenticate :user, ->(u) { u.organizer? } do + root to: "dashboard#index" + end + authenticate :user, ->(u) { u.volunteer? } do + root to: "checkins#index" + end resources :dashboard do get :map_data, on: :collection get :todays_activity_data, on: :collection @@ -58,7 +66,6 @@ resources :questionnaires do post :datatable, on: :collection patch :check_in, on: :member - patch :convert_to_admin, on: :member patch :update_acc_status, on: :member patch :bulk_apply, on: :collection end @@ -67,7 +74,7 @@ end resources :users do post :user_datatable, on: :collection - post :admin_datatable, on: :collection + post :staff_datatable, on: :collection patch :reset_password, on: :member end resources :messages do diff --git a/config/schedule.yml b/config/schedule.yml index 7035ecc3f..520cc4fe0 100644 --- a/config/schedule.yml +++ b/config/schedule.yml @@ -1,3 +1,3 @@ -admin_weekly_report: +staff_weekly_report: cron: '0 8 * * MON' - class: 'AdminWeeklyReportJob' + class: 'StaffWeeklyReportJob' diff --git a/db/seed_messages/questionnaire--rsvp_reminder.md b/db/seed_messages/questionnaire--rsvp_reminder.md new file mode 100644 index 000000000..ad7577856 --- /dev/null +++ b/db/seed_messages/questionnaire--rsvp_reminder.md @@ -0,0 +1,12 @@ +## Missing RSVP + +
+

Are you coming to {{hackathon_name}}?

+

Let us know if we should expect you there!

+

+ Yes, I will Attend » + No, I Can't Attend » +
+ Link not working? Go to {{rsvp_url}} +

+
\ No newline at end of file diff --git a/db/seeds.rb b/db/seeds.rb index 28ce41ec8..b72203e26 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -15,6 +15,7 @@ "questionnaire.accepted" => "You've been accepted!", "questionnaire.denied" => "Your application status", "questionnaire.rsvp_confirmed" => "RSVP Confirmation", + "questionnaire.rsvp_reminder" => "Are you coming to #{HackathonConfig['name']}?", "user.24hr_incomplete_application" => "Incomplete application", "bus_list.new_captain_confirmation" => "You're a bus captain!", "bus_list.update_notes" => "Bus Update" @@ -25,6 +26,7 @@ "questionnaire.accepted" => "Accepted email", "questionnaire.denied" => "Denied email", "questionnaire.rsvp_confirmed" => "RSVP confirmed email", + "questionnaire.rsvp_reminder" => "RSVP Reminder", "user.24hr_incomplete_application" => "Incomplete application (24-hour reminder)", "bus_list.new_captain_confirmation" => "New bus captain confirmation", "bus_list.update_notes" => "Bus list update" diff --git a/docs/api-overview.md b/docs/api-overview.md index da4e24b63..ac81471f9 100644 --- a/docs/api-overview.md +++ b/docs/api-overview.md @@ -41,7 +41,6 @@ Example for questionnaire management endpoints: Prefix Verb URI Pattern Controller#Action datatable_manage_questionnaires POST /manage/questionnaires/datatable(.:format) manage/questionnaires#datatable check_in_manage_questionnaire PATCH /manage/questionnaires/:id/check_in(.:format) manage/questionnaires#check_in - convert_to_admin_manage_questionnaire PATCH /manage/questionnaires/:id/convert_to_admin(.:format) manage/questionnaires#convert_to_admin update_acc_status_manage_questionnaire PATCH /manage/questionnaires/:id/update_acc_status(.:format) manage/questionnaires#update_acc_status bulk_apply_manage_questionnaires PATCH /manage/questionnaires/bulk_apply(.:format) manage/questionnaires#bulk_apply manage_questionnaires GET /manage/questionnaires(.:format) manage/questionnaires#index diff --git a/docs/api-testing-setup.md b/docs/api-testing-setup.md index 03e33e690..c4767b5a0 100644 --- a/docs/api-testing-setup.md +++ b/docs/api-testing-setup.md @@ -9,7 +9,7 @@ These programs allow you to run API requests (`GET`, `POST`, and so on) in an is In order to make requests in either Postman or Paw, you need to setup _OAuth 2 authorization_, as in HackathonManager, each request needs to be authorized first. This guide discusses how to enable OAuth 2 for these apps. -This guide assumes you have already setup an admin account on a local HackathonManager instance. For more details on this, see the [main README](https://github.com/codeRIT/hackathon-manager#local-development). +This guide assumes you have already setup an account with Director status on a local HackathonManager instance. For more details on this, see the [main README](https://github.com/codeRIT/hackathon-manager#local-development). > To make API requests on a live/remote instance, simply replace `localhost` in all following commands with your HackathonManager's URL. @@ -27,7 +27,7 @@ Select an app below to jump directly to its guide: ## Connecting with Postman -In HackathonManager, sign in to your admin account and click "Manage". Then, at the bottom left of the sidebar, click the **Doorkeeper** tab. +In HackathonManager, sign in to your staff account and click "Manage". Then, at the bottom left of the sidebar, click the **Doorkeeper** tab. @@ -47,7 +47,7 @@ On this screen, fill out the information but with your own keys from the image a -You should get a popup with your hackathon's sign in screen. Type in your admin credentials and log in. +You should get a popup with your hackathon's sign in screen. Type in your staff credentials and log in. On the next screen, select `Authorize`: diff --git a/docs/deployment-dokku.md b/docs/deployment-dokku.md index 7f5c1cf04..0b080214d 100644 --- a/docs/deployment-dokku.md +++ b/docs/deployment-dokku.md @@ -6,14 +6,18 @@ title: Dokku Deployment >These docs assume you already have a virtual machine with [Dokku](http://dokku.viewdocs.io/dokku/) running on it, and can SSH into the VM. DNS should be set up as well, but isn't required for bare minimum functionality. > >If you need a VM, check out [DigitalOcean](https://m.do.co/c/b5ee103e23c3) or [Linode](https://www.linode.com/?r=e90a6fb2a6999fb4ec7b60b1add3e288f97954bf) and the [Dokku docs](http://dokku.viewdocs.io/dokku/) to get started. +> +>**Student Developer?** The [GitHub Student Developer Pack](https://education.github.com/pack?sort=popularity&tag=Cloud) has several discounts for cloud hosting, Ruby tutorials, and more! ## Setting up a new deployment -Below are steps & notes to deploy HackathonManager on Dokku. Need to update an existing deployment? +Below are steps to deploy a new HackathonManager instance on Dokku. To update an existing Dokku deployment, check out our [updating docs](updating-hm.html). + +If you have any questions, please don't hesitate to reach out to the [codeRIT Engineering Team](mailto:engineering@coderit.org)! This doc is very much a work in progress but we want to keep it as up to date as possible. -If you have any questions at all, please don't hesitate to reach out to the [codeRIT Engineering Team](mailto:engineering@coderit.org)! This doc is very much a work in progress but we want to keep it as up to date as possible. +## Dokku Setup -## Dokku plugins +### Plugins Currently used and required Dokku plugins (other than the defaults): @@ -21,9 +25,9 @@ Currently used and required Dokku plugins (other than the defaults): - [Redis](https://github.com/dokku/dokku-redis) (background jobs + caching) - [dokku-letsencrypt](https://github.com/dokku/dokku-letsencrypt) (Optional: free, automated SSL certificates) -### Dokku Setup Steps +### Setup Steps -**We'll be using `hm` as the app name in these steps,** as well as sharing the same `hm` name for both the app, database, and redis name. You're free to use another names. +**We'll be using `hm` as the app name in these steps,** as well as sharing the same `hm` name for both the app, database, and redis name. You're free to use other names. ```bash dokku apps:create hm @@ -103,14 +107,14 @@ dokku letsencrypt hm - Deploy should succeed without any red flags in the build log - Should be able to submit an application on the website & receive an immediate confirmation email -### Promote account to admin +### Promote account to director ```bash dokku enter hm web # Wait for a bash shell to start... $ bin/rails c # Wait for the Rails console to start... -User.find_by(email: "your-email@example.com").update_attribute(:role, :admin) +User.find_by(email: "your-email@example.com").update_attribute(:role, :director) exit exit ``` @@ -177,4 +181,4 @@ In order to support groupdate, timezone tables must be created. ```bash mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u $OPENSHIFT_MYSQL_DB_USERNAME -p mysql -``` \ No newline at end of file +``` diff --git a/docs/deployment-okd.md b/docs/deployment-okd.md index 69c00fcf8..23468082f 100644 --- a/docs/deployment-okd.md +++ b/docs/deployment-okd.md @@ -152,7 +152,7 @@ spec: 1. Seed the database (schools, emails, etc) -- do this **before** you create your first user 2. Apply as a hacker -3. Manually promote your (first) account to an admin +3. Manually promote your (first) account to a director 4. Configure your hackathon ### Seed the database @@ -170,7 +170,7 @@ exit 1. Open your hackathon's website, create an account, and complete an application 2. Validate that you received a confirmation email (if you didn't, don't fix it now, but take note for later) -### Manually promote your account to admin status +### Manually promote your account to director status 1. On the OKD website, navigate to the currently-running HackathonManager pod (Applications -> Pods -> Click the HM pod in the list) 2. In the tab bar, click "Terminal" @@ -178,7 +178,7 @@ exit ```bash bin/rails c # Wait for the Rails console to start... -User.find_by(email: "your-email@example.com").update_attribute(:role, :admin) +User.find_by(email: "your-email@example.com").update_attribute(:role, :director) exit exit ``` diff --git a/docs/messages.md b/docs/messages.md index 9131d1553..c47392f52 100644 --- a/docs/messages.md +++ b/docs/messages.md @@ -53,7 +53,7 @@ Automated emails can also be sent out upon certain events happening. All events * **Questionnaire status** — Upon being accepted, denied, RSVP'd, etc * **Bust list** — Becoming a passenger or bus captain -These messages are sent immediatley upon an applicant entering the given state. For example, when an admin marks someone as "accepted," they will immediately receive any automated messages associated with the "Questionnaire Status: Accepted" event. +These messages are sent immediatley upon an applicant entering the given state. For example, when a staff member marks someone as "accepted," they will immediately receive any automated messages assocaited with the "Questionnaire Status: Accepted" event. ## Message formatting diff --git a/test/controllers/bus_lists_controller_test.rb b/test/controllers/bus_lists_controller_test.rb index c32066764..e50ecd7fc 100644 --- a/test/controllers/bus_lists_controller_test.rb +++ b/test/controllers/bus_lists_controller_test.rb @@ -19,7 +19,7 @@ class BusListsControllerTest < ActionController::TestCase context "while authenticated without a questionnaire" do setup do - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] @user = create(:user, email: "newabc@example.com") sign_in @user end @@ -37,7 +37,7 @@ class BusListsControllerTest < ActionController::TestCase context "while authenticated with a questionnaire but no bus list" do setup do - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @questionnaire.user @questionnaire.update_attribute(:acc_status, "accepted") end @@ -55,7 +55,7 @@ class BusListsControllerTest < ActionController::TestCase context "while authenticated with a questionnaire with a bus list" do setup do - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @questionnaire.user @questionnaire.update_attribute(:acc_status, "accepted") @bus_list = create(:bus_list) diff --git a/test/controllers/manage/bus_lists_controller_test.rb b/test/controllers/manage/bus_lists_controller_test.rb index c03b743b8..1d12d9363 100644 --- a/test/controllers/manage/bus_lists_controller_test.rb +++ b/test/controllers/manage/bus_lists_controller_test.rb @@ -137,10 +137,76 @@ class Manage::BusListsControllerTest < ActionController::TestCase end end - context "while authenticated as a limited access admin" do + context "while authenticated as a volunteer" do setup do - @user = create(:limited_access_admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:volunteer) + @request.env["devise.mapping"] = Devise.mappings[:user] + sign_in @user + end + + should "allow access to manage_bus_lists#index" do + get :index + assert_response :success + end + + should "allow access to manage_bus_lists#show" do + get :show, params: { id: @bus_list } + assert_response :success + end + + should "not allow access to manage_bus_lists#new" do + get :new + assert_response :redirect + assert_redirected_to manage_bus_lists_path + end + + should "not allow access to manage_bus_lists#edit" do + get :edit, params: { id: @bus_list } + assert_response :redirect + assert_redirected_to manage_bus_lists_path + end + + should "not allow access to manage_bus_lists#create" do + post :create, params: { bus_list: { email: "test@example.com" } } + assert_response :redirect + assert_redirected_to manage_bus_lists_path + end + + should "not allow access to manage_bus_lists#update" do + patch :update, params: { id: @bus_list, bus_list: { email: "test@example.com" } } + assert_response :redirect + assert_redirected_to manage_bus_lists_path + end + + should "not allow access to manage_bus_lists#toggle_bus_captain" do + questionnaire = create(:questionnaire) + assert_difference "enqueued_jobs.size", 0 do + patch :toggle_bus_captain, params: { id: @bus_list, questionnaire_id: questionnaire.id, bus_captain: "1" } + end + assert_equal false, questionnaire.reload.is_bus_captain + assert_response :redirect + assert_redirected_to manage_bus_lists_path + end + + should "not allow access to manage_bus_lists#send_update_email" do + assert_difference "enqueued_jobs.size", 0 do + patch :send_update_email, params: { id: @bus_list } + end + assert_response :redirect + assert_redirected_to manage_bus_lists_path + end + + should "not allow access to manage_bus_lists#destroy" do + patch :destroy, params: { id: @bus_list } + assert_response :redirect + assert_redirected_to manage_bus_lists_path + end + end + + context "while authenticated as an organizer" do + setup do + @user = create(:organizer) + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end @@ -203,9 +269,9 @@ class Manage::BusListsControllerTest < ActionController::TestCase end end - context "while authenticated as an admin" do + context "while authenticated as a director" do setup do - @user = create(:admin) + @user = create(:director) @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end diff --git a/test/controllers/manage/checkins_controller_test.rb b/test/controllers/manage/checkins_controller_test.rb index 58d2f6df3..6b92b4276 100644 --- a/test/controllers/manage/checkins_controller_test.rb +++ b/test/controllers/manage/checkins_controller_test.rb @@ -15,7 +15,7 @@ class Manage::CheckinsControllerTest < ActionController::TestCase setup do if do_sign_in @user = create(:user) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @user end end @@ -43,7 +43,7 @@ class Manage::CheckinsControllerTest < ActionController::TestCase context "while authenticated as a user" do setup do @user = create(:user) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @user end @@ -52,42 +52,17 @@ class Manage::CheckinsControllerTest < ActionController::TestCase end end - limited_conditions = { - 'event tracking user' => :event_tracking, - } - - limited_conditions.each do |condition_name, user_role| - context "while authenticated as a #{condition_name}" do - setup do - @user = create(:user, role: user_role) - @request.env["devise.mapping"] = Devise.mappings[:admin] - sign_in @user - end - - should "not get index" do - test_index_failure - end - - should "not show checkin" do - test_show_failure - end - - should "not render checking datatable" do - test_datatable_failure - end - end - end - success_conditions = { - 'limited access admin' => :admin_limited_access, - 'admin' => :admin + 'volunteer' => :volunteer, + 'organizer' => :organizer, + 'director' => :director } success_conditions.each do |condition_name, user_role| context "while authenticated as a #{condition_name}" do setup do @user = create(:user, role: user_role) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @user end diff --git a/test/controllers/manage/configs_controller_test.rb b/test/controllers/manage/configs_controller_test.rb index 038423fa4..826bb3043 100644 --- a/test/controllers/manage/configs_controller_test.rb +++ b/test/controllers/manage/configs_controller_test.rb @@ -31,7 +31,7 @@ class Manage::ConfigsControllerTest < ActionController::TestCase context "while authenticated as a user" do setup do @user = create(:user) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @user end @@ -61,10 +61,10 @@ class Manage::ConfigsControllerTest < ActionController::TestCase end end - context "while authenticated as a limited access admin" do + context "while authenticated as a volunteer" do setup do - @user = create(:limited_access_admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:volunteer) + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end @@ -91,10 +91,40 @@ class Manage::ConfigsControllerTest < ActionController::TestCase end end - context "while authenticated as an admin" do + context "while authenticated as an organizer" do setup do - @user = create(:admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:organizer) + @request.env["devise.mapping"] = Devise.mappings[:user] + sign_in @user + end + + should "not allow access to manage_configs#index" do + get :index + assert_response :redirect + end + + should "not allow access to manage_configs#edit" do + get :edit, params: { id: "registration_is_open" } + assert_response :redirect + end + + should "not update config" do + HackathonConfig["registration_is_open"] = false + patch :update, params: { id: "registration_is_open", hackathon_config: { registration_is_open: "true" } } + assert_equal false, HackathonConfig["registration_is_open"] + end + + should "not update css config" do + HackathonConfig["custom_css"] = "" + patch :update_only_css_variables, params: { id: "custom_css", hackathon_config: { custom_css: ":root {\n --foo: #fff;\n}" } } + assert_equal "", HackathonConfig["custom_css"] + end + end + + context "while authenticated as a director" do + setup do + @user = create(:director) + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end diff --git a/test/controllers/manage/dashboard_controller_test.rb b/test/controllers/manage/dashboard_controller_test.rb index f1dad23c1..f473968e6 100644 --- a/test/controllers/manage/dashboard_controller_test.rb +++ b/test/controllers/manage/dashboard_controller_test.rb @@ -12,21 +12,156 @@ class Manage::DashboardControllerTest < ActionController::TestCase context "while authenticated as a user" do setup do @user = create(:user) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @user end - should "allow access to manage_dashboard#index" do + should "not allow access to manage_dashboard#index" do get :index assert_response :redirect assert_redirected_to root_path end + + should "not allow access to all data endpoints" do + school1 = FactoryBot.create(:school) + school2 = FactoryBot.create(:school) + FactoryBot.create_list(:questionnaire, 20, school_id: school1.id, acc_status: "pending") + FactoryBot.create_list(:questionnaire, 20, school_id: school1.id, acc_status: "accepted") + FactoryBot.create_list(:questionnaire, 10, school_id: school2.id, acc_status: "accepted") + Questionnaire::POSSIBLE_ACC_STATUS.each do |status, _name| + FactoryBot.create_list(:questionnaire, 1, school_id: school2.id, acc_status: status) + end + + stub_request(:get, "https://geocoding.geo.census.gov/geocoder/locations/address?street=123+Fake+Street&city=Rochester&state=NY&benchmark=Public_AR_Current&format=json") + .to_return(status: 200, body: '{ "result":{ "addressMatches":[{ "coordinates":{ "x": 100, "y": 100 } }] } }', headers: { 'Content-Type' => 'application/json; charset=UTF-8' }) + stub_request(:get, "https://geo.fcc.gov/api/census/area?format=json&lat=100&lon=100") + .to_return(status: 200, body: '{ "results":[{ "country_fips":1234 }] }', headers: { 'Content-Type' => 'application/json; charset=UTF-8' }) + + paths = [ + :todays_activity_data, + :todays_stats_data, + :checkin_activity_data, + :confirmation_activity_data, + :application_activity_data, + :schools_confirmed_data, + :user_distribution_data, + :application_distribution_data, + :schools_applied_data + ] + + paths.each do |path| + get path + assert_redirected_to root_path + end + + get :map_data, format: "tsv" + assert_redirected_to root_path + end + end + + context "while authenticated as a volunteer" do + setup do + @user = create(:volunteer) + @request.env["devise.mapping"] = Devise.mappings[:director] + sign_in @user + end + + should "not allow access to manage_dashboard#index" do + get :index + assert_response :redirect + assert_redirected_to manage_checkins_path + end + + should "not allow access to all data endpoints" do + school1 = FactoryBot.create(:school) + school2 = FactoryBot.create(:school) + FactoryBot.create_list(:questionnaire, 20, school_id: school1.id, acc_status: "pending") + FactoryBot.create_list(:questionnaire, 20, school_id: school1.id, acc_status: "accepted") + FactoryBot.create_list(:questionnaire, 10, school_id: school2.id, acc_status: "accepted") + Questionnaire::POSSIBLE_ACC_STATUS.each do |status, _name| + FactoryBot.create_list(:questionnaire, 1, school_id: school2.id, acc_status: status) + end + + stub_request(:get, "https://geocoding.geo.census.gov/geocoder/locations/address?street=123+Fake+Street&city=Rochester&state=NY&benchmark=Public_AR_Current&format=json") + .to_return(status: 200, body: '{ "result":{ "addressMatches":[{ "coordinates":{ "x": 100, "y": 100 } }] } }', headers: { 'Content-Type' => 'application/json; charset=UTF-8' }) + stub_request(:get, "https://geo.fcc.gov/api/census/area?format=json&lat=100&lon=100") + .to_return(status: 200, body: '{ "results":[{ "country_fips":1234 }] }', headers: { 'Content-Type' => 'application/json; charset=UTF-8' }) + + paths = [ + :todays_activity_data, + :todays_stats_data, + :checkin_activity_data, + :confirmation_activity_data, + :application_activity_data, + :schools_confirmed_data, + :user_distribution_data, + :application_distribution_data, + :schools_applied_data + ] + + paths.each do |path| + get path + assert_redirected_to manage_checkins_path + end + + get :map_data, format: "tsv" + assert_redirected_to manage_checkins_path + end + end + + context "while authenticated as an organizer" do + setup do + @user = create(:organizer) + @request.env["devise.mapping"] = Devise.mappings[:director] + sign_in @user + end + + should "allow access to manage_dashboard#index" do + get :index + assert_response :success + end + + should "allow access to all data endpoints" do + school1 = FactoryBot.create(:school) + school2 = FactoryBot.create(:school) + FactoryBot.create_list(:questionnaire, 20, school_id: school1.id, acc_status: "pending") + FactoryBot.create_list(:questionnaire, 20, school_id: school1.id, acc_status: "accepted") + FactoryBot.create_list(:questionnaire, 10, school_id: school2.id, acc_status: "accepted") + Questionnaire::POSSIBLE_ACC_STATUS.each do |status, _name| + FactoryBot.create_list(:questionnaire, 1, school_id: school2.id, acc_status: status) + end + + stub_request(:get, "https://geocoding.geo.census.gov/geocoder/locations/address?street=123+Fake+Street&city=Rochester&state=NY&benchmark=Public_AR_Current&format=json") + .to_return(status: 200, body: '{ "result":{ "addressMatches":[{ "coordinates":{ "x": 100, "y": 100 } }] } }', headers: { 'Content-Type' => 'application/json; charset=UTF-8' }) + stub_request(:get, "https://geo.fcc.gov/api/census/area?format=json&lat=100&lon=100") + .to_return(status: 200, body: '{ "results":[{ "country_fips":1234 }] }', headers: { 'Content-Type' => 'application/json; charset=UTF-8' }) + + paths = [ + :todays_activity_data, + :todays_stats_data, + :checkin_activity_data, + :confirmation_activity_data, + :application_activity_data, + :schools_confirmed_data, + :user_distribution_data, + :application_distribution_data, + :schools_applied_data + ] + + paths.each do |path| + get path + assert_response :success + end + + get :map_data, format: "tsv" + assert_response :success + end end - context "while authenticated as an admin" do + context "while authenticated as a director" do setup do - @user = create(:admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:director) + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @user end diff --git a/test/controllers/manage/messages_controller_test.rb b/test/controllers/manage/messages_controller_test.rb index 291ee290a..c63245752 100644 --- a/test/controllers/manage/messages_controller_test.rb +++ b/test/controllers/manage/messages_controller_test.rb @@ -200,10 +200,110 @@ class Manage::MessagesControllerTest < ActionController::TestCase end end - context "while authenticated as a limited access admin" do + context "while authenticated as a volunteer" do setup do - @user = create(:limited_access_admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:volunteer) + @request.env["devise.mapping"] = Devise.mappings[:user] + sign_in @user + end + + should "not allow access to manage_messages#index" do + get :index + assert_response :redirect + assert_redirected_to manage_checkins_path + end + + should "not allow access to manage_messages datatables api" do + post :datatable, format: :json, params: { "columns[0][data]" => "" } + assert_response :redirect + assert_redirected_to manage_checkins_path + end + + should "not allow access to manage_messages#new" do + get :new + assert_response :redirect + assert_redirected_to manage_messages_path + end + + should "not allow access to manage_messages#show" do + get :show, params: { id: @message } + assert_response :redirect + assert_redirected_to manage_checkins_path + end + + should "not allow access to manage_messages#edit" do + get :edit, params: { id: @message } + assert_response :redirect + assert_redirected_to manage_messages_path + end + + should "not allow access to manage_messages#create" do + post :create, params: { message: { email: "test@example.com" } } + assert_response :redirect + assert_redirected_to manage_messages_path + end + + should "not allow access to manage_messages#update" do + patch :update, params: { id: @message, message: { email: "test@example.com" } } + assert_response :redirect + assert_redirected_to manage_messages_path + end + + should "not allow access to manage_messages#destroy" do + patch :destroy, params: { id: @message } + assert_response :redirect + assert_redirected_to manage_messages_path + end + + should "not deliver message" do + assert_difference("enqueued_jobs.size", 0) do + patch :deliver, params: { id: @message } + end + assert_response :redirect + assert_redirected_to manage_messages_path + end + + should "not allow access to manage_messages#preview" do + get :preview, params: { id: @message } + assert_response :redirect + assert_redirected_to manage_checkins_path + end + + should "not allow access to manage_messages#live_preview" do + get :live_preview, params: { body: "foo bar" } + assert_response :redirect + assert_redirected_to manage_messages_path + end + + should "not allow access to manage_messages#duplicate" do + assert_difference("Message.count", 0) do + patch :duplicate, params: { id: @message } + end + assert_response :redirect + assert_redirected_to manage_messages_path + end + + should "not allow access to manage_messages#template" do + test_template_failure + end + + should "not allow access to manage_messages#template_preview" do + test_template_preview_failure + end + + should "not allow access to manage_messages#template_update" do + test_template_update_failure + end + + should "not allow access to manage_messages#template_replace_with_default" do + test_template_replace_with_default_failure + end + end + + context "while authenticated as an organizer" do + setup do + @user = create(:organizer) + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end @@ -296,9 +396,9 @@ class Manage::MessagesControllerTest < ActionController::TestCase end end - context "while authenticated as an admin" do + context "while authenticated as a director" do setup do - @user = create(:admin) + @user = create(:director) @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end diff --git a/test/controllers/manage/questionnaires_controller_test.rb b/test/controllers/manage/questionnaires_controller_test.rb index 969937faa..ab7f84023 100644 --- a/test/controllers/manage/questionnaires_controller_test.rb +++ b/test/controllers/manage/questionnaires_controller_test.rb @@ -50,12 +50,6 @@ class Manage::QuestionnairesControllerTest < ActionController::TestCase assert_redirected_to new_user_session_path end - should "not allow convert questionnaire's user to an admin" do - patch :convert_to_admin, params: { id: @questionnaire } - assert_response :redirect - assert_redirected_to new_user_session_path - end - should "not allow access to manage_questionnaires#destroy" do patch :destroy, params: { id: @questionnaire } assert_response :redirect @@ -77,7 +71,7 @@ class Manage::QuestionnairesControllerTest < ActionController::TestCase context "while authenticated as a user" do setup do - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @questionnaire.user end @@ -123,12 +117,6 @@ class Manage::QuestionnairesControllerTest < ActionController::TestCase assert_redirected_to root_path end - should "not allow convert questionnaire's user to an admin" do - patch :convert_to_admin, params: { id: @questionnaire } - assert_response :redirect - assert_redirected_to root_path - end - should "not allow access to manage_questionnaires#destroy" do patch :destroy, params: { id: @questionnaire } assert_response :redirect @@ -148,10 +136,10 @@ class Manage::QuestionnairesControllerTest < ActionController::TestCase end end - context "while authenticated as a limited access admin" do + context "while authenticated as a volunteer" do setup do - @user = create(:limited_access_admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:volunteer) + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end @@ -194,8 +182,66 @@ class Manage::QuestionnairesControllerTest < ActionController::TestCase assert_redirected_to manage_questionnaires_path end - should "not allow convert questionnaire's user to an admin" do - patch :convert_to_admin, params: { id: @questionnaire } + should "not allow access to manage_questionnaires#destroy" do + patch :destroy, params: { id: @questionnaire } + assert_response :redirect + assert_redirected_to manage_questionnaires_path + end + + should "not access to manage_questionnaires#update_acc_status" do + patch :update_acc_status, params: { id: @questionnaire, questionnaire: { acc_status: "accepted" } } + assert_response :redirect + assert_redirected_to manage_questionnaires_path + end + + should "allow access to manage_questionnaires#bulk_apply" do + patch :bulk_apply, params: { bulk_action: "waitlist", bulk_ids: [@questionnaire.id] } + assert_response :success + end + end + + context "while authenticated as an organizer" do + setup do + @user = create(:organizer) + @request.env["devise.mapping"] = Devise.mappings[:user] + sign_in @user + end + + should "allow access to manage_questionnaires#index" do + get :index + assert_response :success + end + + should "allow access to manage_questionnaires datatables api" do + post :datatable, format: :json, params: { "columns[0][data]" => "" } + assert_response :success + end + + should "allow access to manage_questionnaires#show" do + get :show, params: { id: @questionnaire } + assert_response :success + end + + should "not allow access to manage_questionnaires#new" do + get :new, params: { id: @questionnaire } + assert_response :redirect + assert_redirected_to manage_questionnaires_path + end + + should "not allow access to manage_questionnaires#edit" do + get :edit, params: { id: @questionnaire } + assert_response :redirect + assert_redirected_to manage_questionnaires_path + end + + should "not allow access to manage_questionnaires#create" do + post :create, params: { questionnaire: { major: "Best Major" } } + assert_response :redirect + assert_redirected_to manage_questionnaires_path + end + + should "not allow access to manage_questionnaires#update" do + patch :update, params: { id: @questionnaire, questionnaire: { major: "Best Major" } } assert_response :redirect assert_redirected_to manage_questionnaires_path end @@ -218,10 +264,10 @@ class Manage::QuestionnairesControllerTest < ActionController::TestCase end end - context "while authenticated as an admin" do + context "while authenticated as a director" do setup do - @user = create(:admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:director) + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @user end @@ -299,18 +345,21 @@ class Manage::QuestionnairesControllerTest < ActionController::TestCase assert_redirected_to manage_questionnaire_path(assigns(:questionnaire)) end - should "convert questionnaire's user to an admin" do - patch :convert_to_admin, params: { id: @questionnaire } - assert assigns(:questionnaire).user.admin? - assert_nil assigns(:questionnaire).user.reload.questionnaire - assert_redirected_to edit_manage_user_path(assigns(:questionnaire).user) - end + context "destroy questionnaire" do + should "if bus captain, notify directors that bus captain has been removed" do + @user = create(:director) + @questionnaire.update_attribute(:is_bus_captain, true) + assert_difference('enqueued_jobs.size', User.where(role: :director).size) do + delete :destroy, params: { id: @questionnaire } + end + end - should "destroy questionnaire" do - assert_difference("Questionnaire.count", -1) do - delete :destroy, params: { id: @questionnaire } + should "user destroy questionnaire" do + assert_difference('Questionnaire.count', -1) do + delete :destroy, params: { id: @questionnaire } + end + assert_redirected_to manage_questionnaires_path end - assert_redirected_to manage_questionnaires_path end should "check in the questionnaire" do @@ -341,7 +390,7 @@ class Manage::QuestionnairesControllerTest < ActionController::TestCase assert_equal @user.id, @questionnaire.checked_in_by_id assert_equal true, @questionnaire.agreement_accepted assert_equal true, @questionnaire.can_share_info - assert_equal "(123) 333-3333", @questionnaire.phone + assert_equal "1233333333", @questionnaire.phone assert_equal "new_email@example.com", @questionnaire.email assert_match /Checked in/, flash[:notice] assert_response :redirect diff --git a/test/controllers/manage/schools_controller_test.rb b/test/controllers/manage/schools_controller_test.rb index 6402b80ce..a19f9406d 100644 --- a/test/controllers/manage/schools_controller_test.rb +++ b/test/controllers/manage/schools_controller_test.rb @@ -134,10 +134,75 @@ class Manage::SchoolsControllerTest < ActionController::TestCase end end - context "while authenticated as a limited access admin" do + context "while authenticated as a volunteer" do setup do - @user = create(:limited_access_admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:volunteer) + @request.env["devise.mapping"] = Devise.mappings[:user] + sign_in @user + end + + should "allow access to manage_schools#index" do + get :index + assert_response :success + end + + should "allow access to manage_schools datatables api" do + post :datatable, format: :json, params: { "columns[0][data]" => "" } + assert_response :success + end + + should "allow access to manage_schools#show" do + get :show, params: { id: @school } + assert_response :success + end + + should "not allow access to manage_schools#new" do + get :new + assert_response :redirect + assert_redirected_to manage_schools_path + end + + should "not allow access to manage_schools#edit" do + get :edit, params: { id: @school } + assert_response :redirect + assert_redirected_to manage_schools_path + end + + should "not allow access to manage_schools#create" do + post :create, params: { school: { name: "My Test School" } } + assert_response :redirect + assert_redirected_to manage_schools_path + end + + should "not allow access to manage_schools#update" do + patch :update, params: { id: @school, school: { name: "My Test School" } } + assert_response :redirect + assert_redirected_to manage_schools_path + end + + should "not allow access to manage_schools#destroy" do + patch :destroy, params: { id: @school } + assert_response :redirect + assert_redirected_to manage_schools_path + end + + should "not allow access to manage_schools#merge" do + patch :merge, params: { id: @school } + assert_response :redirect + assert_redirected_to manage_schools_path + end + + should "not allow access to manage_schools#perform_merge" do + patch :perform_merge, params: { id: @school, school: { id: "My Test School" } } + assert_response :redirect + assert_redirected_to manage_schools_path + end + end + + context "while authenticated as an organizer" do + setup do + @user = create(:organizer) + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end @@ -199,9 +264,9 @@ class Manage::SchoolsControllerTest < ActionController::TestCase end end - context "while authenticated as an admin" do + context "while authenticated as a director" do setup do - @user = create(:admin) + @user = create(:director) @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end diff --git a/test/controllers/manage/stats_controller_test.rb b/test/controllers/manage/stats_controller_test.rb index 9e4e66f65..79aa2c9cb 100644 --- a/test/controllers/manage/stats_controller_test.rb +++ b/test/controllers/manage/stats_controller_test.rb @@ -20,7 +20,7 @@ class Manage::StatsControllerTest < ActionController::TestCase context "while authenticated as a user" do setup do @user = create(:user) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @user end @@ -39,14 +39,61 @@ class Manage::StatsControllerTest < ActionController::TestCase end end - context "while authenticated as an admin" do + context "while authenticated as a volunteer" do setup do - @user = create(:admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:volunteer) + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end - should "allow access to manage_dashboard#index" do + should "not allow access to stats#index" do + get :index + assert_response :redirect + assert_redirected_to manage_checkins_path + end + + should "not allow access to data endpoints" do + paths.each do |path| + patch path + assert_response :redirect + assert_redirected_to manage_checkins_path + end + end + end + + context "while authenticated as an organizer" do + setup do + @user = create(:organizer) + @request.env["devise.mapping"] = Devise.mappings[:user] + sign_in @user + end + + should "allow access to stats#index" do + get :index + assert_response :success + end + + should "allow access to all data endpoints" do + school = create(:school) + Questionnaire::POSSIBLE_ACC_STATUS.each do |status, _name| + create_list(:questionnaire, 5, school_id: school.id, acc_status: status, dietary_restrictions: "Vegetarian", special_needs: "Something") + end + + paths.each do |path| + patch path + assert_response :success + end + end + end + + context "while authenticated as a director" do + setup do + @user = create(:director) + @request.env["devise.mapping"] = Devise.mappings[:user] + sign_in @user + end + + should "allow access to stats#index" do get :index assert_response :success end diff --git a/test/controllers/manage/trackable_events_controller_test.rb b/test/controllers/manage/trackable_events_controller_test.rb index faf5b4478..67cd2d398 100644 --- a/test/controllers/manage/trackable_events_controller_test.rb +++ b/test/controllers/manage/trackable_events_controller_test.rb @@ -15,7 +15,7 @@ class Manage::TrackableEventsControllerTest < ActionController::TestCase setup do if do_sign_in @user = create(:user) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @user @trackable_event.update_attribute(:user, @user) end @@ -52,15 +52,15 @@ class Manage::TrackableEventsControllerTest < ActionController::TestCase end limited_conditions = { - 'event tracking user' => :event_tracking, - 'limited access admin' => :admin_limited_access + 'volunteer' => :volunteer, + 'organizer' => :organizer } limited_conditions.each do |condition_name, user_role| context "while authenticated as a #{condition_name}" do setup do @user = create(:user, role: user_role) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user @trackable_event.update_attribute(:user, @user) end @@ -105,10 +105,10 @@ class Manage::TrackableEventsControllerTest < ActionController::TestCase end end - context "while authenticated as an admin" do + context "while authenticated as a director" do setup do - @user = create(:admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:director) + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end diff --git a/test/controllers/manage/trackable_tags_controller_test.rb b/test/controllers/manage/trackable_tags_controller_test.rb index a392cf371..56c273cfa 100644 --- a/test/controllers/manage/trackable_tags_controller_test.rb +++ b/test/controllers/manage/trackable_tags_controller_test.rb @@ -15,7 +15,7 @@ class Manage::TrackableTagsControllerTest < ActionController::TestCase setup do if do_sign_in @user = create(:user) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @user end end @@ -51,15 +51,15 @@ class Manage::TrackableTagsControllerTest < ActionController::TestCase end limited_conditions = { - 'event tracking user' => :event_tracking, - 'limited access admin' => :admin_limited_access + 'volunteer' => :volunteer, + 'organizer' => :organizer } limited_conditions.each do |condition_name, user_role| context "while authenticated as a #{condition_name}" do setup do @user = create(:user, role: user_role) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end @@ -93,10 +93,10 @@ class Manage::TrackableTagsControllerTest < ActionController::TestCase end end - context "while authenticated as an admin" do + context "while authenticated as a director" do setup do - @user = create(:admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:director) + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end diff --git a/test/controllers/manage/users_controller_test.rb b/test/controllers/manage/users_controller_test.rb index 1a2b5dc42..2ea0cd3c9 100644 --- a/test/controllers/manage/users_controller_test.rb +++ b/test/controllers/manage/users_controller_test.rb @@ -17,8 +17,8 @@ class Manage::UsersControllerTest < ActionController::TestCase assert_response 401 end - should "not allow access to manage_users admin datatables api" do - post :admin_datatable, format: :json, params: { "columns[0][data]" => "" } + should "not allow access to manage_users staff datatables api" do + post :staff_datatable, format: :json, params: { "columns[0][data]" => "" } assert_response 401 end @@ -65,8 +65,8 @@ class Manage::UsersControllerTest < ActionController::TestCase assert_redirected_to root_path end - should "not allow access to manage_users admin datatables api" do - post :admin_datatable, format: :json, params: { "columns[0][data]" => "" } + should "not allow access to manage_users staff datatables api" do + post :staff_datatable, format: :json, params: { "columns[0][data]" => "" } assert_response :redirect assert_redirected_to root_path end @@ -96,31 +96,77 @@ class Manage::UsersControllerTest < ActionController::TestCase end end - context "while authenticated as a limited access admin" do + context "while authenticated as a volunteer" do setup do - @user = create(:limited_access_admin) - @request.env["devise.mapping"] = Devise.mappings[:admin] + @user = create(:volunteer) + @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end should "not allow access to manage_users#index" do get :index - assert_redirected_to root_path + assert_redirected_to manage_checkins_path end should "not allow access to manage_users users datatables api" do post :user_datatable, format: :json, params: { "columns[0][data]" => "" } - assert_redirected_to root_path + assert_redirected_to manage_checkins_path end - should "not allow access to manage_users admins datatables api" do - post :admin_datatable, format: :json, params: { "columns[0][data]" => "" } - assert_redirected_to root_path + should "not allow access to manage_users staff datatables api" do + post :staff_datatable, format: :json, params: { "columns[0][data]" => "" } + assert_redirected_to manage_checkins_path end should "allow access to manage_users#show" do get :show, params: { id: @user } - assert_redirected_to root_path + assert_redirected_to manage_checkins_path + end + + should "not allow access to manage_users#edit" do + get :edit, params: { id: @user } + assert_response :redirect + assert_redirected_to manage_users_path + end + + should "not allow access to manage_users#update" do + patch :update, params: { id: @user, user: { email: "test@example.com" } } + assert_response :redirect + assert_redirected_to manage_users_path + end + + should "not allow access to manage_users#destroy" do + patch :destroy, params: { id: @user } + assert_response :redirect + assert_redirected_to manage_users_path + end + end + + context "while authenticated as an organizer" do + setup do + @user = create(:organizer) + @request.env["devise.mapping"] = Devise.mappings[:user] + sign_in @user + end + + should "not allow access to manage_users#index" do + get :index + assert_redirected_to manage_root_path + end + + should "not allow access to manage_users users datatables api" do + post :user_datatable, format: :json, params: { "columns[0][data]" => "" } + assert_redirected_to manage_root_path + end + + should "not allow access to manage_users staff datatables api" do + post :staff_datatable, format: :json, params: { "columns[0][data]" => "" } + assert_redirected_to manage_root_path + end + + should "allow access to manage_users#show" do + get :show, params: { id: @user } + assert_redirected_to manage_root_path end should "not allow access to manage_users#edit" do @@ -142,9 +188,9 @@ class Manage::UsersControllerTest < ActionController::TestCase end end - context "while authenticated as an admin" do + context "while authenticated as a director" do setup do - @user = create(:admin) + @user = create(:director) @request.env["devise.mapping"] = Devise.mappings[:user] sign_in @user end diff --git a/test/controllers/questionnaires_controller_test.rb b/test/controllers/questionnaires_controller_test.rb index faf0279a0..a3f14b404 100644 --- a/test/controllers/questionnaires_controller_test.rb +++ b/test/controllers/questionnaires_controller_test.rb @@ -35,7 +35,7 @@ class QuestionnairesControllerTest < ActionController::TestCase context "while authenticated without a completed questionnaire" do setup do - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] @user = create(:user) sign_in @user end @@ -76,6 +76,15 @@ class QuestionnairesControllerTest < ActionController::TestCase end end + context "with block questionnaires set" do + should "not allow creation" do + HackathonConfig['accepting_questionnaires'] = false + assert_difference('Questionnaire.count', 0) do + post :create, params: { questionnaire: { experience: @questionnaire.experience, interest: @questionnaire.interest, phone: @questionnaire.phone, level_of_study: @questionnaire.level_of_study, date_of_birth: @questionnaire.date_of_birth, shirt_size: @questionnaire.shirt_size, school_id: @school.id, agreement_accepted: "1", code_of_conduct_accepted: "1", data_sharing_accepted: "1", major: @questionnaire.major, gender: @questionnaire.gender, why_attend: @questionnaire.why_attend, graduation_year: @questionnaire.graduation_year, race_ethnicity: @questionnaire.race_ethnicity } } + end + end + end + context "#school_name" do context "on create" do should "save existing school name" do @@ -130,7 +139,7 @@ class QuestionnairesControllerTest < ActionController::TestCase context "while authenticated with a completed questionnaire" do setup do - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @questionnaire.user end @@ -156,12 +165,22 @@ class QuestionnairesControllerTest < ActionController::TestCase assert_redirected_to questionnaires_path end - should "destroy questionnaire" do - assert_difference('Questionnaire.count', -1) do - delete :destroy + context "destroy questionnaire" do + should "if bus captain, notify directors that bus captain has been removed" do + @director = create(:director) + @questionnaire.update_attribute(:is_bus_captain, true) + assert_difference('enqueued_jobs.size', User.where(role: :director).size) do + delete :destroy + end end - assert_redirected_to questionnaires_path + should "user destroy questionnaire" do + assert_difference('Questionnaire.count', -1) do + delete :destroy + end + + assert_redirected_to questionnaires_path + end end context "with invalid questionnaire params" do diff --git a/test/controllers/rsvps_controller_test.rb b/test/controllers/rsvps_controller_test.rb index 77a15dbe7..7a61408a5 100644 --- a/test/controllers/rsvps_controller_test.rb +++ b/test/controllers/rsvps_controller_test.rb @@ -32,7 +32,7 @@ class RsvpsControllerTest < ActionController::TestCase context "while authenticated without a questionnaire" do setup do - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] @user = create(:user, email: "newabc@example.com") sign_in @user end @@ -60,7 +60,7 @@ class RsvpsControllerTest < ActionController::TestCase context "while authenticated with a non-accepted questionnaire" do setup do - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @questionnaire.user @questionnaire.acc_status = "denied" end @@ -90,7 +90,7 @@ class RsvpsControllerTest < ActionController::TestCase setup do clear_enqueued_jobs - @request.env["devise.mapping"] = Devise.mappings[:admin] + @request.env["devise.mapping"] = Devise.mappings[:director] sign_in @questionnaire.user @questionnaire.update_attribute(:acc_status, "accepted") end @@ -243,5 +243,38 @@ class RsvpsControllerTest < ActionController::TestCase assert_match /select a RSVP status/, flash[:alert] assert_redirected_to rsvp_path end + + should "if bus captain leaves a bus, notify directors that bus captain has been removed" do + @director = create(:director) + @questionnaire.update_attribute(:is_bus_captain, true) + @questionnaire.update_attribute(:acc_status, "rsvp_confirmed") + + bus_list1 = create(:bus_list, capacity: 1) + bus_list2 = create(:bus_list, capacity: 2) + patch :update, params: { + questionnaire: { + acc_status: "rsvp_confirmed", + phone: "(123) 456-7890", + bus_list_id: bus_list1.id + } + } + + assert_difference('enqueued_jobs.size', User.where(role: :director).size) do + patch :update, params: { + questionnaire: { + acc_status: "rsvp_confirmed", + phone: "(123) 456-7890", + bus_list_id: bus_list2.id + } + } + end + end + + should "not queue bus_captain_left email if questionnaire is not a bus captain" do + @questionnaire.update_attribute(:is_bus_captain, false) + assert_difference('enqueued_jobs.size', 0) do + patch :update, params: { questionnaire: { acc_status: "rsvp_confirmed" } } + end + end end end diff --git a/test/controllers/admin_mailer_test.rb b/test/controllers/staff_mailer_test.rb similarity index 68% rename from test/controllers/admin_mailer_test.rb rename to test/controllers/staff_mailer_test.rb index 565b63158..591b4089d 100644 --- a/test/controllers/admin_mailer_test.rb +++ b/test/controllers/staff_mailer_test.rb @@ -1,6 +1,6 @@ require "test_helper" -class AdminMailerTest < ActionMailer::TestCase +class StaffMailerTest < ActionMailer::TestCase context "weekly_report" do setup do @user = create(:user, email: "test@example.com", receive_weekly_report: true) @@ -10,7 +10,7 @@ class AdminMailerTest < ActionMailer::TestCase end should "deliver weekly email report" do - email = AdminMailer.weekly_report(@user.id).deliver_now + email = StaffMailer.weekly_report(@user.id).deliver_now assert_equal ["test@example.com"], email.to assert_equal "Your Weekly Report", email.subject @@ -19,25 +19,25 @@ class AdminMailerTest < ActionMailer::TestCase should "not send when more than 7 days after event started" do HackathonConfig["event_start_date"] = 10.days.ago.to_s - email = AdminMailer.weekly_report(@user.id).deliver_now + email = StaffMailer.weekly_report(@user.id).deliver_now assert_nil email end - should "not send if admin is inactive" do + should "not send if staff member is inactive" do @user.update_attribute(:is_active, false) - email = AdminMailer.weekly_report(@user.id).deliver_now + email = StaffMailer.weekly_report(@user.id).deliver_now assert_nil email end - should "not send if admin isn't receiving weekly reports" do + should "not send if staff member isn't receiving weekly reports" do @user.update_attribute(:receive_weekly_report, false) - email = AdminMailer.weekly_report(@user.id).deliver_now + email = StaffMailer.weekly_report(@user.id).deliver_now assert_nil email end should "not send if there hasn't been new activity" do @questionnaire.update_attribute(:created_at, Date.today) - email = AdminMailer.weekly_report(@user.id).deliver_now + email = StaffMailer.weekly_report(@user.id).deliver_now assert_nil email end end diff --git a/test/controllers/user_mailer_test.rb b/test/controllers/user_mailer_test.rb index 5b9d237e4..8bdaeea91 100644 --- a/test/controllers/user_mailer_test.rb +++ b/test/controllers/user_mailer_test.rb @@ -29,6 +29,19 @@ class UserMailerTest < ActionMailer::TestCase end end + context "upon scheduled rsvp reminder email" do + setup do + @user = create(:user, email: "test@example.com") + @message = create(:message, subject: "Are you coming to HackFoo?", type: "automated", trigger: "questionnaire.rsvp_reminder_email") + + should "queue reminder bulk message" do + assert_difference "enqueued_jobs.size", 1 do + UserMailer.rsvp_reminder_email(@user.id).deliver_later + end + end + end + end + context "with customized HackathonConfig" do setup do @user = create(:user, email: "test@example.com") diff --git a/test/factories/users.rb b/test/factories/users.rb index f4b7bedf1..4b5f80572 100644 --- a/test/factories/users.rb +++ b/test/factories/users.rb @@ -10,18 +10,25 @@ is_active { true } receive_weekly_report { false } - factory :admin do + factory :director do sequence :email do |n| - "admin#{n}@example.com" + "director#{n}@example.com" end - role { :admin } + role { :director } end - factory :limited_access_admin do + factory :organizer do sequence :email do |n| - "limited_admin#{n}@example.com" + "organizer#{n}@example.com" end - role { :admin_limited_access } + role { :organizer } + end + + factory :volunteer do + sequence :email do |n| + "volunteer#{n}@example.com" + end + role { :volunteer } end end end diff --git a/test/integration/user_flows_test.rb b/test/integration/user_flows_test.rb index f6131b5cf..f8ca5767d 100644 --- a/test/integration/user_flows_test.rb +++ b/test/integration/user_flows_test.rb @@ -10,8 +10,8 @@ class UserFlowsTest < ActionDispatch::IntegrationTest assert assigns(:questionnaire) end - should "be able to login and browse site as an admin" do - login(FactoryBot.create(:admin)) + should "be able to login and browse site as a director" do + login(FactoryBot.create(:director)) assert_redirected_to new_questionnaires_path get manage_dashboard_index_path @@ -24,7 +24,7 @@ class UserFlowsTest < ActionDispatch::IntegrationTest get manage_questionnaires_path assert_response :redirect - login(FactoryBot.create(:admin)) + login(FactoryBot.create(:director)) assert_redirected_to manage_questionnaires_path end diff --git a/test/jobs/admin_weekly_report_job_test.rb b/test/jobs/staff_weekly_report_job_test.rb similarity index 74% rename from test/jobs/admin_weekly_report_job_test.rb rename to test/jobs/staff_weekly_report_job_test.rb index c8b6007ba..094fd4403 100644 --- a/test/jobs/admin_weekly_report_job_test.rb +++ b/test/jobs/staff_weekly_report_job_test.rb @@ -1,11 +1,11 @@ require "test_helper" -class AdminWeeklyReportJobTest < ActiveJob::TestCase +class StaffWeeklyReportJobTest < ActiveJob::TestCase should "queue a mailer per recipient" do create_list(:user, 3, receive_weekly_report: true) create_list(:user, 2, receive_weekly_report: false) assert_difference "enqueued_jobs.size", 3 do - worker = AdminWeeklyReportJob.new + worker = StaffWeeklyReportJob.new worker.perform end end diff --git a/test/models/questionnaire_test.rb b/test/models/questionnaire_test.rb index d61fcfd47..c1d0ea6c1 100644 --- a/test/models/questionnaire_test.rb +++ b/test/models/questionnaire_test.rb @@ -194,16 +194,16 @@ class QuestionnaireTest < ActiveSupport::TestCase end should "return nil if author deleted" do - user = create(:user, email: "admin@example.com") + user = create(:user, email: "director@example.com") questionnaire = create(:questionnaire, acc_status_author_id: user.id) user.destroy assert_nil questionnaire.acc_status_author end should "return the questionnaire's user" do - user = create(:user, email: "admin@example.com") + user = create(:user, email: "director@example.com") questionnaire = create(:questionnaire, acc_status_author_id: user.id) - assert_equal "admin@example.com", questionnaire.acc_status_author.email + assert_equal "director@example.com", questionnaire.acc_status_author.email end end diff --git a/test/models/user_test.rb b/test/models/user_test.rb index 86e264e0c..2bac1093b 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -64,11 +64,11 @@ class UserTest < ActiveSupport::TestCase assert_equal 2, User.without_questionnaire.count end - should "not return admins" do + should "not return staff" do create(:questionnaire) # user, has questionnaire - create(:user, role: :event_tracking) # user, does not - create(:user, role: :admin_limited_access) # admin, does not - create(:user, role: :admin) # admin, does not + create(:user, role: :volunteer) # volunteer, does not + create(:user, role: :organizer) # organizer, does not + create(:user, role: :director) # director, does not assert_equal 4, User.count assert_equal 1, User.without_questionnaire.count end @@ -80,6 +80,50 @@ class UserTest < ActiveSupport::TestCase end end + context "current_user is staff" do + should "not report user as staff" do + user = create(:user, role: user) + assert_equal false, user.staff? + end + + should "report volunteer as staff" do + user = create(:user, role: :volunteer) + assert_equal true, user.staff? + end + + should "report organizer as staff" do + user = create(:user, role: :organizer) + assert_equal true, user.staff? + end + + should "report director as staff" do + user = create(:user, role: :director) + assert_equal true, user.staff? + end + end + + context "current_user is organizing staff" do + should "not report user as organizing staff" do + user = create(:user, role: user) + assert_equal false, user.organizing_staff? + end + + should "not report volunteer as organizing staff" do + user = create(:user, role: :volunteer) + assert_equal false, user.organizing_staff? + end + + should "report organizer as organizing staff" do + user = create(:user, role: :organizer) + assert_equal true, user.organizing_staff? + end + + should "report director as organizing staff" do + user = create(:user, role: :director) + assert_equal true, user.organizing_staff? + end + end + context "safe_receive_weekly_report" do should "return false if user is inactive" do user = build(:user, is_active: true, receive_weekly_report: true) diff --git a/vendor/cache/puma-4.3.4.gem b/vendor/cache/puma-4.3.4.gem new file mode 100644 index 000000000..422fc484c Binary files /dev/null and b/vendor/cache/puma-4.3.4.gem differ