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,112 @@
1
+ class Manage::DashboardController < Manage::ApplicationController
2
+ def index
3
+ end
4
+
5
+ def map_data
6
+ @schools = School.where("questionnaire_count", 1..Float::INFINITY).select([:city, :state, :questionnaire_count])
7
+ end
8
+
9
+ def todays_activity_data
10
+ render json: activity_chart_data(["Applications", "Confirmations", "Denials", "Non-Applied Users"], "hour", Time.zone.today.beginning_of_day..Time.zone.today.end_of_day)
11
+ end
12
+
13
+ def todays_stats_data
14
+ date_min = Time.zone.today.beginning_of_day
15
+ render json: {
16
+ "Applications" => Questionnaire.where("created_at >= :date_min", date_min: date_min).count,
17
+ "Confirmations" => Questionnaire.where("acc_status = \"rsvp_confirmed\" AND acc_status_date >= :date_min", date_min: date_min).count,
18
+ "Denials" => Questionnaire.where("acc_status = \"rsvp_denied\" AND acc_status_date >= :date_min", date_min: date_min).count,
19
+ "Non-Applied Users" => User.without_questionnaire.where("users.created_at >= :date_min", date_min: date_min).count
20
+ }
21
+ end
22
+
23
+ def confirmation_activity_data
24
+ render json: activity_chart_data(["Confirmations", "Denials"], "day", 3.week.ago..Time.zone.now)
25
+ end
26
+
27
+ def application_activity_data
28
+ render json: activity_chart_data(["Non-RIT Applications", "RIT Applications", "Non-Applied Users"], "day", 3.week.ago..Time.zone.now)
29
+ end
30
+
31
+ def user_distribution_data
32
+ total_stats_data = {}
33
+ total_count = Questionnaire.count
34
+ rit_count = Questionnaire.where("school_id = \"2304\"").count
35
+ total_stats_data["Non-Applied Users"] = User.where(admin: false).count - total_count
36
+ total_stats_data["Non-RIT Applications"] = total_count - rit_count
37
+ total_stats_data["RIT Applications"] = rit_count
38
+ render json: total_stats_data
39
+ end
40
+
41
+ def application_distribution_data
42
+ counts = Questionnaire.group(:acc_status).count
43
+ results = Questionnaire::POSSIBLE_ACC_STATUS.map { |acc_status, status_title| [status_title, counts[acc_status] || 0] }
44
+ render json: results
45
+ end
46
+
47
+ def schools_confirmed_data
48
+ schools = Questionnaire.joins(:school).group('schools.name').where("acc_status = 'rsvp_confirmed'").order("schools.name ASC").count
49
+ schools_riding = Questionnaire.joins(:school).group('schools.name').where("acc_status = 'rsvp_confirmed' AND riding_bus AND schools.bus_list_id").count
50
+ schools = schools.map do |name, count|
51
+ bus_count_row = schools_riding.select { |school_bus_name, _| school_bus_name == name }
52
+ bus_count = bus_count_row ? bus_count_row[name] || 0 : 0
53
+ count_without_bus = count - bus_count
54
+ [name, count_without_bus, bus_count]
55
+ end
56
+ render json: [
57
+ { name: "Not riding bus", data: schools.sort_by { |_, no_bus, bus| [bus, no_bus] }.reverse },
58
+ { name: "Riding bus", data: schools_riding }
59
+ ]
60
+ end
61
+
62
+ def schools_applied_data
63
+ counted_schools = {
64
+ "pending" => {},
65
+ "denied" => {},
66
+ "rsvp_denied" => {},
67
+ "late_waitlist" => {},
68
+ "waitlist" => {},
69
+ "accepted" => {},
70
+ "rsvp_confirmed" => {}
71
+ }
72
+ # Temporary fix
73
+ # result = Questionnaire.joins(:school).group(:acc_status, "schools.name").where("schools.questionnaire_count >= 5").order("schools.questionnaire_count DESC").order("schools.name ASC").count
74
+ result = Questionnaire.joins(:school).group(:acc_status, "schools.name", "schools.questionnaire_count").order("schools.questionnaire_count DESC").where("schools.questionnaire_count >= 5").count
75
+ result.each do |group, count|
76
+ counted_schools[group[0]][group[1]] = count
77
+ end
78
+ render json: [
79
+ { name: "RSVP Confirmed", data: counted_schools["rsvp_confirmed"] },
80
+ { name: "Accepted", data: counted_schools["accepted"] },
81
+ { name: "Waitlisted", data: counted_schools["waitlist"] },
82
+ { name: "Late Waitlisted", data: counted_schools["late_waitlist"] },
83
+ { name: "RSVP Denied", data: counted_schools["rsvp_denied"] },
84
+ { name: "Denied", data: counted_schools["denied"] },
85
+ { name: "Pending", data: counted_schools["pending"] }
86
+ ]
87
+ end
88
+
89
+ private
90
+
91
+ def activity_chart_data(types, group_type, range)
92
+ chart_data = []
93
+ types.each do |type|
94
+ case type
95
+ when "Applications"
96
+ data = Questionnaire.send("group_by_#{group_type}", :created_at, range: range).count
97
+ when "RIT Applications"
98
+ data = Questionnaire.where("school_id = \"2304\"").send("group_by_#{group_type}", :created_at, range: range).count
99
+ when "Non-RIT Applications"
100
+ data = Questionnaire.where("school_id != \"2304\"").send("group_by_#{group_type}", :created_at, range: range).count
101
+ when "Confirmations"
102
+ data = Questionnaire.where(acc_status: "rsvp_confirmed").send("group_by_#{group_type}", :acc_status_date, range: range).count
103
+ when "Denials"
104
+ data = Questionnaire.where(acc_status: "rsvp_denied").send("group_by_#{group_type}", :acc_status_date, range: range).count
105
+ when "Non-Applied Users"
106
+ data = User.without_questionnaire.send("group_by_#{group_type}", "users.created_at", range: range).count
107
+ end
108
+ chart_data << { name: type, data: data }
109
+ end
110
+ chart_data
111
+ end
112
+ end
@@ -0,0 +1,88 @@
1
+ class Manage::MessagesController < Manage::ApplicationController
2
+ before_action :set_message, only: [:show, :edit, :update, :destroy, :deliver, :preview, :duplicate]
3
+ before_action :check_message_access, only: [:edit, :update, :destroy]
4
+
5
+ respond_to :html
6
+
7
+ def index
8
+ end
9
+
10
+ def datatable
11
+ render json: MessageDatatable.new(view_context)
12
+ end
13
+
14
+ def show
15
+ respond_with(:manage, @message)
16
+ end
17
+
18
+ def new
19
+ @message = Message.new
20
+ respond_with(:manage, @message)
21
+ end
22
+
23
+ def edit
24
+ end
25
+
26
+ def create
27
+ @message = Message.new(message_params)
28
+ @message.save
29
+ respond_with(:manage, @message)
30
+ end
31
+
32
+ def update
33
+ @message.update_attributes(message_params)
34
+ respond_with(:manage, @message)
35
+ end
36
+
37
+ def destroy
38
+ @message.destroy
39
+ respond_with(:manage, @message)
40
+ end
41
+
42
+ def deliver
43
+ if @message.status != "drafted"
44
+ flash[:notice] = "Message cannot be re-delivered"
45
+ return redirect_to manage_messages_path
46
+ end
47
+ @message.update_attribute(:queued_at, Time.now)
48
+ BulkMessageWorker.perform_async(@message.id)
49
+ flash[:notice] = "Message queued for delivery"
50
+ redirect_to manage_message_path(@message)
51
+ end
52
+
53
+ def preview
54
+ email = Mailer.bulk_message_email(@message.id, current_user.id)
55
+ render html: email.body.raw_source.html_safe
56
+ end
57
+
58
+ def duplicate
59
+ new_message = @message.dup
60
+ new_message.update_attributes(
61
+ delivered_at: nil,
62
+ started_at: nil,
63
+ queued_at: nil,
64
+ name: "Copy of #{@message.name}"
65
+ )
66
+ new_message.save
67
+ redirect_to edit_manage_message_path(new_message.reload)
68
+ end
69
+
70
+ private
71
+
72
+ def message_params
73
+ params.require(:message).permit(
74
+ :name, :subject, :template, :body, recipients: []
75
+ )
76
+ end
77
+
78
+ def set_message
79
+ @message = Message.find(params[:id])
80
+ end
81
+
82
+ def check_message_access
83
+ return if @message.can_edit?
84
+
85
+ flash[:notice] = "Message can no longer be modified"
86
+ redirect_to manage_message_path(@message)
87
+ end
88
+ end
@@ -0,0 +1,172 @@
1
+ class Manage::QuestionnairesController < Manage::ApplicationController
2
+ include QuestionnairesControllable
3
+
4
+ before_action :set_questionnaire, only: [:show, :edit, :update, :destroy, :check_in, :convert_to_admin, :update_acc_status, :message_events, :invite_to_slack]
5
+
6
+ respond_to :html
7
+
8
+ def index
9
+ end
10
+
11
+ def datatable
12
+ render json: QuestionnaireDatatable.new(view_context)
13
+ end
14
+
15
+ def show
16
+ respond_with(:manage, @questionnaire)
17
+ end
18
+
19
+ def new
20
+ @questionnaire = ::Questionnaire.new
21
+ respond_with(:manage, @questionnaire)
22
+ end
23
+
24
+ def edit
25
+ end
26
+
27
+ def create
28
+ create_params = questionnaire_params
29
+ email = create_params.delete(:email)
30
+ create_params = convert_school_name_to_id(create_params)
31
+ @questionnaire = ::Questionnaire.new(create_params)
32
+ if @questionnaire.valid?
33
+ user = User.new(email: email, password: Devise.friendly_token.first(10))
34
+ if user.save
35
+ @questionnaire.user = user
36
+ @questionnaire.save
37
+ else
38
+ flash[:notice] = user.errors.full_messages.join(", ")
39
+ if user.errors.include?(:email)
40
+ @questionnaire.errors.add(:email, user.errors[:email].join(", "))
41
+ end
42
+ return render 'new'
43
+ end
44
+ end
45
+ respond_with(:manage, @questionnaire)
46
+ end
47
+
48
+ def update
49
+ update_params = questionnaire_params
50
+ email = update_params.delete(:email)
51
+ @questionnaire.user.update_attributes(email: email) if email.present?
52
+ update_params = convert_school_name_to_id(update_params)
53
+ @questionnaire.update_attributes(update_params)
54
+ respond_with(:manage, @questionnaire)
55
+ end
56
+
57
+ def check_in
58
+ if params[:check_in] == "true"
59
+ if params[:questionnaire]
60
+ q_params = params.require(:questionnaire).permit(:agreement_accepted, :phone, :can_share_info, :email)
61
+ email = q_params.delete(:email)
62
+ @questionnaire.update_attributes(q_params)
63
+ @questionnaire.user.update_attributes(email: email)
64
+ end
65
+ unless @questionnaire.valid?
66
+ flash[:notice] = @questionnaire.errors.full_messages.join(", ")
67
+ redirect_to manage_questionnaire_path @questionnaire
68
+ return
69
+ end
70
+ @questionnaire.update_attribute(:checked_in_at, Time.now)
71
+ @questionnaire.update_attribute(:checked_in_by_id, current_user.id)
72
+ @questionnaire.invite_to_slack
73
+ flash[:notice] = "Checked in #{@questionnaire.full_name}."
74
+ elsif params[:check_in] == "false"
75
+ @questionnaire.update_attribute(:checked_in_at, nil)
76
+ @questionnaire.update_attribute(:checked_in_by_id, current_user.id)
77
+ flash[:notice] = "#{@questionnaire.full_name} no longer checked in."
78
+ else
79
+ flash[:notice] = "No check-in action provided!"
80
+ redirect_to manage_questionnaire_path @questionnaire
81
+ return
82
+ end
83
+ redirect_to manage_questionnaires_path
84
+ end
85
+
86
+ def convert_to_admin
87
+ user = @questionnaire.user
88
+ @questionnaire.destroy
89
+ user.update_attributes(admin: true, admin_limited_access: true)
90
+ redirect_to edit_manage_admin_path(user)
91
+ end
92
+
93
+ def destroy
94
+ user = @questionnaire.user
95
+ @questionnaire.destroy
96
+ user.destroy if user.present?
97
+ respond_with(:manage, @questionnaire)
98
+ end
99
+
100
+ def update_acc_status
101
+ new_status = params[:questionnaire][:acc_status]
102
+ if new_status.blank?
103
+ flash[:notice] = "No status provided"
104
+ redirect_to(manage_questionnaire_path(@questionnaire))
105
+ return
106
+ end
107
+
108
+ @questionnaire.acc_status = new_status
109
+ @questionnaire.acc_status_author_id = current_user.id
110
+ @questionnaire.acc_status_date = Time.now
111
+
112
+ unless @questionnaire.save(validate: false)
113
+ flash[:notice] = "Failed to update acceptance status"
114
+ end
115
+
116
+ process_acc_status_notifications(@questionnaire, new_status)
117
+
118
+ redirect_to manage_questionnaire_path(@questionnaire)
119
+ end
120
+
121
+ def bulk_apply
122
+ action = params[:bulk_action]
123
+ ids = params[:bulk_ids]
124
+ if action.blank? || ids.blank?
125
+ head :bad_request
126
+ return
127
+ end
128
+ Questionnaire.find(ids).each do |q|
129
+ q.acc_status = action
130
+ q.acc_status_author_id = current_user.id
131
+ q.acc_status_date = Time.now
132
+ q.save(validate: false) && process_acc_status_notifications(q, action)
133
+ end
134
+ head :ok
135
+ end
136
+
137
+ def invite_to_slack
138
+ @questionnaire.invite_to_slack
139
+ flash[:notice] = 'Slack invite has been queued for delivery'
140
+ redirect_to manage_questionnaire_path @questionnaire
141
+ end
142
+
143
+ def message_events
144
+ render json: @questionnaire.message_events
145
+ end
146
+
147
+ private
148
+
149
+ def questionnaire_params
150
+ params.require(:questionnaire).permit(
151
+ :email, :experience, :first_name, :last_name, :gender,
152
+ :date_of_birth, :interest, :school_id, :school_name, :major, :level_of_study,
153
+ :shirt_size, :dietary_restrictions, :special_needs, :international,
154
+ :portfolio_url, :vcs_url, :agreement_accepted, :bus_captain_interest,
155
+ :riding_bus, :phone, :can_share_info, :code_of_conduct_accepted,
156
+ :travel_not_from_school, :travel_location, :data_sharing_accepted,
157
+ :resume, :delete_resume, :is_bus_captain
158
+ )
159
+ end
160
+
161
+ def set_questionnaire
162
+ @questionnaire = ::Questionnaire.find(params[:id])
163
+ end
164
+
165
+ def process_acc_status_notifications(questionnaire, new_status)
166
+ Mailer.delay.accepted_email(questionnaire.id) if new_status == "accepted"
167
+ Mailer.delay.rsvp_confirmation_email(questionnaire.id) if new_status == "rsvp_confirmed"
168
+ Mailer.delay.denied_email(questionnaire.id) if new_status == "denied"
169
+
170
+ questionnaire.invite_to_slack if ENV['INVITE_TO_SLACK_WHEN_ACCEPTED'] == 'true' && ['accepted', 'rsvp_confirmed'].include?(new_status)
171
+ end
172
+ end
@@ -0,0 +1,87 @@
1
+ class Manage::SchoolsController < Manage::ApplicationController
2
+ before_action :find_school, only: [:show, :edit, :update, :destroy, :merge, :perform_merge]
3
+
4
+ respond_to :html
5
+
6
+ def index
7
+ end
8
+
9
+ def datatable
10
+ render json: SchoolDatatable.new(view_context)
11
+ end
12
+
13
+ def show
14
+ respond_with(:manage, @school)
15
+ end
16
+
17
+ def new
18
+ @school = ::School.new
19
+ respond_with(:manage, @school)
20
+ end
21
+
22
+ def edit
23
+ end
24
+
25
+ def create
26
+ @school = ::School.new(school_params)
27
+ @school.save
28
+ respond_with(:manage, @school, location: manage_schools_path)
29
+ end
30
+
31
+ def update
32
+ @school.update_attributes(school_params)
33
+ respond_with(:manage, @school, location: manage_schools_path)
34
+ end
35
+
36
+ def destroy
37
+ @school.destroy
38
+ respond_with(:manage, @school, location: manage_schools_path)
39
+ end
40
+
41
+ def merge
42
+ end
43
+
44
+ def perform_merge
45
+ new_school_name = params[:school][:id]
46
+ if new_school_name.blank?
47
+ flash[:notice] = "Error: Must include the new school to merge into!"
48
+ render :merge
49
+ return
50
+ end
51
+
52
+ new_school = School.where(name: new_school_name).first
53
+ if new_school.blank?
54
+ flash[:notice] = "Error: School doesn't exist: #{new_school_name}"
55
+ render :merge
56
+ return
57
+ end
58
+
59
+ Questionnaire.where(school_id: @school.id).each do |q|
60
+ q.update_attribute(:school_id, new_school.id)
61
+ end
62
+
63
+ SchoolNameDuplicate.create(name: @school.name, school_id: new_school.id)
64
+
65
+ @school.reload
66
+
67
+ if @school.questionnaire_count < 1
68
+ @school.destroy
69
+ else
70
+ flash[:notice] = "*** Old school NOT deleted: #{@school.questionnaire_count} questionnaires still associated!\n"
71
+ end
72
+
73
+ redirect_to manage_schools_path(new_school)
74
+ end
75
+
76
+ private
77
+
78
+ def school_params
79
+ params.require(:school).permit(
80
+ :name, :address, :city, :state, :bus_list_id
81
+ )
82
+ end
83
+
84
+ def find_school
85
+ @school = ::School.find(params[:id])
86
+ end
87
+ end
@@ -0,0 +1,77 @@
1
+ class Manage::StatsController < Manage::ApplicationController
2
+ def index
3
+ end
4
+
5
+ def dietary_special_needs
6
+ data = Rails.cache.fetch(cache_key_for_questionnaires("dietary_special_needs")) do
7
+ attributes = [:first_name,
8
+ :last_name,
9
+ :email,
10
+ :phone,
11
+ :checked_in_at,
12
+ :dietary_restrictions,
13
+ :special_needs]
14
+ select_attributes = Array.new(attributes) << :user_id
15
+ data = Questionnaire.where("dietary_restrictions != '' AND acc_status = 'rsvp_confirmed' OR special_needs != '' AND acc_status = 'rsvp_confirmed'").select(select_attributes)
16
+ to_json_array(data, attributes)
17
+ end
18
+ render json: { data: data }
19
+ end
20
+
21
+ def sponsor_info
22
+ data = Rails.cache.fetch(cache_key_for_questionnaires("sponsor_info")) do
23
+ attributes = [:first_name,
24
+ :last_name,
25
+ :email,
26
+ :vcs_url,
27
+ :portfolio_url]
28
+ select_attributes = Array.new(attributes) << :user_id
29
+ data = Questionnaire.where("can_share_info = '1' AND acc_status = 'rsvp_confirmed'").select(select_attributes)
30
+ to_json_array(data, attributes)
31
+ end
32
+ render json: { data: data }
33
+ end
34
+
35
+ def alt_travel
36
+ data = Rails.cache.fetch(cache_key_for_questionnaires("alt_travel")) do
37
+ attributes = [:id,
38
+ :first_name,
39
+ :last_name,
40
+ :email,
41
+ :travel_location,
42
+ :acc_status]
43
+ select_attributes = Array.new(attributes) << [:user_id, :school_id]
44
+ data = Questionnaire.where("travel_not_from_school = '1'").select(select_attributes)
45
+ json = to_json_array(data, attributes)
46
+ json.each do |e|
47
+ e[0] = view_context.link_to("View &raquo;".html_safe, manage_questionnaire_path(e[0]))
48
+ end
49
+ end
50
+ render json: { data: data }
51
+ end
52
+
53
+ def mlh_info
54
+ data = Rails.cache.fetch(cache_key_for_questionnaires("mlh_info")) do
55
+ attributes = [:first_name,
56
+ :last_name,
57
+ :email,
58
+ :phone]
59
+ select_attributes = Array.new(attributes) << :user_id
60
+ data = Questionnaire.select(select_attributes)
61
+ to_json_array(data, attributes)
62
+ end
63
+ render json: { data: data }
64
+ end
65
+
66
+ private
67
+
68
+ def to_json_array(data, attributes)
69
+ data.map { |e| attributes.map { |a| e.send(a) } }
70
+ end
71
+
72
+ def cache_key_for_questionnaires(id)
73
+ count = Questionnaire.count
74
+ max_updated_at = Questionnaire.maximum(:updated_at).try(:utc).try(:to_s, :number)
75
+ "stats/all-#{count}-#{max_updated_at}-#{id}"
76
+ end
77
+ end
@@ -0,0 +1,145 @@
1
+ class QuestionnairesController < ApplicationController
2
+ include QuestionnairesControllable
3
+
4
+ before_action :logged_in
5
+ before_action :find_questionnaire, only: [:show, :update, :edit, :destroy]
6
+
7
+ layout 'hackathon_manager'
8
+
9
+ def logged_in
10
+ authenticate_user!
11
+ end
12
+
13
+ # GET /apply
14
+ # GET /apply.json
15
+ def show
16
+ respond_to do |format|
17
+ format.html # show.html.erb
18
+ format.json { render json: @questionnaire }
19
+ end
20
+ end
21
+
22
+ # GET /apply/new
23
+ # GET /apply/new.json
24
+ def new
25
+ if current_user.questionnaire.present?
26
+ return redirect_to questionnaires_path
27
+ end
28
+ @questionnaire = Questionnaire.new
29
+
30
+ if session["devise.provider_data"] && session["devise.provider_data"]["info"]
31
+ @questionnaire.tap do |q|
32
+ q.first_name = session["devise.provider_data"]["info"]["first_name"]
33
+ q.last_name = session["devise.provider_data"]["info"]["last_name"]
34
+ q.phone = session["devise.provider_data"]["info"]["phone_number"]
35
+ q.level_of_study = session["devise.provider_data"]["info"]["level_of_study"]
36
+ q.major = session["devise.provider_data"]["info"]["major"]
37
+ q.date_of_birth = session["devise.provider_data"]["info"]["date_of_birth"]
38
+ q.shirt_size = session["devise.provider_data"]["info"]["shirt_size"]
39
+ q.dietary_restrictions = session["devise.provider_data"]["info"]["dietary_restrictions"]
40
+ q.special_needs = session["devise.provider_data"]["info"]["special_needs"]
41
+ q.gender = session["devise.provider_data"]["info"]["gender"]
42
+
43
+ school = School.where(name: session["devise.provider_data"]["info"]["school"]["name"]).first_or_create do |s|
44
+ s.name = session["devise.provider_data"]["info"]["school"]["name"]
45
+ end
46
+ q.school_id = school.id
47
+ end
48
+ end
49
+
50
+ respond_to do |format|
51
+ format.html # new.html.erb
52
+ format.json { render json: @questionnaire }
53
+ end
54
+ end
55
+
56
+ # GET /apply/edit
57
+ def edit
58
+ end
59
+
60
+ # POST /apply
61
+ # POST /apply.json
62
+ def create
63
+ if current_user.questionnaire.present?
64
+ return redirect_to questionnaires_path, notice: 'Application already exists.'
65
+ end
66
+ @questionnaire = Questionnaire.new(convert_school_name_to_id(questionnaire_params))
67
+
68
+ respond_to do |format|
69
+ if @questionnaire.save
70
+ current_user.questionnaire = @questionnaire
71
+ @questionnaire.update_attribute(:acc_status, default_acc_status)
72
+ Mailer.delay.application_confirmation_email(@questionnaire.id)
73
+ format.html { redirect_to questionnaires_path, notice: 'Application was successfully created.' }
74
+ format.json { render json: @questionnaire, status: :created, location: @questionnaire }
75
+ else
76
+ format.html { render action: "new" }
77
+ format.json { render json: @questionnaire.errors, status: :unprocessable_entity }
78
+ end
79
+ end
80
+ end
81
+
82
+ # PUT /apply
83
+ # PUT /apply.json
84
+ def update
85
+ update_params = questionnaire_params
86
+ update_params = convert_school_name_to_id(update_params)
87
+
88
+ respond_to do |format|
89
+ if @questionnaire.update_attributes(update_params)
90
+ format.html { redirect_to questionnaires_path, notice: 'Application was successfully updated.' }
91
+ format.json { head :no_content }
92
+ else
93
+ format.html { render action: "edit" }
94
+ format.json { render json: @questionnaire.errors, status: :unprocessable_entity }
95
+ end
96
+ end
97
+ end
98
+
99
+ # DELETE /apply
100
+ # DELETE /apply.json
101
+ def destroy
102
+ @questionnaire.destroy
103
+
104
+ respond_to do |format|
105
+ format.html { redirect_to questionnaires_url }
106
+ format.json { head :no_content }
107
+ end
108
+ end
109
+
110
+ # GET /apply/schools
111
+ def schools
112
+ if params[:name].blank? || params[:name].length < 3
113
+ head :bad_request
114
+ return
115
+ end
116
+ schools = School.where('name LIKE ?', "%#{params[:name]}%").order(questionnaire_count: :desc).limit(20).select(:name).all
117
+ render json: schools.map(&:name)
118
+ end
119
+
120
+ private
121
+
122
+ def questionnaire_params
123
+ params.require(:questionnaire).permit(
124
+ :email, :experience, :first_name, :last_name, :gender,
125
+ :date_of_birth, :interest, :school_id, :school_name, :major, :level_of_study,
126
+ :shirt_size, :dietary_restrictions, :special_needs, :international,
127
+ :portfolio_url, :vcs_url, :agreement_accepted, :bus_captain_interest,
128
+ :riding_bus, :phone, :can_share_info, :code_of_conduct_accepted,
129
+ :travel_not_from_school, :travel_location, :data_sharing_accepted,
130
+ :resume, :delete_resume
131
+ )
132
+ end
133
+
134
+ def find_questionnaire
135
+ unless current_user.questionnaire.present?
136
+ return redirect_to new_questionnaires_path
137
+ end
138
+ @questionnaire = current_user.questionnaire
139
+ end
140
+
141
+ def default_acc_status
142
+ return "late_waitlist" if Rails.configuration.hackathon['auto_late_waitlist']
143
+ "pending"
144
+ end
145
+ end