hackathon_manager 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +90 -0
  4. data/Rakefile +36 -0
  5. data/app/assets/config/hackathon_manager_manifest.js +0 -0
  6. data/app/assets/javascripts/hackathon_manager/application.js +16 -0
  7. data/app/assets/javascripts/hackathon_manager/jquery.transit.min.js +1 -0
  8. data/app/assets/javascripts/hackathon_manager/main.js +237 -0
  9. data/app/assets/javascripts/hackathon_manager/manage/application.js +20 -0
  10. data/app/assets/javascripts/hackathon_manager/manage/lib/emailEvents.js +25 -0
  11. data/app/assets/javascripts/hackathon_manager/manage/lib/jquery.bulkRowSelect.js +13 -0
  12. data/app/assets/javascripts/hackathon_manager/manage/lib/jquery.bulkRowedit.js +42 -0
  13. data/app/assets/javascripts/hackathon_manager/manage/lib/jquery.chartkickAutoReload.js +8 -0
  14. data/app/assets/javascripts/hackathon_manager/manage/lib/setupDataTables.js +98 -0
  15. data/app/assets/javascripts/hackathon_manager/manage/lib/setupHighcharts.js +34 -0
  16. data/app/assets/javascripts/hackathon_manager/manage/map.js +58 -0
  17. data/app/assets/javascripts/hackathon_manager/registrations.js +26 -0
  18. data/app/assets/javascripts/hackathon_manager/us.json +1 -0
  19. data/app/assets/javascripts/hackathon_manager/vendor/buttons.html5.min.js +22 -0
  20. data/app/assets/javascripts/hackathon_manager/vendor/d3.v3.min.js +5 -0
  21. data/app/assets/javascripts/hackathon_manager/vendor/dataTables.buttons.min.js +35 -0
  22. data/app/assets/javascripts/hackathon_manager/vendor/jquery.dataTables.min.js +164 -0
  23. data/app/assets/javascripts/hackathon_manager/vendor/pdfmake.min.js +22 -0
  24. data/app/assets/javascripts/hackathon_manager/vendor/queue.v1.min.js +1 -0
  25. data/app/assets/javascripts/hackathon_manager/vendor/topojson.v1.min.js +1 -0
  26. data/app/assets/javascripts/hackathon_manager/vendor/vfs_fonts.js +1 -0
  27. data/app/assets/stylesheets/hackathon_manager/core.sass +20 -0
  28. data/app/assets/stylesheets/hackathon_manager/datatables/buttons.dataTables.min.css +1 -0
  29. data/app/assets/stylesheets/hackathon_manager/datatables/jquery.dataTables.min.css +1 -0
  30. data/app/assets/stylesheets/hackathon_manager/forms/_confirmation.sass +21 -0
  31. data/app/assets/stylesheets/hackathon_manager/forms/_forms.sass +243 -0
  32. data/app/assets/stylesheets/hackathon_manager/general/_base.sass +105 -0
  33. data/app/assets/stylesheets/hackathon_manager/general/_button.sass +49 -0
  34. data/app/assets/stylesheets/hackathon_manager/general/_footer.sass +21 -0
  35. data/app/assets/stylesheets/hackathon_manager/general/_main.sass +4 -0
  36. data/app/assets/stylesheets/hackathon_manager/general/_media-queries.sass +52 -0
  37. data/app/assets/stylesheets/hackathon_manager/general/_mixins.sass +58 -0
  38. data/app/assets/stylesheets/hackathon_manager/general/_mlh.sass +13 -0
  39. data/app/assets/stylesheets/hackathon_manager/general/_sidebar.sass +70 -0
  40. data/app/assets/stylesheets/hackathon_manager/general/_status-colors.sass +14 -0
  41. data/app/assets/stylesheets/hackathon_manager/general/_table.sass +26 -0
  42. data/app/assets/stylesheets/hackathon_manager/mailer.sass +108 -0
  43. data/app/assets/stylesheets/hackathon_manager/manage.sass +119 -0
  44. data/app/assets/stylesheets/hackathon_manager/scaffolds.scss +50 -0
  45. data/app/assets/stylesheets/variables.sass +41 -0
  46. data/app/controllers/bus_lists_controller.rb +37 -0
  47. data/app/controllers/concerns/questionnaires_controllable.rb +15 -0
  48. data/app/controllers/manage/admins_controller.rb +55 -0
  49. data/app/controllers/manage/application_controller.rb +13 -0
  50. data/app/controllers/manage/bus_lists_controller.rb +71 -0
  51. data/app/controllers/manage/dashboard_controller.rb +112 -0
  52. data/app/controllers/manage/messages_controller.rb +88 -0
  53. data/app/controllers/manage/questionnaires_controller.rb +172 -0
  54. data/app/controllers/manage/schools_controller.rb +87 -0
  55. data/app/controllers/manage/stats_controller.rb +77 -0
  56. data/app/controllers/questionnaires_controller.rb +145 -0
  57. data/app/controllers/rsvps_controller.rb +97 -0
  58. data/app/controllers/users/omniauth_callbacks_controller.rb +18 -0
  59. data/app/controllers/users/registrations_controller.rb +63 -0
  60. data/app/datatables/admin_datatable.rb +29 -0
  61. data/app/datatables/message_datatable.rb +30 -0
  62. data/app/datatables/questionnaire_datatable.rb +39 -0
  63. data/app/datatables/school_datatable.rb +34 -0
  64. data/app/helpers/hackathon_manager_helper.rb +36 -0
  65. data/app/helpers/manage/dashboard_helper.rb +9 -0
  66. data/app/inputs/deletable_attachment_input.rb +11 -0
  67. data/app/inputs/formatted_boolean_input.rb +26 -0
  68. data/app/inputs/school_selection_input.rb +9 -0
  69. data/app/mailers/application_mailer.rb +4 -0
  70. data/app/mailers/mail_preview.rb +42 -0
  71. data/app/mailers/mailer.rb +84 -0
  72. data/app/models/bus_list.rb +24 -0
  73. data/app/models/deletable_attachment.rb +17 -0
  74. data/app/models/fips.rb +3 -0
  75. data/app/models/message.rb +76 -0
  76. data/app/models/questionnaire.rb +166 -0
  77. data/app/models/schedule.rb +53 -0
  78. data/app/models/school.rb +31 -0
  79. data/app/models/school_name_duplicate.rb +7 -0
  80. data/app/models/user.rb +52 -0
  81. data/app/views/application/_bus_list_info.html.haml +20 -0
  82. data/app/views/application/_bus_list_stats.html.haml +9 -0
  83. data/app/views/application/_questionnaire_summary.html.haml +54 -0
  84. data/app/views/bus_lists/show.html.haml +45 -0
  85. data/app/views/devise/passwords/_form.html.haml +9 -0
  86. data/app/views/devise/passwords/edit.html.haml +14 -0
  87. data/app/views/devise/passwords/new.html.haml +5 -0
  88. data/app/views/devise/registrations/_form.html.haml +8 -0
  89. data/app/views/devise/registrations/edit.html.haml +20 -0
  90. data/app/views/devise/registrations/new.html.haml +18 -0
  91. data/app/views/devise/sessions/_form.html.haml +8 -0
  92. data/app/views/devise/sessions/new.html.haml +9 -0
  93. data/app/views/layouts/_shared_footer.html.haml +1 -0
  94. data/app/views/layouts/_sidebar.html.haml +22 -0
  95. data/app/views/layouts/blank.html.haml +12 -0
  96. data/app/views/layouts/dayof.html.haml +12 -0
  97. data/app/views/layouts/hackathon_manager.html.haml +12 -0
  98. data/app/views/layouts/mailer.html.erb +51 -0
  99. data/app/views/layouts/manage/application.html.haml +26 -0
  100. data/app/views/mailer/_getting_there.html.erb +14 -0
  101. data/app/views/mailer/_questions.html.erb +2 -0
  102. data/app/views/mailer/accepted_email.html.erb +13 -0
  103. data/app/views/mailer/application_confirmation_email.html.erb +13 -0
  104. data/app/views/mailer/bulk_message_email.html.erb +1 -0
  105. data/app/views/mailer/bulk_templates/_default.html.erb +1 -0
  106. data/app/views/mailer/bus_captain_confirmation_email.html.erb +12 -0
  107. data/app/views/mailer/bus_list_update_email.html.erb +7 -0
  108. data/app/views/mailer/denied_email.html.erb +5 -0
  109. data/app/views/mailer/incomplete_reminder_email.html.erb +6 -0
  110. data/app/views/mailer/rsvp_confirmation_email.html.erb +8 -0
  111. data/app/views/mailer/slack_invite_email.html.erb +10 -0
  112. data/app/views/manage/admins/_form.html.haml +18 -0
  113. data/app/views/manage/admins/edit.html.haml +12 -0
  114. data/app/views/manage/admins/index.html.haml +15 -0
  115. data/app/views/manage/admins/new.html.haml +8 -0
  116. data/app/views/manage/admins/show.html.haml +17 -0
  117. data/app/views/manage/bus_lists/_form.html.haml +14 -0
  118. data/app/views/manage/bus_lists/edit.html.haml +8 -0
  119. data/app/views/manage/bus_lists/index.html.haml +26 -0
  120. data/app/views/manage/bus_lists/new.html.haml +6 -0
  121. data/app/views/manage/bus_lists/show.html.haml +92 -0
  122. data/app/views/manage/dashboard/index.html.haml +64 -0
  123. data/app/views/manage/dashboard/map_data.tsv.erb +48 -0
  124. data/app/views/manage/messages/_form.html.haml +15 -0
  125. data/app/views/manage/messages/edit.html.haml +10 -0
  126. data/app/views/manage/messages/index.html.haml +17 -0
  127. data/app/views/manage/messages/new.html.haml +8 -0
  128. data/app/views/manage/messages/show.html.haml +50 -0
  129. data/app/views/manage/questionnaires/_form.html.haml +54 -0
  130. data/app/views/manage/questionnaires/edit.html.haml +12 -0
  131. data/app/views/manage/questionnaires/index.html.haml +36 -0
  132. data/app/views/manage/questionnaires/new.html.haml +8 -0
  133. data/app/views/manage/questionnaires/show.html.haml +63 -0
  134. data/app/views/manage/schools/_form.html.haml +16 -0
  135. data/app/views/manage/schools/edit.html.haml +12 -0
  136. data/app/views/manage/schools/index.html.haml +18 -0
  137. data/app/views/manage/schools/merge.html.haml +35 -0
  138. data/app/views/manage/schools/new.html.haml +8 -0
  139. data/app/views/manage/schools/show.html.haml +52 -0
  140. data/app/views/manage/stats/index.html.haml +55 -0
  141. data/app/views/questionnaires/_form.html.haml +70 -0
  142. data/app/views/questionnaires/edit.html.haml +10 -0
  143. data/app/views/questionnaires/new.html.haml +7 -0
  144. data/app/views/questionnaires/show.html.haml +30 -0
  145. data/app/views/rsvps/show.html.haml +61 -0
  146. data/app/workers/bulk_message_worker.rb +86 -0
  147. data/app/workers/slack_invite_worker.rb +49 -0
  148. data/config/blazer.yml +56 -0
  149. data/config/initializers/ajax_datatables_rails.rb +7 -0
  150. data/config/initializers/chartkick.rb +4 -0
  151. data/config/initializers/devise.rb +265 -0
  152. data/config/initializers/hackathon.rb +9 -0
  153. data/config/initializers/mime_types.rb +5 -0
  154. data/config/initializers/new_framework_defaults.rb +20 -0
  155. data/config/initializers/sidekiq.rb +11 -0
  156. data/config/initializers/simple_form.rb +164 -0
  157. data/config/initializers/static_data.rb +7 -0
  158. data/config/initializers/wrap_parameters.rb +14 -0
  159. data/config/routes.rb +74 -0
  160. data/db/migrate/20141011210642_create_participants.rb +18 -0
  161. data/db/migrate/20141029055313_create_schools.rb +12 -0
  162. data/db/migrate/20150104071608_add_shirt_and_dietary_medical_to_participants.rb +6 -0
  163. data/db/migrate/20150104190233_add_attachment_resume_to_participants.rb +13 -0
  164. data/db/migrate/20150110020958_add_international_to_participants.rb +5 -0
  165. data/db/migrate/20150110215933_change_participants_to_registration.rb +5 -0
  166. data/db/migrate/20150110222214_create_users.rb +5 -0
  167. data/db/migrate/20150110222455_add_portfolio_and_vcs_urls_to_registrations.rb +6 -0
  168. data/db/migrate/20150110222655_add_devise_to_users.rb +48 -0
  169. data/db/migrate/20150111000224_change_resgistrations_to_questionnaire.rb +5 -0
  170. data/db/migrate/20150111012709_add_questionnaire_ref_to_users.rb +8 -0
  171. data/db/migrate/20150113205638_add_amin_to_users.rb +5 -0
  172. data/db/migrate/20150113233730_add_questionnaire_count_to_schools.rb +12 -0
  173. data/db/migrate/20150125213100_set_default_admin_value.rb +17 -0
  174. data/db/migrate/20150216232155_add_agreement_accepted_to_questionnaires.rb +5 -0
  175. data/db/migrate/20150218051450_add_admin_read_only_to_users.rb +5 -0
  176. data/db/migrate/20150221165513_create_messages.rb +15 -0
  177. data/db/migrate/20150225235817_add_status_to_user.rb +7 -0
  178. data/db/migrate/20150302011457_create_fips.rb +11 -0
  179. data/db/migrate/20150326031423_add_template_to_message.rb +5 -0
  180. data/db/migrate/20150410175056_create_bus_lists.rb +12 -0
  181. data/db/migrate/20150411161432_add_capacity_notes_captain_to_bus_lists.rb +8 -0
  182. data/db/migrate/20150415165844_add_is_bus_captain_to_questionnaire.rb +5 -0
  183. data/db/migrate/20150415181114_add_check_in_data_to_questionnaire.rb +8 -0
  184. data/db/migrate/20151224015223_change_read_only_user_to_limited.rb +5 -0
  185. data/db/migrate/20160110012217_add_code_of_conduct_accepted_to_questionnaire.rb +5 -0
  186. data/db/migrate/20160110222639_add_omniauth_to_users.rb +8 -0
  187. data/db/migrate/20160111020817_update_questionnaire_for_my_mlh.rb +14 -0
  188. data/db/migrate/20160112222137_add_option_for_alt_travel_to_questionnaire.rb +6 -0
  189. data/db/migrate/20160208061253_rename_can_share_resume_to_info.rb +5 -0
  190. data/db/migrate/20161020032736_remove_resume_from_questionnaires.rb +14 -0
  191. data/db/migrate/20161024145452_add_data_sharing_to_questionnaire.rb +5 -0
  192. data/db/migrate/20161206073921_rename_graduation_to_level_of_study.rb +6 -0
  193. data/db/migrate/20161206084722_add_reminder_sent_at_to_users.rb +5 -0
  194. data/db/migrate/20161208055809_add_attachment_resume_to_questionnaires.rb +11 -0
  195. data/db/migrate/20161212030010_add_interest_to_questionnaire.rb +5 -0
  196. data/db/migrate/20170107210122_create_school_name_duplicates.rb +10 -0
  197. data/db/migrate/20170128063020_install_blazer.rb +45 -0
  198. data/db/schools.csv +1 -0
  199. data/db/seeds.rb +17 -0
  200. data/lib/hackathon_manager/engine.rb +35 -0
  201. data/lib/hackathon_manager/version.rb +3 -0
  202. data/lib/hackathon_manager.rb +5 -0
  203. data/lib/tasks/coverage.rake +14 -0
  204. data/lib/tasks/hackathon_manager_tasks.rake +4 -0
  205. metadata +667 -0
