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,166 @@
1
+ class Questionnaire < ApplicationRecord
2
+ include ActiveModel::Dirty
3
+
4
+ before_validation :consolidate_school_names
5
+ after_save :update_school_questionnaire_count
6
+ after_destroy :update_school_questionnaire_count
7
+
8
+ validates_presence_of :first_name, :last_name, :phone, :date_of_birth, :school_id, :experience, :shirt_size, :interest
9
+ validates_presence_of :gender, :major, :level_of_study
10
+ validates_presence_of :agreement_accepted, message: "Must accept"
11
+ validates_presence_of :code_of_conduct_accepted, message: "Must accept"
12
+ validates_presence_of :data_sharing_accepted, message: "Must accept"
13
+
14
+ has_attached_file :resume
15
+ validates_attachment_content_type :resume, content_type: %w(application/pdf), message: "Invalid file type"
16
+ validates_attachment_size :resume, in: 0..2.megabytes, message: "File size is too big"
17
+
18
+ include DeletableAttachment
19
+
20
+ validates :portfolio_url, url: { allow_blank: true }
21
+ validates :vcs_url, url: { allow_blank: true }
22
+ validates_format_of :vcs_url, with: /((github.com\/\w+\/?)|(bitbucket.org\/\w+\/?))/, allow_blank: true, message: "Must be a GitHub or BitBucket url"
23
+
24
+ belongs_to :school
25
+
26
+ strip_attributes
27
+
28
+ POSSIBLE_EXPERIENCES = {
29
+ "first" => "This is my 1st hackathon!",
30
+ "experienced" => "My feet are wet. (1-5 hackathons)",
31
+ "expert" => "I'm a veteran hacker. (6+ hackathons)"
32
+ }.freeze
33
+
34
+ POSSIBLE_INTERESTS = {
35
+ "design" => "Design",
36
+ "software" => "Software",
37
+ "hardware" => "Hardware",
38
+ "combination" => "Combination of everything!"
39
+ }.freeze
40
+
41
+ POSSIBLE_SHIRT_SIZES = [
42
+ "Women's - XS",
43
+ "Women's - S",
44
+ "Women's - M",
45
+ "Women's - L",
46
+ "Women's - XL",
47
+ "Unisex - XS",
48
+ "Unisex - S",
49
+ "Unisex - M",
50
+ "Unisex - L",
51
+ "Unisex - XL"
52
+ ].freeze
53
+
54
+ POSSIBLE_ACC_STATUS = {
55
+ "pending" => "Pending Review",
56
+ "accepted" => "Accepted",
57
+ "waitlist" => "Waitlisted",
58
+ "denied" => "Denied",
59
+ "late_waitlist" => "Waitlisted, Late",
60
+ "rsvp_confirmed" => "RSVP Confirmed",
61
+ "rsvp_denied" => "RSVP Denied"
62
+ }.freeze
63
+
64
+ validates_inclusion_of :experience, in: POSSIBLE_EXPERIENCES
65
+ validates_inclusion_of :interest, in: POSSIBLE_INTERESTS
66
+ # validates_inclusion_of :school_id, :in => School.select(:id)
67
+ validates_inclusion_of :shirt_size, in: POSSIBLE_SHIRT_SIZES
68
+ validates_inclusion_of :acc_status, in: POSSIBLE_ACC_STATUS
69
+
70
+ belongs_to :user
71
+
72
+ def email
73
+ user.email
74
+ end
75
+
76
+ def portfolio_url=(value)
77
+ value = "http://" + value if !value.blank? && !value.include?("http://") && !value.include?("https://")
78
+ super value
79
+ end
80
+
81
+ def vcs_url=(value)
82
+ value = "http://" + value if !value.blank? && !value.include?("http://") && !value.include?("https://")
83
+ super value
84
+ end
85
+
86
+ def school
87
+ School.find(school_id) if school_id
88
+ end
89
+
90
+ def full_name
91
+ "#{first_name} #{last_name}"
92
+ end
93
+
94
+ def full_location
95
+ "#{school.city}, #{school.state}"
96
+ end
97
+
98
+ def date_of_birth_formatted
99
+ date_of_birth.strftime("%B %-d, %Y")
100
+ end
101
+
102
+ def acc_status_author
103
+ return unless acc_status_author_id.present?
104
+ User.find(acc_status_author_id)
105
+ end
106
+
107
+ def checked_in?
108
+ checked_in_at.present?
109
+ end
110
+
111
+ def checked_in_by
112
+ return unless checked_in_by_id.present?
113
+ User.find(checked_in_by_id)
114
+ end
115
+
116
+ def fips_code
117
+ Fips.where(city: school.city, state: school.state).first
118
+ end
119
+
120
+ def can_rsvp?
121
+ ["accepted", "rsvp_confirmed", "rsvp_denied"].include? acc_status
122
+ end
123
+
124
+ def did_rsvp?
125
+ ['rsvp_confirmed', 'rsvp_denied'].include? acc_status
126
+ end
127
+
128
+ def eligible_for_a_bus?
129
+ school.present? && school.bus_list_id?
130
+ end
131
+
132
+ def bus_list
133
+ return unless eligible_for_a_bus?
134
+ school.bus_list
135
+ end
136
+
137
+ def message_events
138
+ return [] unless ENV['SPARKPOST_API_KEY']
139
+
140
+ simple_spark = SimpleSpark::Client.new
141
+ simple_spark.message_events.search(recipients: email)
142
+ end
143
+
144
+ def invite_to_slack
145
+ SlackInviteWorker.perform_async(id)
146
+ end
147
+
148
+ private
149
+
150
+ def consolidate_school_names
151
+ return if school.blank?
152
+ duplicate = SchoolNameDuplicate.find_by(name: school.name)
153
+ return if duplicate.blank?
154
+ self.school_id = duplicate.school_id
155
+ end
156
+
157
+ def update_school_questionnaire_count
158
+ if destroyed?
159
+ School.decrement_counter(:questionnaire_count, school_id)
160
+ elsif saved_change_to_school_id?
161
+ old_school_id = saved_changes['school_id'].first
162
+ School.decrement_counter(:questionnaire_count, old_school_id) if old_school_id.present?
163
+ School.increment_counter(:questionnaire_count, school_id)
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,53 @@
1
+ require 'httparty'
2
+ SHEETS_KEY = ENV['GOOGLESHEETS_KEY']
3
+ SHEETS_URL = "https://sheets.googleapis.com/v4/spreadsheets/".freeze
4
+ SHEETS_FIELDS = "fields=sheets(data.rowData.values.userEnteredValue)".freeze
5
+ SECTION = ":section".freeze
6
+ ITEM = ":item".freeze
7
+
8
+ class Schedule
9
+ def initialize(spreadsheet_id, sheet = 0)
10
+ cache_key = "schedule/#{spreadsheet_id}"
11
+ parsed_response = Rails.cache.fetch(cache_key, expires_in: 1.hour) do
12
+ response = HTTParty.get(SHEETS_URL + "#{spreadsheet_id}?#{SHEETS_FIELDS}&key=#{SHEETS_KEY}")
13
+ response ? response.parsed_response.to_hash : nil
14
+ end
15
+
16
+ unless parsed_response && parsed_response["error"].nil?
17
+ Rails.logger.error "Error reading Google Sheet #{spreadsheet_id}"
18
+ return
19
+ end
20
+
21
+ @sheet = parsed_response["sheets"][sheet]
22
+ end
23
+
24
+ def rows
25
+ @sheet ? @sheet["data"][0]["rowData"] : []
26
+ end
27
+
28
+ def sections
29
+ section = []
30
+ sections = []
31
+ rows.each do |row|
32
+ if row["values"][0]["userEnteredValue"]["stringValue"] == SECTION
33
+ sections << section unless section.count.zero?
34
+ section = [row["values"][1]["userEnteredValue"]["stringValue"]]
35
+ else
36
+ fill_section(section, row)
37
+ end
38
+ end
39
+ sections << section unless section.empty?
40
+ sections
41
+ end
42
+
43
+ private
44
+
45
+ def fill_section(section, row)
46
+ r = []
47
+ row["values"].map do |col|
48
+ next if !col.empty? && col["userEnteredValue"]["stringValue"] == ITEM
49
+ r << (col.empty? ? '' : col["userEnteredValue"]["stringValue"])
50
+ end
51
+ section << r unless r.count.zero?
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ class School < ApplicationRecord
2
+ validates_presence_of :name
3
+
4
+ validates_uniqueness_of :name
5
+
6
+ strip_attributes
7
+
8
+ has_many :questionnaires
9
+ belongs_to :bus_list, optional: true
10
+
11
+ def full_name
12
+ out = ""
13
+ out << name
14
+ if city.present? || state.present?
15
+ out << " in "
16
+ out << city if city.present?
17
+ out << ", " if city.present? && state.present?
18
+ out << state if state.present?
19
+ end
20
+ out
21
+ end
22
+
23
+ def bus_list
24
+ return unless bus_list_id
25
+ BusList.find(bus_list_id)
26
+ end
27
+
28
+ def fips_code
29
+ Fips.where(city: city, state: state).first
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ class SchoolNameDuplicate < ApplicationRecord
2
+ validates_uniqueness_of :name
3
+
4
+ strip_attributes
5
+
6
+ belongs_to :school
7
+ end
@@ -0,0 +1,52 @@
1
+ class User < ApplicationRecord
2
+ devise :database_authenticatable, :registerable,
3
+ :recoverable, :rememberable, :trackable, :validatable,
4
+ :omniauthable, omniauth_providers: [:mlh]
5
+
6
+ has_one :questionnaire
7
+
8
+ def active_for_authentication?
9
+ true
10
+ end
11
+
12
+ def send_devise_notification(notification, *args)
13
+ devise_mailer.send(notification, self, *args).deliver_later
14
+ end
15
+
16
+ def queue_reminder_email
17
+ return if reminder_sent_at
18
+ Mailer.delay_for(1.day).incomplete_reminder_email(id)
19
+ update_attribute(:reminder_sent_at, Time.now)
20
+ end
21
+
22
+ def email=(value)
23
+ super value.try(:downcase)
24
+ end
25
+
26
+ def first_name
27
+ return "" if questionnaire.blank?
28
+ questionnaire.first_name
29
+ end
30
+
31
+ def last_name
32
+ return "" if questionnaire.blank?
33
+ questionnaire.last_name
34
+ end
35
+
36
+ def full_name
37
+ return "" if questionnaire.blank?
38
+ questionnaire.full_name
39
+ end
40
+
41
+ def self.from_omniauth(auth)
42
+ where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
43
+ user.uid = auth.uid
44
+ user.email = auth.info.email
45
+ user.password = Devise.friendly_token[0, 20]
46
+ end
47
+ end
48
+
49
+ def self.without_questionnaire
50
+ User.left_outer_joins(:questionnaire).where(questionnaires: { id: nil }, admin: false)
51
+ end
52
+ end
@@ -0,0 +1,20 @@
1
+ %fieldset
2
+ %legend Bus Captians
3
+ - if bus_list.captains.empty?
4
+ %p
5
+ %em TBD
6
+ - bus_list.captains.each do |p|
7
+ %p
8
+ %strong= p.full_name
9
+ %br
10
+ %em= p.school.name
11
+ %br
12
+ Phone:
13
+ = p.phone
14
+ %br
15
+ Email:
16
+ = p.email
17
+
18
+ %fieldset
19
+ %legend Bus Notes
20
+ = bus_list.notes.present? ? markdown(bus_list.notes.html_safe) : "<p>(none)</p>".html_safe
@@ -0,0 +1,9 @@
1
+ %p
2
+ - accepted = Questionnaire.joins(:school).where("schools.bus_list_id = '#{bus_list.id}' AND acc_status = 'accepted'").count
3
+ = pluralize(accepted, 'person has', 'people have')
4
+ been accepted but not yet RSVP'd.
5
+
6
+ %p
7
+ - accepted = Questionnaire.joins(:school).where("schools.bus_list_id = '#{bus_list.id}' AND acc_status = 'rsvp_confirmed' AND riding_bus = false").count
8
+ = pluralize(accepted, 'person has', 'people have')
9
+ RSVP'd as attending but didn't sign up for the bus.
@@ -0,0 +1,54 @@
1
+ %p
2
+ %b Experience:
3
+ = Questionnaire::POSSIBLE_EXPERIENCES[@questionnaire.experience]
4
+ %p
5
+ %b Portfolio link:
6
+ = @questionnaire.portfolio_url? ? link_to(@questionnaire.portfolio_url, @questionnaire.portfolio_url, target: '_blank') : 'Not provided'
7
+ %p
8
+ %b GitHub/BitBucket link:
9
+ = @questionnaire.vcs_url? ? link_to(@questionnaire.vcs_url, @questionnaire.vcs_url, target: '_blank') : 'Not provided'
10
+ %p
11
+ %b Resume:
12
+ = @questionnaire.resume? ? link_to("Download &raquo;".html_safe, @questionnaire.resume.url) : 'Not provided'
13
+ %p
14
+ %b Traveling from:
15
+ = @questionnaire.travel_not_from_school ? "Somewhere else (#{@questionnaire.travel_location})" : "My school (#{@questionnaire.school.full_name})"
16
+
17
+ %fieldset
18
+ %legend Provided by My MLH
19
+ %p
20
+ %b First name:
21
+ = @questionnaire.first_name
22
+ %p
23
+ %b Last name:
24
+ = @questionnaire.last_name
25
+ %p
26
+ %b Email:
27
+ = @questionnaire.email
28
+ %p
29
+ %b Phone:
30
+ = @questionnaire.phone
31
+ %p
32
+ %b Date of birth:
33
+ = @questionnaire.date_of_birth_formatted
34
+ %p
35
+ %b Gender:
36
+ = @questionnaire.gender
37
+ %p
38
+ %b School:
39
+ = @questionnaire.school.full_name
40
+ %p
41
+ %b Major:
42
+ = @questionnaire.major
43
+ %p
44
+ %b Level of study:
45
+ = @questionnaire.level_of_study
46
+ %p
47
+ %b Shirt size:
48
+ = @questionnaire.shirt_size
49
+ %p
50
+ %b Dietary restrictions
51
+ = @questionnaire.dietary_restrictions || "<i>(none)</i>".html_safe
52
+ %p
53
+ %b Special needs
54
+ = @questionnaire.special_needs || "<i>(none)</i>".html_safe
@@ -0,0 +1,45 @@
1
+ %section.section{ style: "padding-left: 20px; padding-right: 20px" }
2
+ %h1.section-title= title "Bus List"
3
+ %p#notice= notice
4
+
5
+ %p Thank you for being a bus captain! Below is any information you may need about your passengers.
6
+
7
+ %ul
8
+ %li Only students on this list may board the bus. <strong>No exceptions</strong>- this is to ensure everyone goes through the application process & has signed RIT's waivers.
9
+ %li If a student was accepted but didn't RSVP or sign up for the bus, they can go to <strong>https://brickhack.io/rsvp</strong> to do so.
10
+ %li If any emergencies arise, call our travel director, <strong>Velizar Demirev</strong>, at <strong>(413) 221-2420</strong>.
11
+ %li
12
+ If you have any other questions, please feel free to email
13
+ = link_to "travel@codeRIT.org", "mailto:travel@codeRIT.org"
14
+ !
15
+
16
+ %p
17
+ %b Bus List Name:
18
+ = @bus_list.name
19
+
20
+ = render partial: 'bus_list_info', locals: { bus_list: @bus_list }
21
+
22
+ %p
23
+ %strong Passengers:
24
+ = "(#{@bus_list.passengers.count} total, #{@bus_list.checked_in_passengers.count} checked in)"
25
+
26
+ %table.table
27
+ %thead
28
+ %tr
29
+ %th First Name
30
+ %th Last Name
31
+ %th Email
32
+ %th Phone Number
33
+ %th School
34
+ %th Checked in?
35
+ %tbody
36
+ - @bus_list.passengers.each do |p|
37
+ %tr
38
+ %td= p.first_name
39
+ %td= p.last_name
40
+ %td= p.email
41
+ %td= phone_link_to p.phone
42
+ %td= p.school.name
43
+ %td= p.checked_in? ? '<span class="acc-status-accepted">Yes</span>'.html_safe : 'No'
44
+
45
+ = render partial: 'bus_list_stats', locals: { bus_list: @bus_list }
@@ -0,0 +1,9 @@
1
+ %div{class:'form-container'}
2
+ = simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
3
+ = f.error_notification
4
+ .form-inputs
5
+ = f.input :email, required: true, autofocus: true
6
+ .center
7
+ .form-actions
8
+ = f.button :submit, "Send Reset Instructions"
9
+ = render "devise/shared/links"
@@ -0,0 +1,14 @@
1
+ %section{class:'section'}
2
+ %div{class:'container'}
3
+ %h1{class:'section-title'} Change your password
4
+ %div{class:'form-container'}
5
+ = simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|
6
+ = f.error_notification
7
+ = f.input :reset_password_token, as: :hidden
8
+ = f.full_error :reset_password_token
9
+ .form-inputs
10
+ = f.input :password, label: "New Password", required: true, autofocus: true
11
+ = f.input :password_confirmation, label: "Confirm", required: true
12
+ .form-actions
13
+ = f.button :submit, "Change My Password"
14
+ = render "devise/shared/links"
@@ -0,0 +1,5 @@
1
+ %section{class:'section'}
2
+ %div{class:'container'}
3
+ %h1{class:'section-title'} Password Reset
4
+
5
+ = render 'form'
@@ -0,0 +1,8 @@
1
+ = simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
2
+ .form-actions
3
+ .center
4
+ = btn_link_to "Sign Up with My MLH &raquo;".html_safe, user_mlh_omniauth_authorize_path
5
+ %p.center
6
+ Already applied?
7
+ %br
8
+ = btn_link_to "Sign In &raquo;".html_safe, user_mlh_omniauth_authorize_path
@@ -0,0 +1,20 @@
1
+ %section.section
2
+ .container
3
+ %h1.section-title Edit Account
4
+ .form-container
5
+ = simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f|
6
+ = f.error_notification
7
+ .form-inputs
8
+ = f.input :email, required: true, autofocus: true
9
+ - if devise_mapping.confirmable? && resource.pending_reconfirmation?
10
+ %p
11
+ Currently waiting confirmation for: #{resource.unconfirmed_email}
12
+ = f.input :password, autocomplete: "off", hint: "leave blank if you don't want to change it", required: false
13
+ = f.input :password_confirmation, required: false
14
+ = f.input :current_password, required: true
15
+ .form-actions
16
+ = f.button :submit, "Update"
17
+ .form-container
18
+ %p
19
+ Unhappy? #{link_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure? Your account and application will be permanently erased." }, method: :delete}
20
+ = link_to "Back", :back
@@ -0,0 +1,18 @@
1
+ %section.section
2
+ .container
3
+ .form-container.signup
4
+ %h1.section-title Sign Up or Sign In
5
+
6
+ #disclaimer
7
+ - unless Rails.configuration.hackathon['registration_is_open']
8
+ .center
9
+ %strong Registration is now closed. Thanks to everyone who applied!
10
+ %br
11
+ %br
12
+ Registration is simplified with #{link_to "My MLH", "https://my.mlh.io", style: "color: #f5f5f5; text-decoration: underline;"}! Click below to sign into your existing My MLH account, or create one. You'll be redirected back to BrickHack to finish your application afterwards.
13
+ %ul
14
+ %li Applicants must be 18 years of age by February 11th
15
+ %li RIT students must still apply
16
+ %li International applicants are welcome
17
+
18
+ = render 'form'
@@ -0,0 +1,8 @@
1
+ .form-actions
2
+ .center
3
+ %p
4
+ = btn_link_to "Sign In with My MLH &raquo;".html_safe, user_mlh_omniauth_authorize_path
5
+ %p
6
+ Need an account?
7
+ %br
8
+ = btn_link_to "Sign Up &raquo;".html_safe, new_user_registration_path
@@ -0,0 +1,9 @@
1
+ .section
2
+ .container
3
+ .form-container.login
4
+ %h1.section-title Log In
5
+ - if notice
6
+ .form-success
7
+ .success_message
8
+ %p#notice= notice
9
+ = render 'form'
@@ -0,0 +1 @@
1
+ %link{ href:'//fonts.googleapis.com/css?family=Open+Sans:300,400,600', rel: 'stylesheet', type: 'text/css' }
@@ -0,0 +1,22 @@
1
+ %div{ class:"sidebar #{controller.controller_name}" }
2
+ %span#sidebar-toggle
3
+ %i.fa.fa-navicon
4
+ .pusher
5
+ - if Rails.configuration.hackathon['logo_asset']
6
+ #logo-cta
7
+ = link_to root_path do
8
+ = image_tag Rails.configuration.hackathon['logo_asset'], id: "logo", alt: "BrickHack", title: "BrickHack"
9
+ - if user_signed_in?
10
+ %div
11
+ - if current_user.admin?
12
+ = btn_link_to "Manage", manage_root_path
13
+ - else
14
+ = btn_link_to "Review", new_questionnaires_path
15
+ - else
16
+ %div
17
+ = btn_link_to "Login", new_user_session_path
18
+ %div
19
+ = btn_link_to "Register", new_user_registration_path
20
+ - if user_signed_in?
21
+ %div
22
+ = btn_link_to "Sign Out", destroy_user_session_path, method: :delete
@@ -0,0 +1,12 @@
1
+ !!! 5
2
+ %html
3
+ %head
4
+ %title BrickHack 3 - Feb 11-12, 2017
5
+ = render "layouts/shared_head"
6
+ = stylesheet_link_tag "application", :media => "all"
7
+ = csrf_meta_tags
8
+
9
+ %body
10
+ = yield
11
+ = javascript_include_tag "application"
12
+ = render "layouts/shared_footer"
@@ -0,0 +1,12 @@
1
+ !!! 5
2
+ %html
3
+ %head
4
+ %title BrickHack
5
+ = render "layouts/shared_head"
6
+ = stylesheet_link_tag "application", :media => "all"
7
+ = csrf_meta_tags
8
+ %body
9
+ %div{class:'day-of'}
10
+ = yield
11
+ = javascript_include_tag "application"
12
+ = javascript_include_tag "vendor/owl.carousel.min.js"
@@ -0,0 +1,12 @@
1
+ !!! 5
2
+ %html
3
+ %head
4
+ %title= yield(:title) || "BrickHack 3 - Feb 11-12, 2017"
5
+ = stylesheet_link_tag "hackathon_manager/manage", media: "all"
6
+ = csrf_meta_tags
7
+
8
+ %body
9
+ = render "layouts/sidebar"
10
+ #main
11
+ = yield
12
+ = javascript_include_tag "hackathon_manager/manage/application"
@@ -0,0 +1,51 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml"><head>
3
+ <title></title>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <style type="text/css">
6
+ <%= Rails.env == "production" ? File.read(Rails.root.join("public" + ActionController::Base.helpers.asset_path("mailer.css"))).html_safe : Rails.application.assets["mailer"].to_s.html_safe %>
7
+ </style>
8
+ <meta name="robots" content="noindex,nofollow">
9
+ </head>
10
+
11
+
12
+ <body>
13
+ <div id="content">
14
+ <!--head-->
15
+ <%= image_tag 'email_banner.jpg', class: 'banner' %>
16
+
17
+ <!--content-->
18
+ <div id="main-content">
19
+ <%= yield %>
20
+ </div>
21
+
22
+ <!--footer-->
23
+ <div class="email-footer">
24
+ <table border="0" >
25
+ <tr>
26
+ <td>
27
+ <span>
28
+ <%= link_to 'BrickHack', 'https://brickhack.io' %>
29
+ </span>
30
+ <span>
31
+ <%= link_to 'Facebook', 'https://www.facebook.com/brickhackrit' %>
32
+ </span>
33
+ <span>
34
+ <%= link_to 'Twitter', 'https://twitter.com/brickhackrit' %>
35
+ </span>
36
+ </td>
37
+ <td>
38
+ <span>
39
+ <%= link_to 'http://coderit.org', class: 'nodecor' do %>
40
+ Student run by <img class="coderit-logo" src="<%= image_url('coderit_logo.png') %>" />
41
+ <% end %>
42
+ </span>
43
+ </td>
44
+ </tr>
45
+ </table>
46
+ </div>
47
+ </div>
48
+
49
+ </body>
50
+
51
+ </html>