hackathon_manager 0.5.11 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/hackathon_manager/manage/lib/setupDataTables.js +1 -0
- data/app/assets/stylesheets/hackathon_manager/general/_main.sass +3 -0
- data/app/controllers/manage/messages_controller.rb +1 -1
- data/app/datatables/message_datatable.rb +2 -0
- data/app/models/message.rb +55 -20
- data/app/models/message_recipient_query.rb +61 -0
- data/app/models/questionnaire.rb +10 -0
- data/app/views/application/_triggered_email_summary.html.haml +27 -0
- data/app/views/manage/bus_lists/_form.html.haml +13 -12
- data/app/views/manage/messages/_form.html.haml +15 -13
- data/app/views/manage/messages/edit.html.haml +2 -1
- data/app/views/manage/messages/index.html.haml +8 -3
- data/app/views/manage/messages/show.html.haml +29 -16
- data/app/views/manage/questionnaires/index.html.haml +16 -5
- data/app/views/manage/questionnaires/show.html.haml +1 -1
- data/app/workers/bulk_message_worker.rb +28 -34
- data/db/migrate/20180108231420_add_trigger_to_message.rb +5 -0
- data/db/migrate/20180118035548_convert_message_recipients_to_recipient_queries.rb +36 -0
- data/lib/hackathon_manager/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b2b4e0940990bd9d79779dc11df2261481e953a
|
4
|
+
data.tar.gz: 231e89a71e42dd25ed692d41c2bf285dbee54962
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eeb9342f9cd545f46932c0330154888d8cc549f26199b19d5c96f31a47d4503ba801aadf4913d6e2908ff947841ddb39158306aa0eda9b3dca2bdb572774542a
|
7
|
+
data.tar.gz: c17ae7672d988fe083cce647d3c1e4e0edb4005961a433ab803d0d7f9af8f6adfdca2a260a7390a2b432e19a9f6b7d8d6243cc81666180c35425acd999f40bea
|
@@ -72,6 +72,7 @@ var setupDataTables = function() {
|
|
72
72
|
{ orderable: true, data: 'id'},
|
73
73
|
{ orderable: true, data: 'name'},
|
74
74
|
{ orderable: true, data: 'subject'},
|
75
|
+
{ orderable: true, data: 'trigger'},
|
75
76
|
{ orderable: false, data: 'status'},
|
76
77
|
{ orderable: true, data: 'delivered_at'}
|
77
78
|
]
|
@@ -6,6 +6,7 @@ class MessageDatatable < AjaxDatatablesRails::Base
|
|
6
6
|
id: { source: "Message.id" },
|
7
7
|
name: { source: "Message.name" },
|
8
8
|
subject: { source: "Message.subject" },
|
9
|
+
trigger: { source: "Message.trigger" },
|
9
10
|
delivered_at: { source: "Message.delivered_at", searchable: false }
|
10
11
|
}
|
11
12
|
end
|
@@ -19,6 +20,7 @@ class MessageDatatable < AjaxDatatablesRails::Base
|
|
19
20
|
id: record.id,
|
20
21
|
name: record.name,
|
21
22
|
subject: record.subject,
|
23
|
+
trigger: Message::POSSIBLE_TRIGGERS[record.trigger],
|
22
24
|
status: record.status.titleize,
|
23
25
|
delivered_at: record.delivered_at.present? ? record.delivered_at.strftime("%B %d, %Y at %I:%M %p") : ''
|
24
26
|
}
|
data/app/models/message.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
class Message < ApplicationRecord
|
2
|
-
validates_presence_of :name, :subject, :
|
2
|
+
validates_presence_of :name, :subject, :template
|
3
3
|
validates_presence_of :body, if: :using_default_template?
|
4
4
|
|
5
5
|
strip_attributes
|
6
6
|
|
7
7
|
POSSIBLE_TEMPLATES = ["default"].freeze
|
8
8
|
|
9
|
-
|
9
|
+
POSSIBLE_SIMPLE_RECIPIENTS = {
|
10
10
|
"all" => "Everyone",
|
11
11
|
"incomplete" => "Incomplete Applications",
|
12
12
|
"complete" => "Complete Applications",
|
@@ -19,23 +19,18 @@ class Message < ApplicationRecord
|
|
19
19
|
"checked-in" => "Checked-In Attendees",
|
20
20
|
"non-checked-in" => "Non-Checked-In, Accepted & RSVP'd Applications",
|
21
21
|
"non-checked-in-excluding" => "Non-Checked-In Applications, Excluding Accepted & RSVP'd",
|
22
|
-
"bus-list-cornell-bing" => "Bus List: Cornell + Binghamton (Confirmed)",
|
23
|
-
"bus-list-buffalo" => "Bus List: Buffalo (Confirmed)",
|
24
|
-
"bus-list-albany" => "Bus List: Albany (Confirmed)",
|
25
|
-
"bus-list-cornell-bing-eligible" => "Bus List: Cornell + Binghamton (eligible, not signed up)",
|
26
|
-
"bus-list-buffalo-eligible" => "Bus List: Buffalo (eligible, not signed up)",
|
27
|
-
"bus-list-albany-eligible" => "Bus List: Albany (eligible, not signed up)",
|
28
|
-
"bus-list-cornell-bing-applied" => "Bus List: Cornell + Binghamton (applied/not accepted)",
|
29
|
-
"bus-list-buffalo-applied" => "Bus List: Buffalo (applied/not accepted)",
|
30
|
-
"bus-list-albany-applied" => "Bus List: Albany (applied/not accepted)",
|
31
|
-
"school-rit" => "Confirmed or accepted: RIT",
|
32
|
-
"school-cornell" => "Confirmed or accepted: Cornell",
|
33
|
-
"school-binghamton" => "Confirmed or accepted: Binghamton",
|
34
|
-
"school-buffalo" => "Confirmed or accepted: Buffalo",
|
35
|
-
"school-waterloo" => "Confirmed or accepted: Waterloo",
|
36
|
-
"school-toronto" => "Confirmed or accepted: Toronto",
|
37
|
-
"school-umd-collegepark" => "Confirmed or accepted: UMD College Park"
|
38
22
|
}.freeze
|
23
|
+
|
24
|
+
POSSIBLE_TRIGGERS = {
|
25
|
+
"questionnaire.pending" => "Questionnaire Status: Pending Review (new application)",
|
26
|
+
"questionnaire.accepted" => "Questionnaire Status: Accepted",
|
27
|
+
"questionnaire.waitlist" => "Questionnaire Status: Waitlisted",
|
28
|
+
"questionnaire.denied" => "Questionnaire Status: Denied",
|
29
|
+
"questionnaire.late_waitlist" => "Questionnaire Status: Waitlisted, Late",
|
30
|
+
"questionnaire.rsvp_confirmed" => "Questionnaire Status: RSVP Confirmed",
|
31
|
+
"questionnaire.rsvp_denied" => "Questionnaire Status: RSVP Denied"
|
32
|
+
}.freeze
|
33
|
+
|
39
34
|
serialize :recipients, Array
|
40
35
|
|
41
36
|
validates_inclusion_of :template, in: POSSIBLE_TEMPLATES
|
@@ -45,7 +40,16 @@ class Message < ApplicationRecord
|
|
45
40
|
end
|
46
41
|
|
47
42
|
def recipients_list
|
48
|
-
recipients.map
|
43
|
+
labels = recipients.map do |r|
|
44
|
+
if POSSIBLE_SIMPLE_RECIPIENTS.include?(r)
|
45
|
+
POSSIBLE_SIMPLE_RECIPIENTS[r]
|
46
|
+
elsif r =~ /(.*)::(\d*)/
|
47
|
+
MessageRecipientQuery.friendly_name(r)
|
48
|
+
else
|
49
|
+
"(unknown)"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
labels.join(', ')
|
49
53
|
end
|
50
54
|
|
51
55
|
def delivered?
|
@@ -68,10 +72,41 @@ class Message < ApplicationRecord
|
|
68
72
|
end
|
69
73
|
|
70
74
|
def can_edit?
|
71
|
-
status == "drafted"
|
75
|
+
status == "drafted" || trigger.present?
|
72
76
|
end
|
73
77
|
|
74
78
|
def using_default_template?
|
75
79
|
template == "default"
|
76
80
|
end
|
81
|
+
|
82
|
+
def self.possible_recipients
|
83
|
+
# Produce an array like:
|
84
|
+
# ["School: My University", "school::123"]
|
85
|
+
option = ->(query, model) { [MessageRecipientQuery.friendly_name(query, model), query] }
|
86
|
+
bus_list_recipients = BusList.select(:id, :name).map do |bus_list|
|
87
|
+
[
|
88
|
+
option.call("bus-list::#{bus_list.id}", bus_list),
|
89
|
+
option.call("bus-list--eligible::#{bus_list.id}", bus_list),
|
90
|
+
option.call("bus-list--applied::#{bus_list.id}", bus_list)
|
91
|
+
]
|
92
|
+
end
|
93
|
+
bus_list_recipients.flatten!(1) # Required since we have multiple options for each bus list
|
94
|
+
|
95
|
+
school_recipients = School.select(:id, :name).map do |school|
|
96
|
+
option.call("school::#{school.id}", school)
|
97
|
+
end
|
98
|
+
# No flatten needed here since each map returns a single option
|
99
|
+
|
100
|
+
# Combine all recipients. push(*recipients) is the most efficient,
|
101
|
+
# as it doesn't create a new array each time (concat() does)
|
102
|
+
recipients = POSSIBLE_SIMPLE_RECIPIENTS.invert.to_a
|
103
|
+
recipients.push(*bus_list_recipients)
|
104
|
+
recipients.push(*school_recipients)
|
105
|
+
recipients
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.queue_for_trigger(trigger, user_id)
|
109
|
+
messages_to_queue = Message.where(trigger: trigger)
|
110
|
+
messages_to_queue.map { |message| Mailer.delay.bulk_message_email(message.id, user_id) }
|
111
|
+
end
|
77
112
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class MessageRecipientQuery
|
2
|
+
attr_accessor :query
|
3
|
+
attr_accessor :type
|
4
|
+
attr_accessor :id
|
5
|
+
attr_accessor :model
|
6
|
+
|
7
|
+
def initialize(query, type, id, model)
|
8
|
+
@query = query
|
9
|
+
@type = type
|
10
|
+
@id = id
|
11
|
+
@model = model
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.parse(query, model = nil)
|
15
|
+
# Format:
|
16
|
+
# model::ID
|
17
|
+
# model--modifier::ID
|
18
|
+
match = query.match(/(.*)::(\d*)/)
|
19
|
+
type = match[1]
|
20
|
+
id = match[2]
|
21
|
+
|
22
|
+
# Find the backing database model, ensuring the given ID exists for that model.
|
23
|
+
model_name = nil
|
24
|
+
case type
|
25
|
+
when "bus-list", "bus-list--applied", "bus-list--eligible"
|
26
|
+
model ||= BusList.find_by_id(id)
|
27
|
+
model_name = "Bus List"
|
28
|
+
when "school"
|
29
|
+
model ||= School.find_by_id(id)
|
30
|
+
model_name = "School"
|
31
|
+
else
|
32
|
+
raise "Unknown recipient query type: #{type.inspect} (in message recipient query: #{query.inspect}"
|
33
|
+
end
|
34
|
+
raise "Could not find #{model_name} with ID #{id.inspect} (in message recipient query: #{query.inspect}" if model.blank?
|
35
|
+
|
36
|
+
MessageRecipientQuery.new(
|
37
|
+
query,
|
38
|
+
type,
|
39
|
+
id,
|
40
|
+
model
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.friendly_name(query, model = nil)
|
45
|
+
recipient_query = parse(query, model)
|
46
|
+
model = recipient_query.model
|
47
|
+
|
48
|
+
case recipient_query.type
|
49
|
+
when "bus-list"
|
50
|
+
"Bus List: #{model.name} (signed up for bus)"
|
51
|
+
when "bus-list--eligible"
|
52
|
+
"Bus List: #{model.name} (eligible, not signed up for bus)"
|
53
|
+
when "bus-list--applied"
|
54
|
+
"Bus List: #{model.name} (applied/not accepted)"
|
55
|
+
when "school"
|
56
|
+
"Confirmed or Accepted: #{model.name}"
|
57
|
+
else
|
58
|
+
raise "Unknown recipient query type: #{recipient_query.type.inspect} (in message recipient query: #{r.inspect}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/app/models/questionnaire.rb
CHANGED
@@ -2,6 +2,8 @@ class Questionnaire < ApplicationRecord
|
|
2
2
|
include ActiveModel::Dirty
|
3
3
|
|
4
4
|
before_validation :consolidate_school_names
|
5
|
+
after_create :queue_triggered_email_create
|
6
|
+
after_update :queue_triggered_email_update
|
5
7
|
after_save :update_school_questionnaire_count
|
6
8
|
after_destroy :update_school_questionnaire_count
|
7
9
|
|
@@ -181,4 +183,12 @@ class Questionnaire < ApplicationRecord
|
|
181
183
|
School.increment_counter(:questionnaire_count, school_id)
|
182
184
|
end
|
183
185
|
end
|
186
|
+
|
187
|
+
def queue_triggered_email_update
|
188
|
+
Message.queue_for_trigger("questionnaire.#{acc_status}", id) if saved_change_to_acc_status?
|
189
|
+
end
|
190
|
+
|
191
|
+
def queue_triggered_email_create
|
192
|
+
Message.queue_for_trigger("questionnaire.#{acc_status}", id)
|
193
|
+
end
|
184
194
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
%h3.no-margin Triggered Email Overview
|
2
|
+
%p
|
3
|
+
Recipient updates that match a given event will be sent the corresponding email(s) automatically.
|
4
|
+
%br
|
5
|
+
For example, when a user moves from the "Accepted" to "RSVP Confirmed" state, the user will be sent an email for the "RSVP Confirmed" event.
|
6
|
+
%p Hard-coded emails are those managed in the source code repository, and cannot be disabled.
|
7
|
+
|
8
|
+
%table.table
|
9
|
+
%thead
|
10
|
+
%tr
|
11
|
+
%th Trigger Event
|
12
|
+
%th Hard-coded Email
|
13
|
+
%th Triggered Emails
|
14
|
+
%tbody
|
15
|
+
- Message::POSSIBLE_TRIGGERS.keys.each do |trigger|
|
16
|
+
%tr
|
17
|
+
%td= Message::POSSIBLE_TRIGGERS[trigger]
|
18
|
+
- messages = Message.where(trigger: trigger).all
|
19
|
+
%td
|
20
|
+
= ['questionnaire.pending', 'questionnaire.accepted', 'questionnaire.denied', 'questionnaire.rsvp_confirmed'].include?(trigger) ? '<strong>Yes</strong>'.html_safe : 'No'
|
21
|
+
%td
|
22
|
+
- if messages.present?
|
23
|
+
%ul.no-margin
|
24
|
+
- messages.each do |message|
|
25
|
+
%li= link_to(message.name, manage_message_path(message))
|
26
|
+
- else
|
27
|
+
None
|
@@ -1,14 +1,15 @@
|
|
1
|
-
|
2
|
-
= f
|
1
|
+
.form-container
|
2
|
+
= simple_form_for(@bus_list, url: url_for(action: @bus_list.new_record? ? "create" : "update", controller: "bus_lists")) do |f|
|
3
|
+
= f.error_notification
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
.form-inputs
|
6
|
+
= f.input :name
|
7
|
+
= f.input :capacity
|
8
|
+
= f.input :needs_bus_captain
|
9
|
+
= f.input :notes, input_html: { rows: 10 }
|
10
|
+
%p
|
11
|
+
%small
|
12
|
+
%em Notes support Markdown and HTML.
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
.form-actions
|
15
|
+
= f.button :submit
|
@@ -1,15 +1,17 @@
|
|
1
|
-
|
2
|
-
= f
|
1
|
+
.form-container
|
2
|
+
= simple_form_for @message, url: url_for(action: @message.new_record? ? "create" : "update", controller: "messages") do |f|
|
3
|
+
= f.error_notification
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
.form-inputs
|
6
|
+
= f.input :name
|
7
|
+
= f.input :subject, hint: "All emails are from <pre>#{html_escape(Rails.configuration.hackathon['email_from'])}</pre>".html_safe
|
8
|
+
= f.input :template, as: :select, collection: Message::POSSIBLE_TEMPLATES.map { |x| [x.titleize, x] }, include_blank: false
|
9
|
+
- if @message.status == "drafted"
|
10
|
+
= f.input :recipients, as: :select, collection: Message.possible_recipients, input_html: { class: "selectize", multiple: true, }, hint: "Sent manually, in bulk", placeholder: "Type to search by school or type..."
|
11
|
+
- else
|
12
|
+
= 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
|
+
= f.input :trigger, as: :select, collection: Message::POSSIBLE_TRIGGERS.invert, include_blank: "(no automatic trigger)", hint: "Sent automatically, to an individual applicant"
|
14
|
+
= f.input :body, input_html: { rows: 10 }, hint: "Supports markdown and HTML"
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
+
.form-actions
|
17
|
+
= f.button :submit
|
@@ -8,11 +8,16 @@
|
|
8
8
|
%th ID
|
9
9
|
%th Name
|
10
10
|
%th Subject
|
11
|
-
%th
|
12
|
-
%th
|
11
|
+
%th Trigger
|
12
|
+
%th Bulk Status
|
13
|
+
%th Bulk Delivered
|
13
14
|
%tbody
|
14
15
|
|
15
16
|
%br
|
16
17
|
|
17
18
|
- unless current_user.admin_limited_access
|
18
|
-
= btn_link_to 'New Message', new_manage_message_path
|
19
|
+
%p= btn_link_to 'New Message', new_manage_message_path
|
20
|
+
|
21
|
+
%br
|
22
|
+
|
23
|
+
= render 'triggered_email_summary'
|
@@ -14,34 +14,47 @@
|
|
14
14
|
= @message.template.titleize
|
15
15
|
%p
|
16
16
|
%b Recipients:
|
17
|
-
= @message.recipients_list
|
17
|
+
= @message.recipients_list.presence || "(none)"
|
18
18
|
%br
|
19
19
|
%small
|
20
|
-
%em
|
20
|
+
%em Sent manually, in bulk
|
21
|
+
- if @message.recipients.present?
|
22
|
+
%br
|
23
|
+
%small
|
24
|
+
%em #{recipient_count} currently match this query
|
25
|
+
%p
|
26
|
+
%b Trigger:
|
27
|
+
= Message::POSSIBLE_TRIGGERS[@message.trigger] || "(no automatic trigger)"
|
28
|
+
%br
|
29
|
+
%small
|
30
|
+
%em Sent automatically, to an individual applicant
|
21
31
|
%p
|
22
32
|
%b Preview:
|
23
33
|
= link_to "Open full preview »".html_safe, preview_manage_message_path
|
24
34
|
|
25
35
|
%iframe.email-preview{src: preview_manage_message_path(@message)}
|
26
36
|
|
27
|
-
|
28
|
-
%
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
- if @message.recipients_list.present?
|
38
|
+
%fieldset
|
39
|
+
%legend Bulk delivery details
|
40
|
+
%p
|
41
|
+
%b
|
42
|
+
Status:
|
43
|
+
= @message.status.titleize
|
44
|
+
%p
|
45
|
+
%b Queued At:
|
46
|
+
= @message.queued_at || "(n/a)"
|
47
|
+
%p
|
48
|
+
%b Started At:
|
49
|
+
= @message.started_at || "(n/a)"
|
50
|
+
%p
|
51
|
+
%b Delivered At:
|
52
|
+
= @message.delivered_at || "(n/a)"
|
40
53
|
|
41
54
|
%hr
|
42
55
|
|
43
56
|
- unless current_user.admin_limited_access
|
44
|
-
- if @message.status == "drafted"
|
57
|
+
- if @message.status == "drafted" && @message.recipients_list.present?
|
45
58
|
= btn_link_to 'Deliver', deliver_manage_message_path(@message), method: :patch, data: { confirm: "Are you sure? The message \"#{@message.name}\" will be sent to #{recipient_count}." }
|
46
59
|
\|
|
47
60
|
- if @message.can_edit?
|
@@ -25,9 +25,20 @@
|
|
25
25
|
|
26
26
|
- unless current_user.admin_limited_access?
|
27
27
|
%br
|
28
|
-
|
28
|
+
.container.container-half
|
29
|
+
= btn_link_to 'New Questionnaire', new_manage_questionnaire_path
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
.container.container-half
|
32
|
+
|
33
|
+
.container.container-half
|
34
|
+
%fieldset
|
35
|
+
%legend Bulk Action
|
36
|
+
= simple_form_for Questionnaire.new, url: bulk_apply_manage_questionnaires_path, html: { data: { bulk_row_edit: true } } do |f|
|
37
|
+
= f.input :acc_status, as: :select, collection: Questionnaire::POSSIBLE_ACC_STATUS.invert, include_blank: false, label: "Acceptance Status:", input_html: { data: { bulk_row_edit: true } }, hint: "Updating this status may trigger an automatic email to each applicant - see below for details."
|
38
|
+
= f.button :submit, value: "Update Status", data: { bulk_row_edit: true }
|
39
|
+
|
40
|
+
%br
|
41
|
+
%br
|
42
|
+
%br
|
43
|
+
|
44
|
+
= render 'triggered_email_summary'
|
@@ -51,7 +51,7 @@
|
|
51
51
|
- unless current_user.admin_limited_access?
|
52
52
|
%hr
|
53
53
|
= simple_form_for @questionnaire, url: url_for(action: "update_acc_status", controller: "questionnaires") do |f|
|
54
|
-
= f.input :acc_status, as: :select, collection: Questionnaire::POSSIBLE_ACC_STATUS.invert, include_blank: false, label: "Acceptance Status:"
|
54
|
+
= f.input :acc_status, as: :select, collection: Questionnaire::POSSIBLE_ACC_STATUS.invert, include_blank: false, label: "Acceptance Status:", hint: "Updating this status may trigger an automatic email to the applicant - see #{link_to('messages', manage_messages_path)} for details.".html_safe
|
55
55
|
= f.button :submit, value: "Update Status"
|
56
56
|
|
57
57
|
%hr
|
@@ -18,13 +18,13 @@ class BulkMessageWorker
|
|
18
18
|
def self.build_recipients(recipient_types)
|
19
19
|
recipients = Set.new
|
20
20
|
recipient_types.each do |type|
|
21
|
-
recipients +=
|
21
|
+
recipients += user_ids(type)
|
22
22
|
end
|
23
23
|
recipients
|
24
24
|
end
|
25
25
|
|
26
26
|
# rubocop:disable CyclomaticComplexity
|
27
|
-
def self.
|
27
|
+
def self.user_ids(type)
|
28
28
|
case type
|
29
29
|
when "all"
|
30
30
|
User.where(admin: false).pluck(:id)
|
@@ -50,38 +50,32 @@ class BulkMessageWorker
|
|
50
50
|
Questionnaire.where("(acc_status = 'accepted' OR acc_status = 'rsvp_confirmed' OR acc_status = 'rsvp_denied') AND checked_in_at IS NULL").pluck(:user_id)
|
51
51
|
when "non-checked-in-excluding"
|
52
52
|
Questionnaire.where("acc_status != 'accepted' AND acc_status != 'rsvp_confirmed' AND acc_status != 'rsvp_denied' AND checked_in_at IS NULL").pluck(:user_id)
|
53
|
-
when
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
when "bus-list
|
70
|
-
|
71
|
-
when "
|
72
|
-
Questionnaire.where("
|
73
|
-
when "
|
74
|
-
Questionnaire.where("
|
75
|
-
when "school
|
76
|
-
Questionnaire.where("school_id =
|
77
|
-
|
78
|
-
|
79
|
-
when "school-waterloo"
|
80
|
-
Questionnaire.where("school_id = 5580 AND (acc_status = \"rsvp_confirmed\" OR acc_status = \"accepted\")").pluck(:user_id)
|
81
|
-
when "school-toronto"
|
82
|
-
Questionnaire.where("school_id = 5539 AND (acc_status = \"rsvp_confirmed\" OR acc_status = \"accepted\")").pluck(:user_id)
|
83
|
-
when "school-umd-collegepark"
|
84
|
-
Questionnaire.where("school_id = 5543 AND (acc_status = \"rsvp_confirmed\" OR acc_status = \"accepted\")").pluck(:user_id)
|
53
|
+
when /(.*)::(\d*)/
|
54
|
+
user_ids_from_query(type)
|
55
|
+
else
|
56
|
+
raise "Unknown recipient type: #{type.inspect}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
# rubocop:enable CyclomaticComplexity
|
60
|
+
|
61
|
+
def self.user_ids_from_query(type)
|
62
|
+
# Parse the query
|
63
|
+
# See app/models/message_recipient_query.rb for how this works
|
64
|
+
recipient_query = MessageRecipientQuery.parse(type)
|
65
|
+
model = recipient_query.model
|
66
|
+
|
67
|
+
# Build the recipients query
|
68
|
+
case recipient_query.type
|
69
|
+
when "bus-list"
|
70
|
+
model.passengers.pluck(:user_id)
|
71
|
+
when "bus-list--eligible"
|
72
|
+
Questionnaire.joins(:school).where("schools.bus_list_id = ? AND riding_bus != 1 AND (acc_status = 'accepted' OR acc_status = 'rsvp_confirmed')", model.id).pluck(:user_id)
|
73
|
+
when "bus-list--applied"
|
74
|
+
Questionnaire.joins(:school).where("schools.bus_list_id = ? AND (acc_status != 'accepted' AND acc_status != 'rsvp_confirmed' AND acc_status != 'rsvp_denied')", model.id).pluck(:user_id)
|
75
|
+
when "school"
|
76
|
+
Questionnaire.where("school_id = ? AND (acc_status = 'rsvp_confirmed' OR acc_status = 'accepted')", model.id).pluck(:user_id)
|
77
|
+
else
|
78
|
+
raise "Unknown recipient query type: #{recipient_query.type.inspect} (in message recipient query: #{type.inspect}"
|
85
79
|
end
|
86
80
|
end
|
87
81
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ConvertMessageRecipientsToRecipientQueries < ActiveRecord::Migration[5.1]
|
2
|
+
CONVERSION_MAPPING = {
|
3
|
+
"bus-list-cornell-bing" => ["bus-list", 1],
|
4
|
+
"bus-list-buffalo" => ["bus-list", 2],
|
5
|
+
"bus-list-albany" => ["bus-list", 3],
|
6
|
+
"bus-list-cornell-bing-eligible" => ["bus-list--eligible", 1],
|
7
|
+
"bus-list-buffalo-eligible" => ["bus-list--eligible", 2],
|
8
|
+
"bus-list-albany-eligible" => ["bus-list--eligible", 3],
|
9
|
+
"bus-list-cornell-bing-applied" => ["bus-list--applied", 1],
|
10
|
+
"bus-list-buffalo-applied" => ["bus-list--applied", 2],
|
11
|
+
"bus-list-albany-applied" => ["bus-list--applied", 3],
|
12
|
+
"school-rit" => ["school", 2304],
|
13
|
+
"school-cornell" => ["school", 2164],
|
14
|
+
"school-binghamton" => ["school", 5526],
|
15
|
+
"school-buffalo" => ["school", 2345],
|
16
|
+
"school-waterloo" => ["school", 5580],
|
17
|
+
"school-toronto" => ["school", 5539],
|
18
|
+
"school-umd-collegepark" => ["school", 5543]
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
def up
|
22
|
+
Message.all.each do |message|
|
23
|
+
CONVERSION_MAPPING.to_a.each do |mapping|
|
24
|
+
old = mapping[0]
|
25
|
+
new_type = mapping[1][0]
|
26
|
+
new_id = mapping[1][1]
|
27
|
+
|
28
|
+
index = message.recipients.index(old)
|
29
|
+
next if index.nil?
|
30
|
+
|
31
|
+
message.recipients[index] = "#{new_type}::#{new_id}"
|
32
|
+
message.save!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hackathon_manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stuart Olivera
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-01-
|
11
|
+
date: 2018-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -517,6 +517,7 @@ files:
|
|
517
517
|
- app/models/deletable_attachment.rb
|
518
518
|
- app/models/fips.rb
|
519
519
|
- app/models/message.rb
|
520
|
+
- app/models/message_recipient_query.rb
|
520
521
|
- app/models/questionnaire.rb
|
521
522
|
- app/models/school.rb
|
522
523
|
- app/models/school_name_duplicate.rb
|
@@ -524,6 +525,7 @@ files:
|
|
524
525
|
- app/views/application/_bus_list_info.html.haml
|
525
526
|
- app/views/application/_bus_list_stats.html.haml
|
526
527
|
- app/views/application/_questionnaire_summary.html.haml
|
528
|
+
- app/views/application/_triggered_email_summary.html.haml
|
527
529
|
- app/views/bus_lists/show.html.haml
|
528
530
|
- app/views/devise/passwords/_form.html.haml
|
529
531
|
- app/views/devise/passwords/edit.html.haml
|
@@ -638,7 +640,9 @@ files:
|
|
638
640
|
- db/migrate/20170107210122_create_school_name_duplicates.rb
|
639
641
|
- db/migrate/20170128063020_install_blazer.rb
|
640
642
|
- db/migrate/20171220042158_add_why_attend_to_questionnaires.rb
|
643
|
+
- db/migrate/20180108231420_add_trigger_to_message.rb
|
641
644
|
- db/migrate/20180116022530_set_default_count_on_schools.rb
|
645
|
+
- db/migrate/20180118035548_convert_message_recipients_to_recipient_queries.rb
|
642
646
|
- db/schools.csv
|
643
647
|
- db/seeds.rb
|
644
648
|
- lib/hackathon_manager.rb
|