@@ -0,0 +1,97 @@
1
+ class RsvpsController < ApplicationController
2
+ before_action :logged_in
3
+ before_action :check_user_has_questionnaire
4
+ before_action :find_questionnaire
5
+ before_action :require_accepted_questionnaire
6
+
7
+ layout 'hackathon_manager'
8
+
9
+ def logged_in
10
+ authenticate_user!
11
+ end
12
+
13
+ # GET /rsvp
14
+ def show
15
+ end
16
+
17
+ # GET /rsvp/accept
18
+ def accept
19
+ @questionnaire.acc_status = "rsvp_confirmed"
20
+ @questionnaire.acc_status_author_id = current_user.id
21
+ @questionnaire.acc_status_date = Time.now
22
+ if @questionnaire.save
23
+ Mailer.delay.rsvp_confirmation_email(@questionnaire.id)
24
+ else
25
+ flash[:notice] = "There was an error submitting your response, please check over your application and try again. Did you accept the BrickHack Agreement?"
26
+ end
27
+ redirect_to rsvp_path
28
+ end
29
+
30
+ # GET /rsvp/deny
31
+ def deny
32
+ @questionnaire.acc_status = "rsvp_denied"
33
+ @questionnaire.acc_status_author_id = current_user.id
34
+ @questionnaire.acc_status_date = Time.now
35
+ unless @questionnaire.save
36
+ flash[:notice] = "There was an error submitting your response, please check over your application and try again. Did you accept the BrickHack Agreement?"
37
+ end
38
+ redirect_to rsvp_path
39
+ end
40
+
41
+ # PUT /rsvp
42
+ def update
43
+ unless @questionnaire.update_attributes(params.require(:questionnaire).permit(:agreement_accepted, :phone))
44
+ flash[:notice] = @questionnaire.errors.full_messages.join(", ")
45
+ redirect_to rsvp_path
46
+ return
47
+ end
48
+
49
+ unless ["rsvp_confirmed", "rsvp_denied"].include? params[:questionnaire][:acc_status]
50
+ flash[:notice] = "Please select a RSVP status."
51
+ redirect_to rsvp_path
52
+ return
53
+ end
54
+
55
+ @questionnaire.acc_status_date = Time.now if @questionnaire.acc_status != params[:questionnaire][:acc_status]
56
+ @questionnaire.acc_status = params[:questionnaire][:acc_status]
57
+ @questionnaire.acc_status_author_id = current_user.id
58
+ if !@questionnaire.riding_bus && params[:questionnaire][:riding_bus] == "true" && @questionnaire.bus_list && @questionnaire.bus_list.full?
59
+ flash[:notice] = "Sorry, your bus is full! You may need to arrange other plans for transportation."
60
+ @questionnaire.riding_bus = false
61
+ @questionnaire.bus_captain_interest = false
62
+ elsif !@questionnaire.eligible_for_a_bus?
63
+ @questionnaire.riding_bus = false
64
+ @questionnaire.bus_captain_interest = false
65
+ else
66
+ @questionnaire.riding_bus = params[:questionnaire][:riding_bus]
67
+ @questionnaire.bus_captain_interest = params[:questionnaire][:bus_captain_interest]
68
+ end
69
+
70
+ acc_status_changed = @questionnaire.acc_status_changed?
71
+
72
+ unless @questionnaire.save
73
+ flash[:notice] = @questionnaire.errors.full_message.join(", ")
74
+ redirect_to rsvp_path
75
+ return
76
+ end
77
+
78
+ Mailer.delay.rsvp_confirmation_email(@questionnaire.id) if acc_status_changed && @questionnaire.acc_status == "rsvp_confirmed"
79
+
80
+ redirect_to rsvp_path
81
+ end
82
+
83
+ private
84
+
85
+ def find_questionnaire
86
+ @questionnaire = current_user.questionnaire
87
+ end
88
+
89
+ def check_user_has_questionnaire
90
+ redirect_to new_questionnaires_path if current_user.questionnaire.nil?
91
+ end
92
+
93
+ def require_accepted_questionnaire
94
+ return if @questionnaire.can_rsvp? || @questionnaire.checked_in?
95
+ redirect_to new_questionnaires_path
96
+ end
97
+ end
@@ -0,0 +1,18 @@
1
+ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
2
+ def mlh
3
+ @user = User.from_omniauth(request.env["omniauth.auth"])
4
+ if @user.persisted?
5
+ sign_in_and_redirect @user, event: :authentication # this will throw if @user is not activated
6
+ session["devise.provider_data"] = request.env["omniauth.auth"]
7
+ set_flash_message(:notice, :success, kind: "My MLH") if is_navigational_format?
8
+ @user.queue_reminder_email
9
+ else
10
+ redirect_to new_user_registration_url
11
+ end
12
+ end
13
+
14
+ def failure
15
+ flash[:notice] = "External authentication failed - try again?"
16
+ redirect_to new_user_session_url
17
+ end
18
+ end
@@ -0,0 +1,63 @@
1
+ class Users::RegistrationsController < Devise::RegistrationsController
2
+ # before_action :configure_sign_up_params, only: [:create]
3
+ # before_action :configure_account_update_params, only: [:update]
4
+
5
+ layout 'hackathon_manager'
6
+
7
+ # GET /resource/sign_up
8
+ # def new
9
+ # super
10
+ # end
11
+
12
+ # POST /resource
13
+ # def create
14
+ # super
15
+ # end
16
+
17
+ # GET /resource/edit
18
+ def edit
19
+ redirect_to questionnaires_path
20
+ end
21
+
22
+ # PUT /resource
23
+ def update
24
+ redirect_to questionnaires_path
25
+ end
26
+
27
+ # DELETE /resource
28
+ def destroy
29
+ current_user.questionnaire.destroy if current_user.questionnaire.present?
30
+ super
31
+ end
32
+
33
+ # GET /resource/cancel
34
+ # Forces the session data which is usually expired after sign
35
+ # in to be expired now. This is useful if the user wants to
36
+ # cancel oauth signing in/up in the middle of the process,
37
+ # removing all OAuth session data.
38
+ # def cancel
39
+ # super
40
+ # end
41
+
42
+ # protected
43
+
44
+ # You can put the params you want to permit in the empty array.
45
+ # def configure_sign_up_params
46
+ # devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
47
+ # end
48
+
49
+ # You can put the params you want to permit in the empty array.
50
+ # def configure_account_update_params
51
+ # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
52
+ # end
53
+
54
+ # The path used after sign up.
55
+ # def after_sign_up_path_for(resource)
56
+ # super(resource)
57
+ # end
58
+
59
+ # The path used after sign up for inactive accounts.
60
+ # def after_inactive_sign_up_path_for(resource)
61
+ # super(resource)
62
+ # end
63
+ end
@@ -0,0 +1,29 @@
1
+ class AdminDatatable < AjaxDatatablesRails::Base
2
+ def_delegators :@view, :link_to, :manage_admin_path
3
+
4
+ def view_columns
5
+ @view_columns ||= {
6
+ id: { source: 'User.id' },
7
+ email: { source: 'User.email' },
8
+ admin_limited_access: { source: 'User.admin_limited_access', searchable: false }
9
+ }
10
+ end
11
+
12
+ private
13
+
14
+ def data
15
+ records.map do |record|
16
+ {
17
+ link: link_to('<i class="fa fa-search"></i>'.html_safe, manage_admin_path(record)),
18
+ id: record.id,
19
+ email: record.email,
20
+ admin_limited_access: record.admin_limited_access ? 'Limited Access' : 'Full Access'
21
+ }
22
+ end
23
+ end
24
+
25
+ # rubocop:disable Style/AccessorMethodName
26
+ def get_raw_records
27
+ User.where(admin: true)
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ class MessageDatatable < AjaxDatatablesRails::Base
2
+ def_delegators :@view, :link_to, :manage_message_path
3
+
4
+ def view_columns
5
+ @view_columns ||= {
6
+ id: { source: "Message.id" },
7
+ name: { source: "Message.name" },
8
+ subject: { source: "Message.subject" }
9
+ }
10
+ end
11
+
12
+ private
13
+
14
+ def data
15
+ records.map do |record|
16
+ {
17
+ link: link_to('<i class="fa fa-search"></i>'.html_safe, manage_message_path(record)),
18
+ id: record.id,
19
+ name: record.name,
20
+ subject: record.subject,
21
+ status: record.status.titleize
22
+ }
23
+ end
24
+ end
25
+
26
+ # rubocop:disable Style/AccessorMethodName
27
+ def get_raw_records
28
+ Message.unscoped
29
+ end
30
+ end
@@ -0,0 +1,39 @@
1
+ class QuestionnaireDatatable < AjaxDatatablesRails::Base
2
+ def_delegators :@view, :link_to, :manage_questionnaire_path, :manage_school_path, :current_user
3
+
4
+ def view_columns
5
+ @view_columns ||= {
6
+ id: { source: 'Questionnaire.id', cond: :eq },
7
+ first_name: { source: 'Questionnaire.first_name' },
8
+ last_name: { source: 'Questionnaire.last_name' },
9
+ email: { source: 'User.email' },
10
+ admin: { source: 'User.admin', cond: :eq, searchable: false },
11
+ acc_status: { source: 'Questionnaire.acc_status', searchable: false },
12
+ checked_in: { source: 'Questionnaire.checked_in_at', searchable: false },
13
+ school: { source: 'School.name' }
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ def data
20
+ records.map do |record|
21
+ {
22
+ bulk: current_user.admin_limited_access ? '' : "<input type=\"checkbox\" data-bulk-row-edit=\"#{record.id}\">".html_safe,
23
+ link: link_to('<i class="fa fa-search"></i>'.html_safe, manage_questionnaire_path(record)),
24
+ id: record.id,
25
+ first_name: record.first_name,
26
+ last_name: record.last_name,
27
+ email: record.email,
28
+ acc_status: "<span class=\"acc-status-#{record.acc_status}\">#{record.acc_status.titleize}</span>".html_safe,
29
+ checked_in: record.checked_in? ? '<span class="acc-status-accepted">Yes</span>'.html_safe : 'No',
30
+ school: link_to(record.school.name, manage_school_path(record.school))
31
+ }
32
+ end
33
+ end
34
+
35
+ # rubocop:disable Style/AccessorMethodName
36
+ def get_raw_records
37
+ Questionnaire.includes(:user, :school).references(:user, :school)
38
+ end
39
+ end
@@ -0,0 +1,34 @@
1
+ class SchoolDatatable < AjaxDatatablesRails::Base
2
+ def_delegators :@view, :link_to, :manage_school_path, :manage_bus_list_path
3
+
4
+ def view_columns
5
+ @view_columns ||= {
6
+ id: { source: 'School.id', cond: :eq },
7
+ name: { source: 'School.name' },
8
+ city: { source: 'School.city' },
9
+ state: { source: 'School.state' },
10
+ questionnaire_count: { source: 'School.questionnaire_count', searchable: false }
11
+ }
12
+ end
13
+
14
+ private
15
+
16
+ def data
17
+ records.map do |record|
18
+ {
19
+ link: link_to('<i class="fa fa-search"></i>'.html_safe, manage_school_path(record)),
20
+ id: record.id,
21
+ name: record.name,
22
+ city: record.city,
23
+ state: record.state,
24
+ questionnaire_count: record.questionnaire_count,
25
+ bus_list: record.bus_list ? link_to(record.bus_list.name, manage_bus_list_path(record.bus_list)) : ''
26
+ }
27
+ end
28
+ end
29
+
30
+ # rubocop:disable Style/AccessorMethodName
31
+ def get_raw_records
32
+ School.all
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ module HackathonManagerHelper
2
+ def title(page_title)
3
+ content_for(:title) { page_title + " - BrickHack" }
4
+ page_title
5
+ end
6
+
7
+ def btn_link_to(name, path, options = {})
8
+ options[:class] ? options[:class] += " button" : options[:class] = "button"
9
+ link_to(name, path, options)
10
+ end
11
+
12
+ def phone_link_to(phone_number)
13
+ link_to(phone_number, "tel:#{phone_number}")
14
+ end
15
+
16
+ def markdown(text)
17
+ markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML,
18
+ no_intra_emphasis: true,
19
+ fenced_code_blocks: true,
20
+ disable_indented_code_blocks: true,
21
+ autolink: true,
22
+ tables: true,
23
+ underline: true,
24
+ hard_wrap: true)
25
+ markdown.render(text).html_safe
26
+ end
27
+
28
+ # https://github.com/rails/sprockets-rails/issues/298#issuecomment-168927471
29
+ def asset_available?(logical_path)
30
+ if Rails.configuration.assets.compile
31
+ Rails.application.precompiled_assets.include? logical_path
32
+ else
33
+ Rails.application.assets_manifest.assets[logical_path].present?
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ module Manage
2
+ module DashboardHelper
3
+ def cache_key_for_questionnaires
4
+ count = Questionnaire.count
5
+ max_updated_at = Questionnaire.maximum(:updated_at).try(:utc).try(:to_s, :number)
6
+ "questionnaires/all-#{count}-#{max_updated_at}"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ class DeletableAttachmentInput < SimpleForm::Inputs::FileInput
2
+ def input(wrapper_options)
3
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
4
+ out = ''
5
+ out << @builder.file_field(attribute_name, merged_input_options)
6
+ if object.send("#{attribute_name}?")
7
+ out << @builder.input("delete_#{attribute_name}", as: :boolean, label: "Remove?")
8
+ end
9
+ out.html_safe
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ class FormattedBooleanInput < SimpleForm::Inputs::Base
2
+ def input(wrapper_options = nil)
3
+ options = merge_wrapper_options(input_html_options, wrapper_options)
4
+ @builder.check_box(attribute_name, options, checked_value, unchecked_value)
5
+ end
6
+
7
+ private
8
+
9
+ def checked_value
10
+ options.fetch(:checked_value, '1')
11
+ end
12
+
13
+ def unchecked_value
14
+ options.fetch(:unchecked_value, '0')
15
+ end
16
+
17
+ def merge_wrapper_options(options, wrapper_options)
18
+ if wrapper_options
19
+ options.merge(wrapper_options) do |_, oldval, newval|
20
+ oldval + Array(newval) if oldval.is_a?(Array)
21
+ end
22
+ else
23
+ options
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,9 @@
1
+ class SchoolSelectionInput < SimpleForm::Inputs::Base
2
+ def input(wrapper_options)
3
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
4
+ input_name = attribute_name.to_s.gsub(/_id/, '_name')
5
+ value = options[:value] || @builder.object.send(attribute_name).blank? ? '' : @builder.object.school.name
6
+ text_field_options = merged_input_options.merge(data: { school_picker: true }, name: "#{object_name}[#{input_name}]", value: value)
7
+ template.text_field(input_name, value, text_field_options)
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ class ApplicationMailer < ActionMailer::Base
2
+ default from: 'codeRIT <noreply@coderit.org>'
3
+ layout 'mailer'
4
+ end
@@ -0,0 +1,42 @@
1
+ if defined?(ActionMailer::Preview)
2
+ class MailPreview < ActionMailer::Preview
3
+ def application_confirmation_email
4
+ questionnaire = Questionnaire.first
5
+ Mailer.application_confirmation_email(questionnaire)
6
+ end
7
+
8
+ def rsvp_confirmation_email
9
+ Mailer.rsvp_confirmation_email(Questionnaire.first.id)
10
+ end
11
+
12
+ def accepted_email
13
+ Mailer.accepted_email(Questionnaire.first.id)
14
+ end
15
+
16
+ def denied_email
17
+ Mailer.denied_email(Questionnaire.first.id)
18
+ end
19
+
20
+ def bulk_message_email
21
+ message = Message.first
22
+ Mailer.bulk_message_email(message, User.first.id)
23
+ end
24
+
25
+ def incomplete_reminder_email
26
+ Mailer.incomplete_reminder_email(User.without_questionnaire.first.id)
27
+ end
28
+
29
+ def bus_captain_confirmation_email
30
+ buslist = BusList.first
31
+ Mailer.bus_captain_confirmation_email(buslist.id, buslist.captains.first.id)
32
+ end
33
+
34
+ def slack_invite_email
35
+ Mailer.slack_invite_email(Questionnaire.first.id)
36
+ end
37
+
38
+ def bus_list_update_email
39
+ Mailer.bus_list_update_email(BusList.first.passengers.first.id)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,84 @@
1
+ class Mailer < ApplicationMailer
2
+ include Roadie::Rails::Automatic
3
+ add_template_helper(HackathonManagerHelper)
4
+
5
+ default from: '"BrickHack" <noreply@coderit.org>'
6
+
7
+ def application_confirmation_email(questionnaire_id)
8
+ @questionnaire = Questionnaire.find(questionnaire_id)
9
+ return unless @questionnaire.present? && @questionnaire.user.present?
10
+ mail_questionnaire("Application Received")
11
+ end
12
+
13
+ def rsvp_confirmation_email(questionnaire_id)
14
+ @questionnaire = Questionnaire.find(questionnaire_id)
15
+ return unless @questionnaire.present? && @questionnaire.user.present?
16
+ mail_questionnaire("RSVP Confirmation")
17
+ end
18
+
19
+ def accepted_email(questionnaire_id)
20
+ @questionnaire = Questionnaire.find(questionnaire_id)
21
+ return unless @questionnaire.present? && @questionnaire.user.present?
22
+ mail_questionnaire("You've been accepted!")
23
+ end
24
+
25
+ def denied_email(questionnaire_id)
26
+ @questionnaire = Questionnaire.find(questionnaire_id)
27
+ return unless @questionnaire.present? && @questionnaire.user.present?
28
+ mail_questionnaire("Your application status")
29
+ end
30
+
31
+ def bulk_message_email(message_id, user_id)
32
+ @message = Message.find(message_id)
33
+ @user = User.find(user_id)
34
+ return if @user.blank? || @message.blank?
35
+ mail(
36
+ to: pretty_email(@user.full_name, @user.email),
37
+ subject: @message.subject
38
+ )
39
+ end
40
+
41
+ def incomplete_reminder_email(user_id)
42
+ @user = User.find(user_id)
43
+ return if @user.blank? || @user.questionnaire || Time.now.to_date > Rails.configuration.hackathon['last_day_to_apply']
44
+ mail(
45
+ to: @user.email,
46
+ subject: "Incomplete Application"
47
+ )
48
+ end
49
+
50
+ def bus_captain_confirmation_email(bus_list_id, user_id)
51
+ @user = User.find(user_id)
52
+ @questionnaire = @user.questionnaire
53
+ @bus_list = BusList.find(bus_list_id)
54
+ return if @user.blank? || @user.questionnaire.blank? || !@user.questionnaire.is_bus_captain? || @bus_list.blank?
55
+ mail_questionnaire("You're a bus captain!")
56
+ end
57
+
58
+ def slack_invite_email(questionnaire_id)
59
+ @questionnaire = Questionnaire.find(questionnaire_id)
60
+ return if @questionnaire.blank?
61
+ mail_questionnaire("Slack Invite!")
62
+ end
63
+
64
+ def bus_list_update_email(questionnaire_id)
65
+ @questionnaire = Questionnaire.find(questionnaire_id)
66
+ @bus_list = @questionnaire.bus_list
67
+ return if @questionnaire.blank? || @questionnaire.user.blank? || @bus_list.blank?
68
+ mail_questionnaire("Bus Update")
69
+ end
70
+
71
+ private
72
+
73
+ def pretty_email(name, email)
74
+ return email if name.blank?
75
+ "\"#{name}\" <#{email}>"
76
+ end
77
+
78
+ def mail_questionnaire(subject)
79
+ mail(
80
+ to: pretty_email(@questionnaire.full_name, @questionnaire.user.email),
81
+ subject: subject
82
+ )
83
+ end
84
+ end
@@ -0,0 +1,24 @@
1
+ class BusList < ApplicationRecord
2
+ validates_presence_of :name
3
+ validates_uniqueness_of :name
4
+
5
+ has_many :schools
6
+
7
+ strip_attributes
8
+
9
+ def full?
10
+ passengers.count >= capacity
11
+ end
12
+
13
+ def passengers
14
+ Questionnaire.joins(:school).where("schools.bus_list_id = '#{id}' AND acc_status = 'rsvp_confirmed' AND riding_bus = true").order("schools.name ASC, last_name ASC")
15
+ end
16
+
17
+ def checked_in_passengers
18
+ passengers.select(&:checked_in?)
19
+ end
20
+
21
+ def captains
22
+ passengers.where(is_bus_captain: true)
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ # This needs to be included after all has_attached_file statements in a class
2
+ module DeletableAttachment
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ attachment_definitions.keys.each do |name|
7
+ attr_accessor :"delete_#{name}"
8
+
9
+ before_validation { send(name).destroy if send("delete_#{name}") == '1' }
10
+
11
+ define_method :"delete_#{name}=" do |value|
12
+ instance_variable_set :"@delete_#{name}", value
13
+ send("#{name}_file_name_will_change!")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ class Fips < ApplicationRecord
2
+ strip_attributes
3
+ end
@@ -0,0 +1,76 @@
1
+ class Message < ApplicationRecord
2
+ validates_presence_of :name, :subject, :recipients, :template
3
+ validates_presence_of :body, if: :using_default_template?
4
+
5
+ strip_attributes
6
+
7
+ POSSIBLE_TEMPLATES = ["default"].freeze
8
+
9
+ POSSIBLE_RECIPIENTS = {
10
+ "all" => "Everyone",
11
+ "incomplete" => "Incomplete Applications",
12
+ "complete" => "Complete Applications",
13
+ "accepted" => "Accepted Applications",
14
+ "denied" => "Denied Applications",
15
+ "waitlisted" => "Waitlisted Applications",
16
+ "late-waitlisted" => "Late, Waitlisted Applications",
17
+ "rsvp-confirmed" => "RSVP Confirmed Attendees",
18
+ "rsvp-denied" => "RSVP Denied Attendees",
19
+ "checked-in" => "Checked-In Attendees",
20
+ "non-checked-in" => "Non-Checked-In, Accepted & RSVP'd Applications",
21
+ "bus-list-cornell-bing" => "Bus List: Cornell + Binghamton (Confirmed)",
22
+ "bus-list-buffalo" => "Bus List: Buffalo (Confirmed)",
23
+ "bus-list-albany" => "Bus List: Albany (Confirmed)",
24
+ "bus-list-cornell-bing-eligible" => "Bus List: Cornell + Binghamton (eligible, not signed up)",
25
+ "bus-list-buffalo-eligible" => "Bus List: Buffalo (eligible, not signed up)",
26
+ "bus-list-albany-eligible" => "Bus List: Albany (eligible, not signed up)",
27
+ "bus-list-cornell-bing-applied" => "Bus List: Cornell + Binghamton (applied/not accepted)",
28
+ "bus-list-buffalo-applied" => "Bus List: Buffalo (applied/not accepted)",
29
+ "bus-list-albany-applied" => "Bus List: Albany (applied/not accepted)",
30
+ "school-rit" => "Confirmed or accepted: RIT",
31
+ "school-cornell" => "Confirmed or accepted: Cornell",
32
+ "school-binghamton" => "Confirmed or accepted: Binghamton",
33
+ "school-buffalo" => "Confirmed or accepted: Buffalo",
34
+ "school-waterloo" => "Confirmed or accepted: Waterloo",
35
+ "school-toronto" => "Confirmed or accepted: Toronto",
36
+ "school-umd-collegepark" => "Confirmed or accepted: UMD College Park"
37
+ }.freeze
38
+ serialize :recipients, Array
39
+
40
+ validates_inclusion_of :template, in: POSSIBLE_TEMPLATES
41
+
42
+ def recipients=(values)
43
+ values.present? ? super(values.reject(&:blank?)) : super(values)
44
+ end
45
+
46
+ def recipients_list
47
+ recipients.map { |r| POSSIBLE_RECIPIENTS[r] }.join(', ')
48
+ end
49
+
50
+ def delivered?
51
+ delivered_at.present?
52
+ end
53
+
54
+ def started?
55
+ started_at.present?
56
+ end
57
+
58
+ def queued?
59
+ queued_at.present?
60
+ end
61
+
62
+ def status
63
+ return "delivered" if delivered?
64
+ return "started" if started?
65
+ return "queued" if queued?
66
+ "drafted"
67
+ end
68
+
69
+ def can_edit?
70
+ status == "drafted"
71
+ end
72
+
73
+ def using_default_template?
74
+ template == "default"
75
+ end
76
+ end