hackathon_manager 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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