hackathon_manager 0.7.1 → 0.8.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.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/app/assets/javascripts/hackathon_manager/manage/application.js +1 -0
- data/app/assets/javascripts/hackathon_manager/manage/lib/datatables.js +1 -0
- data/app/assets/javascripts/hackathon_manager/manage/lib/debounce.js +19 -0
- data/app/assets/javascripts/hackathon_manager/manage/lib/forms.js +34 -0
- data/app/assets/javascripts/hackathon_manager/manage/lib/messageLivePreview.js +16 -0
- data/app/assets/javascripts/hackathon_manager/manage/lib/setupDataTables.js +10 -12
- data/app/assets/stylesheets/hackathon_manager/dashboard.css +6 -0
- data/app/controllers/manage/application_controller.rb +1 -1
- data/app/controllers/manage/messages_controller.rb +13 -2
- data/app/controllers/manage/questionnaires_controller.rb +0 -4
- data/app/controllers/questionnaires_controller.rb +0 -1
- data/app/controllers/rsvps_controller.rb +0 -5
- data/app/datatables/{message_datatable.rb → bulk_message_datatable.rb} +6 -4
- data/app/datatables/questionnaire_datatable.rb +6 -2
- data/app/mailers/mail_preview.rb +0 -17
- data/app/mailers/mailer.rb +2 -26
- data/app/models/message.rb +25 -1
- data/app/views/application/_triggered_email_summary.html.haml +14 -7
- data/app/views/layouts/manage/application.html.haml +4 -4
- data/app/views/mailer/bulk_templates/_default.html.erb +379 -1
- data/app/views/manage/bus_lists/index.html.haml +2 -2
- data/app/views/manage/configs/show.html.haml +2 -2
- data/app/views/manage/dashboard/map_data.tsv.erb +7 -0
- data/app/views/manage/messages/_form.html.haml +13 -4
- data/app/views/manage/messages/index.html.haml +5 -4
- data/app/views/manage/messages/show.html.haml +24 -24
- data/app/views/manage/questionnaires/_overview.html.haml +12 -2
- data/app/views/manage/questionnaires/index.html.haml +3 -1
- data/config/locales/en.yml +4 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20180801144544_add_type_to_messages.rb +17 -0
- data/{app/views/mailer/accepted_email.html.erb → db/seed_messages/questionnaire--accepted.md} +4 -2
- data/db/seed_messages/questionnaire--denied.md +16 -0
- data/db/seed_messages/questionnaire--pending.md +13 -0
- data/db/seed_messages/questionnaire--rsvp_confirmed.md +9 -0
- data/db/seeds.rb +41 -0
- data/lib/hackathon_manager.rb +2 -2
- data/lib/hackathon_manager/engine.rb +1 -1
- data/lib/hackathon_manager/version.rb +1 -1
- data/test/factories/bus_list.rb +2 -2
- data/test/factories/fips.rb +3 -3
- data/test/factories/message.rb +7 -6
- data/test/factories/questionnaire.rb +18 -18
- data/test/factories/school.rb +4 -4
- data/test/factories/users.rb +5 -5
- metadata +11 -7
- data/app/views/mailer/application_confirmation_email.html.erb +0 -10
- data/app/views/mailer/denied_email.html.erb +0 -11
- data/app/views/mailer/rsvp_confirmation_email.html.erb +0 -5
@@ -1,7 +1,7 @@
|
|
1
1
|
= render "layouts/manage/page_title", title: "Hackathon Configuration"
|
2
2
|
|
3
3
|
.row
|
4
|
-
.col-lg-6
|
4
|
+
.col-lg-6.mb-3
|
5
5
|
.card
|
6
6
|
.card-body
|
7
7
|
%h5.card-title Hackathon Manager Config
|
@@ -15,7 +15,7 @@
|
|
15
15
|
%b #{key}:
|
16
16
|
%pre= Rails.configuration.hackathon[key]
|
17
17
|
|
18
|
-
.col-lg-6
|
18
|
+
.col-lg-6.mb-3
|
19
19
|
.card
|
20
20
|
.card-body
|
21
21
|
%h5.card-title Environment Variables
|
@@ -3,6 +3,8 @@
|
|
3
3
|
<%
|
4
4
|
counties = {}
|
5
5
|
amount = 1
|
6
|
+
redo_count = 0
|
7
|
+
redo_limit = 10
|
6
8
|
@schools.each do |school|
|
7
9
|
if school.fips_code.blank?
|
8
10
|
next if school.city.blank? || school.state.blank?
|
@@ -10,8 +12,13 @@ amount = 1
|
|
10
12
|
resp = HTTParty.get("https://maps.googleapis.com/maps/api/geocode/json?address=#{CGI.escape(school.city)}+#{CGI.escape(school.state)}&sensor=true")
|
11
13
|
results = resp.parsed_response["results"][0]
|
12
14
|
if results.blank?
|
15
|
+
if redo_count >= redo_limit
|
16
|
+
raise 'Exceeded maximum number of retries: No results from Google Maps API.'
|
17
|
+
end
|
18
|
+
redo_count += 1
|
13
19
|
redo
|
14
20
|
end
|
21
|
+
redo_count = 0
|
15
22
|
|
16
23
|
lat = results["geometry"]["location"]["lat"]
|
17
24
|
lng = results["geometry"]["location"]["lng"]
|
@@ -3,15 +3,24 @@
|
|
3
3
|
= f.error_notification
|
4
4
|
|
5
5
|
.form-inputs
|
6
|
+
= f.input :type, as: :select, collection: Message::POSSIBLE_TYPES.map { |x| [x.titleize, x] }, include_blank: false
|
7
|
+
= f.input :trigger, as: :select, collection: Message::POSSIBLE_TRIGGERS.invert, include_blank: "(disabled)"
|
6
8
|
= f.input :name
|
7
9
|
= f.input :subject, hint: "All emails are from <pre class=\"d-inline\">#{html_escape(Rails.configuration.hackathon['email_from'])}</pre>".html_safe
|
8
10
|
= f.input :template, as: :select, collection: Message::POSSIBLE_TEMPLATES.map { |x| [x.titleize, x] }, include_blank: false
|
9
11
|
- if @message.status == "drafted"
|
10
|
-
= f.input :recipients, as: :select, collection: @message.possible_recipients, input_html: { class: "selectize", multiple: true, },
|
12
|
+
= f.input :recipients, as: :select, collection: @message.possible_recipients, input_html: { class: "selectize", multiple: true, }, placeholder: "Type to search by school or type..."
|
11
13
|
- else
|
12
14
|
= f.input :recipients, as: :select, collection: @message.possible_recipients, input_html: { class: "selectize", multiple: true }, hint: "Cannot be edited once a message has been delivered", disabled: true
|
13
|
-
|
14
|
-
= f.input :body, input_html: { rows: 10 }, hint: "Supports markdown and HTML"
|
15
|
+
%br
|
15
16
|
|
16
|
-
.
|
17
|
+
.row
|
18
|
+
.col-lg-6.mb-3
|
19
|
+
%h5.mb-3 Body
|
20
|
+
= f.input :body, input_html: { rows: 23, 'data-message-live-preview' => 'textarea', class: 'text-monospace', style: 'font-size: 14px' }, hint: "Supports markdown and HTML", label: false, wrapper: :bootstrap_inline_form
|
21
|
+
.col-lg-6.mb-3
|
22
|
+
%h5.mb-3 Preview
|
23
|
+
%iframe.email-preview{src: live_preview_manage_messages_path(body: @message.body), 'data-message-live-preview' => 'iframe', 'data-message-live-preview-base-src' => live_preview_manage_messages_path}
|
24
|
+
|
25
|
+
.form-actions.mb-3
|
17
26
|
= f.button :submit, class: 'btn-primary'
|
@@ -2,15 +2,16 @@
|
|
2
2
|
= link_to "New Message", new_manage_message_path, class: "btn btn-sm btn-outline-secondary"
|
3
3
|
|
4
4
|
%div
|
5
|
-
%table.messages.datatable.table.table-striped.table-hover{ "data-source" => datatable_manage_messages_path(format: :json) }
|
5
|
+
%table.bulk-messages.datatable.table.table-striped.table-hover{ "data-source" => datatable_manage_messages_path(format: :json) }
|
6
6
|
%thead
|
7
7
|
%tr
|
8
8
|
%th ID
|
9
9
|
%th Name
|
10
10
|
%th Subject
|
11
|
-
%th
|
12
|
-
%th
|
13
|
-
%th
|
11
|
+
%th Status
|
12
|
+
%th Created
|
13
|
+
%th Last modified
|
14
|
+
%th Delivered
|
14
15
|
%tbody
|
15
16
|
|
16
17
|
%hr
|
@@ -28,29 +28,29 @@
|
|
28
28
|
%dt.col-md-3 Template
|
29
29
|
%dd.col-md-9= @message.template.titleize
|
30
30
|
.col-lg-6
|
31
|
-
|
32
|
-
%
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
31
|
+
- if @message.bulk?
|
32
|
+
%p.mb-1
|
33
|
+
%b Recipients
|
34
|
+
%ul.pl-4.mb-1
|
35
|
+
- @message.recipients_list.each do |recipient|
|
36
|
+
%li= recipient
|
37
|
+
- if @message.recipients.blank?
|
38
|
+
%p.text-muted (none)
|
39
|
+
- if @message.recipients.present?
|
40
|
+
%p.small
|
41
|
+
- if recipient_error.present?
|
42
|
+
%strong{style: 'color: red;'} Error parsing recipients:
|
43
|
+
= recipient_error
|
44
|
+
%br To resolve this, edit & remove the offending recipient.
|
45
|
+
- else
|
46
|
+
%em #{recipient_count} currently match this query
|
47
|
+
- if @message.automated?
|
48
|
+
%p.mb-1
|
49
|
+
%b Trigger
|
50
|
+
%small
|
51
|
+
%em Sent automatically to an applicant upon meeting this criteria
|
52
|
+
%p
|
53
|
+
= Message::POSSIBLE_TRIGGERS[@message.trigger] || "<span class=\"text-muted\">(disabled)</span>".html_safe
|
54
54
|
|
55
55
|
%div
|
56
56
|
%p
|
@@ -61,7 +61,7 @@
|
|
61
61
|
|
62
62
|
%iframe.email-preview{src: preview_manage_message_path(@message)}
|
63
63
|
|
64
|
-
- if @message.
|
64
|
+
- if @message.bulk?
|
65
65
|
.card.mt-3.mb-3
|
66
66
|
.card-body
|
67
67
|
%h5.card-title Bulk delivery details
|
@@ -82,9 +82,19 @@
|
|
82
82
|
.card-body
|
83
83
|
.row
|
84
84
|
%dt.col-md-4 Dietary restrictions
|
85
|
-
%dd.col-md-8
|
85
|
+
%dd.col-md-8
|
86
|
+
- if @questionnaire.dietary_restrictions.present?
|
87
|
+
%span.fa.fa-exclamation-triangle.text-warning.icon-space-r-half
|
88
|
+
= @questionnaire.dietary_restrictions
|
89
|
+
- else
|
90
|
+
%span.text-muted (none)
|
86
91
|
%dt.col-md-4 Special needs
|
87
|
-
%dd.col-md-8
|
92
|
+
%dd.col-md-8
|
93
|
+
- if @questionnaire.special_needs.present?
|
94
|
+
%span.fa.fa-exclamation-triangle.text-warning.icon-space-r-half
|
95
|
+
= @questionnaire.special_needs
|
96
|
+
- else
|
97
|
+
%span.text-muted (none)
|
88
98
|
%dt.col-md-4 Traveling from
|
89
99
|
%dd.col-md-8
|
90
100
|
= @questionnaire.travel_not_from_school ? "Somewhere else (#{@questionnaire.travel_location})" : "<span class=\"text-muted\">My school</span>".html_safe
|
data/config/locales/en.yml
CHANGED
@@ -40,6 +40,10 @@ en:
|
|
40
40
|
notes: Notes are shared with applicants. Supports Markdown and HTML.
|
41
41
|
user:
|
42
42
|
admin_limited_access: Limited access prevents the admin from adding, modifying, or deleting any records. Modifications through the check-in process are allowed.
|
43
|
+
message:
|
44
|
+
type: Bulk emails are sent once, manually. Automated emails are sent upon a desired trigger/event.
|
45
|
+
name: A friendly name to recognize this email. Applicants won't see this.
|
46
|
+
trigger: Sent automatically when a new or updated applicant matches this criteria. Does not send to anyone already matching this criteria.
|
43
47
|
placeholders:
|
44
48
|
bus_list:
|
45
49
|
notes: |
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
class AddTypeToMessages < ActiveRecord::Migration[5.1]
|
2
|
+
def up
|
3
|
+
add_column :messages, :type, :string
|
4
|
+
|
5
|
+
Message.all.each do |message|
|
6
|
+
if message.trigger.present?
|
7
|
+
message.update_attribute(:type, 'automated')
|
8
|
+
else
|
9
|
+
message.update_attribute(:type, 'bulk')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def down
|
15
|
+
remove_column :messages, :type, :string
|
16
|
+
end
|
17
|
+
end
|
data/{app/views/mailer/accepted_email.html.erb → db/seed_messages/questionnaire--accepted.md}
RENAMED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
## Congratulations <%= @questionnaire.first_name %>, you're in!
|
2
|
+
|
3
|
+
You have been accepted to attend <%= Rails.configuration.hackathon['name'] %>! **Please RSVP:**
|
4
|
+
|
3
5
|
<p>
|
4
6
|
<a href="https://brickhack.io/rsvp/accept" class="button" target="_blank">Yes, I will Attend »</a>
|
5
7
|
<a href="https://brickhack.io/rsvp/deny" class="button" target="_blank">No, I Can't Attend »</a>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<!--
|
2
|
+
|
3
|
+
IMPLEMENT THIS!
|
4
|
+
|
5
|
+
You'll probably want something along the lines of:
|
6
|
+
|
7
|
+
### Dear @questionnaire.first_name,
|
8
|
+
|
9
|
+
It is with our sincerest regret to inform you that our admissions committee has chosen to not accept your application to BrickHack at this time. We were overjoyed with the number of applicants we received, but unfortunately we can not accept everyone due to capacity for only 400.
|
10
|
+
|
11
|
+
We invite you to apply again next year. There are plenty of other hackathons this season, and it may not be too late to apply for those. Checkout <a href="https://mlh.io" target="_blank">https://mlh.io</a> to find out more information.
|
12
|
+
|
13
|
+
Thank you for applying,<br>
|
14
|
+
- The BrickHack Team
|
15
|
+
|
16
|
+
-->
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<h2 class="center">
|
2
|
+
Thanks for Applying!
|
3
|
+
</h2>
|
4
|
+
|
5
|
+
Hey <%= @questionnaire.first_name %>,
|
6
|
+
|
7
|
+
We've received your application to <%= Rails.configuration.hackathon['name'] %>!
|
8
|
+
|
9
|
+
If needed, you can edit your information by clicking the button below.
|
10
|
+
|
11
|
+
<%= link_to questionnaires_url, class: 'button' do %>
|
12
|
+
My Profile
|
13
|
+
<% end %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
## You are confirmed!
|
2
|
+
|
3
|
+
This is your confirmation for <%= Rails.configuration.hackathon['name'] %>! We can't wait to see you there. In the meantime, follow us on [Facebook](https://www.facebook.com/brickhackrit) and [Twitter](https://twitter.com/brickhackrit) to get news and updates.
|
4
|
+
|
5
|
+
**If you can no longer attend, please let us know so we can open the spot to someone else. [I Can No Longer Attend »](https://brickhack.io/rsvp/deny)**
|
6
|
+
|
7
|
+
### Meet Other Hackers
|
8
|
+
|
9
|
+
Join our [Facebook Group](https://www.facebook.com/groups/brickhack3attendees/) to get in touch with other attendees. This will be the best way to find teammates if you don't have a team already!
|
data/db/seeds.rb
CHANGED
@@ -8,6 +8,45 @@
|
|
8
8
|
|
9
9
|
require 'csv'
|
10
10
|
|
11
|
+
puts "Seeding messages..."
|
12
|
+
|
13
|
+
subject_mapping = {
|
14
|
+
"questionnaire.pending" => "Application Received",
|
15
|
+
"questionnaire.accepted" => "You've been accepted!",
|
16
|
+
"questionnaire.denied" => "Your application status",
|
17
|
+
"questionnaire.rsvp_confirmed" => "RSVP Confirmation"
|
18
|
+
}
|
19
|
+
|
20
|
+
name_mapping = {
|
21
|
+
"questionnaire.pending" => "Application Received",
|
22
|
+
"questionnaire.accepted" => "Accepted email",
|
23
|
+
"questionnaire.denied" => "Denied email",
|
24
|
+
"questionnaire.rsvp_confirmed" => "RSVP confirmed email"
|
25
|
+
}
|
26
|
+
|
27
|
+
path = File.join(File.dirname(__FILE__), 'seed_messages/*.md')
|
28
|
+
files = FileList.glob(path)
|
29
|
+
files.each do |filepath|
|
30
|
+
filename = File.basename(filepath)
|
31
|
+
trigger = filename.sub('.md', '').sub('--', '.')
|
32
|
+
|
33
|
+
if Message.automated.where(trigger: trigger).count >= 1
|
34
|
+
puts "Skipping seed for automated message #{trigger}: existing automated email found"
|
35
|
+
next
|
36
|
+
end
|
37
|
+
|
38
|
+
body = File.read(filepath)
|
39
|
+
Message.create(
|
40
|
+
type: 'automated',
|
41
|
+
name: name_mapping[trigger],
|
42
|
+
subject: subject_mapping[trigger],
|
43
|
+
trigger: trigger,
|
44
|
+
body: body
|
45
|
+
)
|
46
|
+
|
47
|
+
puts "Seeded automated message for #{trigger}"
|
48
|
+
end
|
49
|
+
|
11
50
|
puts "Seeding school list..."
|
12
51
|
|
13
52
|
csv_file = File.join(File.dirname(__FILE__), 'schools.csv')
|
@@ -16,3 +55,5 @@ csv = CSV.parse(csv_text, headers: true)
|
|
16
55
|
csv.each do |row|
|
17
56
|
School.create(row.to_hash)
|
18
57
|
end
|
58
|
+
|
59
|
+
puts "Done"
|
data/lib/hackathon_manager.rb
CHANGED
@@ -5,9 +5,9 @@ module HackathonManager
|
|
5
5
|
hackathon = app.config_for(:hackathon)
|
6
6
|
|
7
7
|
# Applications without a specified config.time_zone will parse
|
8
|
-
# this as a string instead of a
|
8
|
+
# this as a string instead of a Time
|
9
9
|
if hackathon['last_day_to_apply'].is_a?(String)
|
10
|
-
hackathon['last_day_to_apply'] =
|
10
|
+
hackathon['last_day_to_apply'] = Time.parse(hackathon['last_day_to_apply'])
|
11
11
|
end
|
12
12
|
|
13
13
|
app.config.hackathon = hackathon
|
@@ -33,7 +33,7 @@ module HackathonManager
|
|
33
33
|
end
|
34
34
|
|
35
35
|
initializer 'hackathon_manager.factories', after: 'factory_bot.set_factory_paths' do
|
36
|
-
FactoryBot.definition_file_paths << File.expand_path('
|
36
|
+
FactoryBot.definition_file_paths << File.expand_path('../../test/factories', __dir__) if defined?(FactoryBot)
|
37
37
|
end
|
38
38
|
|
39
39
|
ActionController::Base.class_eval do
|
data/test/factories/bus_list.rb
CHANGED
data/test/factories/fips.rb
CHANGED
data/test/factories/message.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
FactoryBot.define do
|
2
2
|
factory :message do
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
type { "bulk" }
|
4
|
+
name { "Message Name" }
|
5
|
+
subject { "Message Subject" }
|
6
|
+
recipients { ["all"] }
|
7
|
+
body { "Hello world!" }
|
8
|
+
queued_at { nil }
|
9
|
+
delivered_at { nil }
|
9
10
|
end
|
10
11
|
end
|
@@ -1,24 +1,24 @@
|
|
1
1
|
FactoryBot.define do
|
2
2
|
factory :questionnaire do
|
3
|
-
first_name "John"
|
4
|
-
last_name "Doe"
|
5
|
-
phone "(123) 456-7890"
|
6
|
-
international false
|
7
|
-
date_of_birth Date.today - 20.years
|
8
|
-
experience "first"
|
9
|
-
interest "design"
|
3
|
+
first_name { "John" }
|
4
|
+
last_name { "Doe" }
|
5
|
+
phone { "(123) 456-7890" }
|
6
|
+
international { false }
|
7
|
+
date_of_birth { Date.today - 20.years }
|
8
|
+
experience { "first" }
|
9
|
+
interest { "design" }
|
10
10
|
school_id { create(:school).id }
|
11
|
-
shirt_size "Unisex - M"
|
12
|
-
dietary_restrictions ""
|
13
|
-
special_needs ""
|
14
|
-
agreement_accepted true
|
15
|
-
code_of_conduct_accepted true
|
16
|
-
data_sharing_accepted true
|
17
|
-
can_share_info true
|
18
|
-
gender "Male"
|
19
|
-
major "Computer Science"
|
20
|
-
level_of_study "University (Undergraduate)"
|
21
|
-
why_attend "This sounds cool"
|
11
|
+
shirt_size { "Unisex - M" }
|
12
|
+
dietary_restrictions { "" }
|
13
|
+
special_needs { "" }
|
14
|
+
agreement_accepted { true }
|
15
|
+
code_of_conduct_accepted { true }
|
16
|
+
data_sharing_accepted { true }
|
17
|
+
can_share_info { true }
|
18
|
+
gender { "Male" }
|
19
|
+
major { "Computer Science" }
|
20
|
+
level_of_study { "University (Undergraduate)" }
|
21
|
+
why_attend { "This sounds cool" }
|
22
22
|
|
23
23
|
association :user
|
24
24
|
end
|