effective_mentorships 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/admin/mentorship_bulk_groups_controller.rb +19 -0
- data/app/datatables/admin/effective_mentorship_bulk_group_mentees_datatable.rb +65 -0
- data/app/datatables/admin/effective_mentorship_bulk_group_mentors_datatable.rb +66 -0
- data/app/datatables/admin/effective_mentorship_bulk_groups_datatable.rb +32 -0
- data/app/datatables/admin/effective_mentorship_cycles_datatable.rb +0 -1
- data/app/datatables/admin/effective_mentorship_groups_datatable.rb +59 -7
- data/app/datatables/admin/effective_mentorship_registrations_datatable.rb +18 -3
- data/app/datatables/effective_mentorships_available_cycles_datatable.rb +1 -1
- data/app/datatables/effective_mentorships_groups_datatable.rb +1 -1
- data/app/datatables/effective_mentorships_registrations_datatable.rb +1 -0
- data/app/jobs/effective/mentorships_bulk_create_groups_job.rb +10 -0
- data/app/jobs/effective/mentorships_bulk_notify_groups_job.rb +10 -0
- data/app/mailers/effective/mentorships_mailer.rb +41 -3
- data/app/models/concerns/effective_mentorships_bulk_group.rb +368 -0
- data/app/models/concerns/effective_mentorships_group.rb +80 -5
- data/app/models/concerns/effective_mentorships_registration.rb +69 -8
- data/app/models/concerns/effective_mentorships_user.rb +42 -0
- data/app/models/effective/mentorship_bulk_group.rb +6 -0
- data/app/models/effective/mentorship_cycle.rb +1 -1
- data/app/models/effective/mentorship_group_user.rb +15 -0
- data/app/views/admin/mentorship_bulk_groups/_content.html.haml +1 -0
- data/app/views/admin/mentorship_bulk_groups/_creation.html.haml +9 -0
- data/app/views/admin/mentorship_bulk_groups/_layout.html.haml +3 -0
- data/app/views/admin/mentorship_bulk_groups/_selection.html.haml +24 -0
- data/app/views/admin/mentorship_bulk_groups/finished.html.haml +35 -0
- data/app/views/admin/mentorship_bulk_groups/group.html.haml +31 -0
- data/app/views/admin/mentorship_bulk_groups/grouping.html.haml +10 -0
- data/app/views/admin/mentorship_bulk_groups/notify.html.haml +49 -0
- data/app/views/admin/mentorship_bulk_groups/notifying.html.haml +10 -0
- data/app/views/admin/mentorship_bulk_groups/publish.html.haml +30 -0
- data/app/views/admin/mentorship_bulk_groups/review.html.haml +49 -0
- data/app/views/admin/mentorship_bulk_groups/start.html.haml +8 -0
- data/app/views/admin/mentorship_cycles/_form_mentorship_cycle.html.haml +0 -4
- data/app/views/admin/mentorship_groups/_form_mentorship_group.html.haml +11 -4
- data/app/views/effective/mentorship_registrations/_fields.html.haml +2 -2
- data/app/views/effective/mentorships/_dashboard.html.haml +1 -1
- data/app/views/effective/mentorships_mailer/mentorship_group_created_to_mentee.liquid +14 -0
- data/app/views/effective/mentorships_mailer/mentorship_group_created_to_mentor.liquid +14 -0
- data/config/effective_mentorships.rb +1 -0
- data/config/locales/effective_mentorships.en.yml +1 -0
- data/config/routes.rb +12 -5
- data/db/migrate/101_create_effective_mentorships.rb +26 -2
- data/lib/effective_mentorships/engine.rb +1 -0
- data/lib/effective_mentorships/version.rb +1 -1
- data/lib/effective_mentorships.rb +6 -2
- metadata +24 -2
@@ -0,0 +1,368 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# EffectiveCpdBulkAudit
|
4
|
+
#
|
5
|
+
# Mark your owner model with effective_cpd_bulk_audit to get all the includes
|
6
|
+
|
7
|
+
module EffectiveMentorshipsBulkGroup
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
module Base
|
11
|
+
def effective_mentorships_bulk_group
|
12
|
+
include ::EffectiveMentorshipsBulkGroup
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def effective_mentorships_bulk_group?; true; end
|
18
|
+
end
|
19
|
+
|
20
|
+
included do
|
21
|
+
acts_as_job_status
|
22
|
+
log_changes if respond_to?(:log_changes)
|
23
|
+
|
24
|
+
acts_as_wizard(
|
25
|
+
start: 'Start',
|
26
|
+
group: 'Preview',
|
27
|
+
grouping: 'Grouping',
|
28
|
+
review: 'Review',
|
29
|
+
publish: 'Publish',
|
30
|
+
notify: 'Notify',
|
31
|
+
notifying: 'Notifying',
|
32
|
+
finished: 'Finished'
|
33
|
+
)
|
34
|
+
|
35
|
+
# Effective Scoped
|
36
|
+
belongs_to :mentorship_cycle, class_name: 'Effective::MentorshipCycle'
|
37
|
+
|
38
|
+
# Application Scoped
|
39
|
+
has_many :mentorship_groups, -> { order(:id) }, inverse_of: :mentorship_bulk_group, dependent: :nullify
|
40
|
+
accepts_nested_attributes_for :mentorship_groups, allow_destroy: true
|
41
|
+
|
42
|
+
effective_resource do
|
43
|
+
mentorship_groups_count :integer
|
44
|
+
|
45
|
+
email_form_skip :boolean
|
46
|
+
|
47
|
+
# Acts as Wizard
|
48
|
+
wizard_steps :text, permitted: false
|
49
|
+
|
50
|
+
# Acts as Tokened
|
51
|
+
token :string
|
52
|
+
|
53
|
+
# Acts as Job Status
|
54
|
+
job_status :string
|
55
|
+
job_started_at :datetime
|
56
|
+
job_ended_at :datetime
|
57
|
+
job_error :text
|
58
|
+
|
59
|
+
timestamps
|
60
|
+
end
|
61
|
+
|
62
|
+
scope :deep, -> { all }
|
63
|
+
scope :sorted, -> { order(:id) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
[model_name.human, ("##{id}" if id.present?)].compact.join(' ')
|
68
|
+
end
|
69
|
+
|
70
|
+
def max_pairings_mentee
|
71
|
+
raise('expected a mentorship cycle') unless mentorship_cycle.present?
|
72
|
+
mentorship_cycle.max_pairings_mentee || 10 # Hardcode a sane limit. This shouldn't ever be used. The registrations is limited to 1-5
|
73
|
+
end
|
74
|
+
|
75
|
+
def mentors_mentorship_registrations
|
76
|
+
raise('expected a mentorship cycle') unless mentorship_cycle.present?
|
77
|
+
EffectiveMentorships.MentorshipRegistration.opt_in.mentors.where(mentorship_cycle: mentorship_cycle)
|
78
|
+
end
|
79
|
+
|
80
|
+
def mentees_mentorship_registrations
|
81
|
+
raise('expected a mentorship cycle') unless mentorship_cycle.present?
|
82
|
+
EffectiveMentorships.MentorshipRegistration.opt_in.mentees.where(mentorship_cycle: mentorship_cycle)
|
83
|
+
end
|
84
|
+
|
85
|
+
def mentorship_group_for(user:)
|
86
|
+
mentorship_groups.find { |mentorship_group| mentorship_group.mentorship_group_user(user: user).present? }
|
87
|
+
end
|
88
|
+
|
89
|
+
def group!
|
90
|
+
# Calls create_groups! and save!
|
91
|
+
perform_with_job_status! { Effective::MentorshipsBulkCreateGroupsJob.perform_later(id) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def publish!
|
95
|
+
mentorship_groups.deep.find_each { |mentorship_group| mentorship_group.publish! }
|
96
|
+
save!
|
97
|
+
end
|
98
|
+
|
99
|
+
def notify!
|
100
|
+
return skip_notify! if email_form_skip?
|
101
|
+
|
102
|
+
# Calls notify_groups! and save!
|
103
|
+
perform_with_job_status! { Effective::MentorshipsBulkNotifyGroupsJob.perform_later(id) }
|
104
|
+
end
|
105
|
+
|
106
|
+
def skip_notify!
|
107
|
+
wizard_steps[:notifying] ||= Time.zone.now
|
108
|
+
wizard_steps[last_wizard_step] ||= Time.zone.now
|
109
|
+
save!
|
110
|
+
end
|
111
|
+
|
112
|
+
def notifying!
|
113
|
+
wizard_steps[last_wizard_step] ||= Time.zone.now # Also finish the whole wizard
|
114
|
+
save!
|
115
|
+
end
|
116
|
+
|
117
|
+
# Called by Effective::MentorshipsBulkNotifyGroupsJob
|
118
|
+
def notify_groups!
|
119
|
+
mentorship_groups.published.not_notified.find_each do |mentorship_group|
|
120
|
+
mentorship_group.notify!
|
121
|
+
end
|
122
|
+
|
123
|
+
wizard_steps[:notifying] ||= Time.zone.now
|
124
|
+
save!
|
125
|
+
end
|
126
|
+
|
127
|
+
# Called by Effective::MentorshipsBulkCreateGroupsJob
|
128
|
+
def create_groups!
|
129
|
+
# First pass
|
130
|
+
# Create groups with 1 mentor and 1 best matching mentee each
|
131
|
+
EffectiveMentorships.MentorshipRegistration.uncached do
|
132
|
+
# In-person
|
133
|
+
mentors_mentorship_registrations.without_groups.in_person.find_each do |mentor_registration|
|
134
|
+
mentorship_group = build_mentorship_group(mentor_registration)
|
135
|
+
mentorship_group&.save!
|
136
|
+
end
|
137
|
+
|
138
|
+
# Either
|
139
|
+
mentors_mentorship_registrations.without_groups.either.find_each do |mentor_registration|
|
140
|
+
mentorship_group = build_mentorship_group(mentor_registration)
|
141
|
+
mentorship_group&.save!
|
142
|
+
end
|
143
|
+
|
144
|
+
# Virtual
|
145
|
+
mentors_mentorship_registrations.without_groups.virtual.find_each do |mentor_registration|
|
146
|
+
mentorship_group = build_mentorship_group(mentor_registration)
|
147
|
+
mentorship_group&.save!
|
148
|
+
end
|
149
|
+
|
150
|
+
# Second pass
|
151
|
+
# Create groups with 1 mentor and any mentee
|
152
|
+
mentors_mentorship_registrations.without_groups.find_each do |mentor_registration|
|
153
|
+
mentorship_group = build_mentorship_group(mentor_registration, any_mentee: true)
|
154
|
+
mentorship_group&.save!
|
155
|
+
end
|
156
|
+
|
157
|
+
# Third pass
|
158
|
+
# Add best matching mentees to groups where mentor wants more than 1 mentee
|
159
|
+
if max_pairings_mentee > 1
|
160
|
+
fillable_mentors_mentorship_registrations = mentors_mentorship_registrations.multiple_mentees.with_groups_from(self)
|
161
|
+
|
162
|
+
# In-person
|
163
|
+
fillable_mentors_mentorship_registrations.in_person.find_each do |mentor_registration|
|
164
|
+
mentorship_group = fill_mentorship_group(mentor_registration)
|
165
|
+
mentorship_group&.save!
|
166
|
+
end
|
167
|
+
|
168
|
+
# Either
|
169
|
+
fillable_mentors_mentorship_registrations.either.find_each do |mentor_registration|
|
170
|
+
mentorship_group = fill_mentorship_group(mentor_registration)
|
171
|
+
mentorship_group&.save!
|
172
|
+
end
|
173
|
+
|
174
|
+
# Virtual
|
175
|
+
fillable_mentors_mentorship_registrations.virtual.find_each do |mentor_registration|
|
176
|
+
mentorship_group = fill_mentorship_group(mentor_registration)
|
177
|
+
mentorship_group&.save!
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Fourth pass
|
182
|
+
# Add any mentees to groups where mentor wants more than 1 mentee
|
183
|
+
if max_pairings_mentee > 1
|
184
|
+
fillable_mentors_mentorship_registrations = mentors_mentorship_registrations.multiple_mentees.with_groups_from(self)
|
185
|
+
|
186
|
+
fillable_mentors_mentorship_registrations.find_each do |mentor_registration|
|
187
|
+
mentorship_group = fill_mentorship_group(mentor_registration, any_mentee: true)
|
188
|
+
mentorship_group&.save!
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# Call after_save callback on all mentorship groups
|
193
|
+
mentorship_groups.each do |mentorship_group|
|
194
|
+
mentorship_group.assign_attributes(save_as_draft: true)
|
195
|
+
after_save_mentorship_group!(mentorship_group)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
wizard_steps[:grouping] ||= Time.zone.now
|
200
|
+
save!
|
201
|
+
end
|
202
|
+
|
203
|
+
def build_mentorship_group(mentor_registration, any_mentee: false)
|
204
|
+
raise('expected a mentorship registration') unless mentor_registration.class.try(:effective_mentorships_registration?)
|
205
|
+
raise('expected a mentor mentorship registration') unless mentor_registration.mentor?
|
206
|
+
|
207
|
+
mentor = mentor_registration.user
|
208
|
+
raise('expected a mentorship user') unless mentor.class.try(:effective_mentorships_user?)
|
209
|
+
|
210
|
+
# Select the best matching mentees for this mentor registration
|
211
|
+
mentee_registration = find_best_mentee_registration(mentor_registration)
|
212
|
+
|
213
|
+
if any_mentee
|
214
|
+
mentee_registration ||= find_any_mentee_registration(mentor_registration)
|
215
|
+
end
|
216
|
+
|
217
|
+
return unless mentee_registration.present?
|
218
|
+
|
219
|
+
mentee = mentee_registration.user
|
220
|
+
raise('expected a mentorship user') unless mentee.class.try(:effective_mentorships_user?)
|
221
|
+
|
222
|
+
# Create a new group in draft state
|
223
|
+
mentorship_group = mentorship_groups.build(mentorship_cycle: mentorship_cycle, save_as_draft: true)
|
224
|
+
mentorship_group.build_mentor(user: mentor)
|
225
|
+
mentorship_group.build_mentee(user: mentee)
|
226
|
+
|
227
|
+
# Return the group ready to be saved
|
228
|
+
mentorship_group
|
229
|
+
end
|
230
|
+
|
231
|
+
def fill_mentorship_group(mentor_registration, any_mentee: false)
|
232
|
+
raise('expected a mentorship registration') unless mentor_registration.class.try(:effective_mentorships_registration?)
|
233
|
+
raise('expected a mentor mentorship registration') unless mentor_registration.mentor?
|
234
|
+
|
235
|
+
mentor = mentor_registration.user
|
236
|
+
raise('expected a mentorship user') unless mentor.class.try(:effective_mentorships_user?)
|
237
|
+
|
238
|
+
# Find the existing mentorship group that we previously created
|
239
|
+
mentorship_group = mentorship_group_for(user: mentor)
|
240
|
+
return unless mentorship_group.present?
|
241
|
+
|
242
|
+
# Fill this group to limit of number of mentees
|
243
|
+
limit = [mentor_registration.mentor_multiple_mentees_limit.to_i, max_pairings_mentee].min
|
244
|
+
fill_mentees = (limit - mentorship_group.mentorship_group_mentees.length)
|
245
|
+
return unless fill_mentees > 0
|
246
|
+
|
247
|
+
# We only support 1 mentor and many mentees
|
248
|
+
fill_mentees.times do
|
249
|
+
mentee_registration = find_best_mentee_registration(mentor_registration)
|
250
|
+
|
251
|
+
if any_mentee
|
252
|
+
mentee_registration ||= find_any_mentee_registration(mentor_registration)
|
253
|
+
end
|
254
|
+
|
255
|
+
if mentee_registration.present?
|
256
|
+
mentee = mentee_registration.user
|
257
|
+
raise('expected a mentorship user') unless mentee.class.try(:effective_mentorships_user?)
|
258
|
+
|
259
|
+
mentorship_group.build_mentee(user: mentee)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# Return the group ready to be saved
|
264
|
+
mentorship_group.assign_attributes(save_as_draft: true)
|
265
|
+
mentorship_group
|
266
|
+
end
|
267
|
+
|
268
|
+
def find_best_mentee_registration(mentor_registration)
|
269
|
+
case mentor_registration.venue
|
270
|
+
when 'In-person'
|
271
|
+
find_best_in_person_mentee_registration(mentor_registration)
|
272
|
+
when 'Either'
|
273
|
+
find_best_either_mentee_registration(mentor_registration)
|
274
|
+
when 'Virtual'
|
275
|
+
find_best_virtual_mentee_registration(mentor_registration)
|
276
|
+
else
|
277
|
+
raise("unexpected venue: #{mentor_registration.venue}")
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def find_any_mentee_registration(mentor_registration)
|
282
|
+
mentees_mentorship_registrations.without_groups.order(:id).first
|
283
|
+
end
|
284
|
+
|
285
|
+
def find_best_in_person_mentee_registration(mentor_registration)
|
286
|
+
registrations = mentees_mentorship_registrations.without_groups.order(:id)
|
287
|
+
|
288
|
+
# In-person, same location, same category
|
289
|
+
registration ||= registrations.in_person.where(location: mentor_registration.location, category: mentor_registration.category).first
|
290
|
+
|
291
|
+
# In-person, same location, any category
|
292
|
+
registration ||= registrations.in_person.where(location: mentor_registration.location).first
|
293
|
+
|
294
|
+
# Either, same location, same category
|
295
|
+
registration ||= registrations.either.where(location: mentor_registration.location, category: mentor_registration.category).first
|
296
|
+
|
297
|
+
# Either, same location, any category
|
298
|
+
registration ||= registrations.either.where(location: mentor_registration.location).first
|
299
|
+
|
300
|
+
# Might be nil
|
301
|
+
registration
|
302
|
+
end
|
303
|
+
|
304
|
+
def find_best_either_mentee_registration(mentor_registration)
|
305
|
+
raise('expected an in-person mentor registration') unless mentor_registration.either?
|
306
|
+
|
307
|
+
registrations = mentees_mentorship_registrations.without_groups.order(:id)
|
308
|
+
|
309
|
+
# Either, same location, same category
|
310
|
+
registration ||= registrations.either.where(location: mentor_registration.location, category: mentor_registration.category).first
|
311
|
+
|
312
|
+
# In-person, same location, same category
|
313
|
+
registration ||= registrations.in_person.where(location: mentor_registration.location, category: mentor_registration.category).first
|
314
|
+
|
315
|
+
# Either, any location, same category
|
316
|
+
registration ||= registrations.either.where(category: mentor_registration.category).first
|
317
|
+
|
318
|
+
# In-person, same location, any category
|
319
|
+
registration ||= registrations.in_person.where(location: mentor_registration.location).first
|
320
|
+
|
321
|
+
# Virtual, same location, same category
|
322
|
+
registration ||= registrations.virtual.where(location: mentor_registration.location, category: mentor_registration.category).first
|
323
|
+
|
324
|
+
# Virtual, any location, same category
|
325
|
+
registration ||= registrations.virtual.where(category: mentor_registration.category).first
|
326
|
+
|
327
|
+
# Either any
|
328
|
+
registration ||= registrations.either.first
|
329
|
+
|
330
|
+
# Virtual any
|
331
|
+
registration ||= registrations.virtual.first
|
332
|
+
|
333
|
+
# Might be nil
|
334
|
+
registration
|
335
|
+
end
|
336
|
+
|
337
|
+
def find_best_virtual_mentee_registration(mentor_registration)
|
338
|
+
raise('expected an in-person mentor registration') unless mentor_registration.virtual?
|
339
|
+
|
340
|
+
registrations = mentees_mentorship_registrations.without_groups.order(:id)
|
341
|
+
|
342
|
+
# Virtual, same location, same category
|
343
|
+
registration ||= registrations.virtual.where(location: mentor_registration.location, category: mentor_registration.category).first
|
344
|
+
|
345
|
+
# Virtual, any location, same category
|
346
|
+
registration ||= registrations.virtual.where(category: mentor_registration.category).first
|
347
|
+
|
348
|
+
# Either, same location, same category
|
349
|
+
registration ||= registrations.either.where(location: mentor_registration.location, category: mentor_registration.category).first
|
350
|
+
|
351
|
+
# Either, any location, same category
|
352
|
+
registration ||= registrations.either.where(category: mentor_registration.category).first
|
353
|
+
|
354
|
+
# Virtual any
|
355
|
+
registration ||= registrations.virtual.first
|
356
|
+
|
357
|
+
# Either any
|
358
|
+
registration ||= registrations.either.first
|
359
|
+
|
360
|
+
# Might be nil
|
361
|
+
registration
|
362
|
+
end
|
363
|
+
|
364
|
+
# Nothing to do. Override me.
|
365
|
+
def after_save_mentorship_group!(mentorship_group)
|
366
|
+
end
|
367
|
+
|
368
|
+
end
|
@@ -18,24 +18,36 @@ module EffectiveMentorshipsGroup
|
|
18
18
|
end
|
19
19
|
|
20
20
|
included do
|
21
|
-
|
21
|
+
acts_as_published
|
22
22
|
acts_as_tokened
|
23
|
-
|
24
23
|
log_changes if respond_to?(:log_changes)
|
25
24
|
|
26
25
|
has_many_rich_texts
|
27
26
|
# rich_text_admin_notes
|
28
27
|
|
28
|
+
# Application Scoped
|
29
|
+
belongs_to :mentorship_bulk_group, optional: true, counter_cache: true
|
30
|
+
|
29
31
|
# Effective Scoped
|
30
32
|
belongs_to :mentorship_cycle, class_name: 'Effective::MentorshipCycle', counter_cache: true
|
31
33
|
|
32
34
|
has_many :mentorship_group_users, class_name: 'Effective::MentorshipGroupUser', dependent: :delete_all
|
33
35
|
accepts_nested_attributes_for :mentorship_group_users, allow_destroy: true
|
34
36
|
|
37
|
+
has_many :mentorship_group_mentors, -> { where(mentorship_role: :mentor) }, class_name: 'Effective::MentorshipGroupUser'
|
38
|
+
has_many :mentorship_group_mentees, -> { where(mentorship_role: :mentee) }, class_name: 'Effective::MentorshipGroupUser'
|
39
|
+
|
35
40
|
effective_resource do
|
36
41
|
title :string
|
37
42
|
|
38
|
-
|
43
|
+
# Track email
|
44
|
+
last_notified_at :datetime
|
45
|
+
|
46
|
+
# Acts as Published
|
47
|
+
published_start_at :datetime
|
48
|
+
published_end_at :datetime
|
49
|
+
|
50
|
+
# Acts as Tokened
|
39
51
|
token :string
|
40
52
|
|
41
53
|
timestamps
|
@@ -44,16 +56,79 @@ module EffectiveMentorshipsGroup
|
|
44
56
|
scope :deep, -> { includes(:mentorship_cycle, :rich_texts, mentorship_group_users: [:user]) }
|
45
57
|
scope :sorted, -> { order(:id) }
|
46
58
|
|
47
|
-
|
59
|
+
scope :notified, -> { where.not(last_notified_at: nil) }
|
60
|
+
scope :not_notified, -> { where(last_notified_at: nil) }
|
61
|
+
|
62
|
+
# When created on the MentorshipBulkGroup Review screen
|
63
|
+
before_validation(if: -> { mentorship_bulk_group.present? }) do
|
64
|
+
self.mentorship_cycle ||= mentorship_bulk_group.mentorship_cycle
|
65
|
+
end
|
66
|
+
|
67
|
+
before_save :assign_title # Assign computed title always
|
48
68
|
end
|
49
69
|
|
50
70
|
# Instance Methods
|
51
71
|
def to_s
|
52
|
-
model_name.human
|
72
|
+
title.presence || model_name.human
|
53
73
|
end
|
54
74
|
|
75
|
+
def assign_title
|
76
|
+
if present_mentorship_group_users.blank?
|
77
|
+
assign_attributes(title: "Empty")
|
78
|
+
else
|
79
|
+
mentor_names = mentors.map { |user| user.try(:first_name) || user.to_s.split(' ').first }.sort
|
80
|
+
mentee_names = mentees.map { |user| user.try(:first_name) || user.to_s.split(' ').first }.sort
|
81
|
+
|
82
|
+
assign_attributes(title: (mentor_names + mentee_names).join(', '))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def notify!
|
87
|
+
return false unless published?
|
88
|
+
|
89
|
+
present_mentorship_group_users.each do |mentorship_group_user|
|
90
|
+
case mentorship_group_user.mentorship_role.to_s
|
91
|
+
when 'mentor'
|
92
|
+
EffectiveMentorships.send_email(:mentorship_group_created_to_mentor, mentorship_group_user)
|
93
|
+
when 'mentee'
|
94
|
+
EffectiveMentorships.send_email(:mentorship_group_created_to_mentee, mentorship_group_user)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
update!(last_notified_at: Time.zone.now)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Find
|
55
102
|
def mentorship_group_user(user:)
|
56
103
|
mentorship_group_users.find { |mgu| mgu.user == user }
|
57
104
|
end
|
58
105
|
|
106
|
+
# Find or build
|
107
|
+
def build_mentorship_group_user(user:, mentorship_role:)
|
108
|
+
raise("unexpected mentorship role: #{mentorship_role}") unless EffectiveMentorships.MentorshipRegistration.mentorship_roles.include?(mentorship_role)
|
109
|
+
mentorship_group_user(user: user) || mentorship_group_users.build(user: user, mentorship_role: mentorship_role)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Find or build
|
113
|
+
def build_mentor(user:)
|
114
|
+
build_mentorship_group_user(user: user, mentorship_role: :mentor)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Find or build
|
118
|
+
def build_mentee(user:)
|
119
|
+
build_mentorship_group_user(user: user, mentorship_role: :mentee)
|
120
|
+
end
|
121
|
+
|
122
|
+
def present_mentorship_group_users
|
123
|
+
mentorship_group_users.reject(&:marked_for_destruction?)
|
124
|
+
end
|
125
|
+
|
126
|
+
def mentors
|
127
|
+
present_mentorship_group_users.select(&:mentor?).map(&:user)
|
128
|
+
end
|
129
|
+
|
130
|
+
def mentees
|
131
|
+
present_mentorship_group_users.select(&:mentee?).map(&:user)
|
132
|
+
end
|
133
|
+
|
59
134
|
end
|
@@ -16,10 +16,16 @@ module EffectiveMentorshipsRegistration
|
|
16
16
|
module ClassMethods
|
17
17
|
def effective_mentorships_registration?; true; end
|
18
18
|
|
19
|
+
# Don't change these roles
|
19
20
|
def mentorship_roles
|
20
21
|
[:mentor, :mentee]
|
21
22
|
end
|
22
23
|
|
24
|
+
# Don't change these venues
|
25
|
+
def venues
|
26
|
+
['Virtual', 'In-person', 'Either']
|
27
|
+
end
|
28
|
+
|
23
29
|
def categories
|
24
30
|
['General', 'Industry Specific']
|
25
31
|
end
|
@@ -27,10 +33,6 @@ module EffectiveMentorshipsRegistration
|
|
27
33
|
def locations
|
28
34
|
['Canada', 'United States']
|
29
35
|
end
|
30
|
-
|
31
|
-
def venues
|
32
|
-
['Virtual', 'In-person', 'Either']
|
33
|
-
end
|
34
36
|
end
|
35
37
|
|
36
38
|
included do
|
@@ -42,11 +44,13 @@ module EffectiveMentorshipsRegistration
|
|
42
44
|
|
43
45
|
# Effective Scoped
|
44
46
|
belongs_to :mentorship_cycle, class_name: 'Effective::MentorshipCycle', counter_cache: true
|
47
|
+
has_many :mentorship_group_users, class_name: 'Effective::MentorshipGroupUser', inverse_of: :mentorship_registration, dependent: :nullify
|
45
48
|
|
46
49
|
# App Scoped
|
47
50
|
belongs_to :user
|
48
51
|
belongs_to :parent, polymorphic: true, optional: true # A FeePayment if this was done through a fee payment
|
49
|
-
|
52
|
+
has_many :mentorship_groups, through: :mentorship_group_users
|
53
|
+
|
50
54
|
effective_resource do
|
51
55
|
title :string # Auto generated
|
52
56
|
|
@@ -83,7 +87,7 @@ module EffectiveMentorshipsRegistration
|
|
83
87
|
validates :accept_declaration, acceptance: true
|
84
88
|
end
|
85
89
|
|
86
|
-
validates :mentor_multiple_mentees_limit, numericality: {
|
90
|
+
validates :mentor_multiple_mentees_limit, numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: 5 }, if: -> { opt_in? && mentor? }
|
87
91
|
|
88
92
|
scope :deep, -> { includes(:rich_texts, :user, :mentorship_cycle) }
|
89
93
|
scope :sorted, -> { order(:id) }
|
@@ -92,6 +96,35 @@ module EffectiveMentorshipsRegistration
|
|
92
96
|
scope :mentees, -> { where(mentorship_role: :mentee) }
|
93
97
|
scope :opt_in, -> { where(opt_in: true) }
|
94
98
|
scope :opt_out, -> { where(opt_in: false) }
|
99
|
+
scope :opt_in_without_groups, -> { opt_in.without_groups }
|
100
|
+
|
101
|
+
scope :in_person, -> { where(venue: 'In-person') }
|
102
|
+
scope :virtual, -> { where(venue: 'Virtual') }
|
103
|
+
scope :either, -> { where(venue: 'Either') }
|
104
|
+
|
105
|
+
scope :with_groups, -> {
|
106
|
+
group_users = Effective::MentorshipGroupUser.all
|
107
|
+
where(id: group_users.select(:mentorship_registration_id))
|
108
|
+
}
|
109
|
+
|
110
|
+
scope :without_groups, -> {
|
111
|
+
group_users = Effective::MentorshipGroupUser.all
|
112
|
+
where.not(id: group_users.select(:mentorship_registration_id))
|
113
|
+
}
|
114
|
+
|
115
|
+
scope :with_groups, -> {
|
116
|
+
group_users = Effective::MentorshipGroupUser.all
|
117
|
+
where(id: group_users.select(:mentorship_registration_id))
|
118
|
+
}
|
119
|
+
|
120
|
+
scope :with_groups_from, -> (mentorship_bulk_group) {
|
121
|
+
groups = EffectiveMentorships.MentorshipGroup.where(mentorship_bulk_group: mentorship_bulk_group)
|
122
|
+
group_users = Effective::MentorshipGroupUser.where(mentorship_group_id: groups.select(:mentorship_group_id))
|
123
|
+
|
124
|
+
where(id: group_users.select(:mentorship_registration_id))
|
125
|
+
}
|
126
|
+
|
127
|
+
scope :multiple_mentees, -> { mentors.where('mentor_multiple_mentees_limit > 1') }
|
95
128
|
|
96
129
|
# User
|
97
130
|
validates :user_id, uniqueness: { scope: [:mentorship_cycle_id] }
|
@@ -102,12 +135,40 @@ module EffectiveMentorshipsRegistration
|
|
102
135
|
title.presence || model_name.human
|
103
136
|
end
|
104
137
|
|
138
|
+
def short_category
|
139
|
+
return category unless category.to_s.include?('(') && category.to_s.include?(')')
|
140
|
+
category.to_s.split('(').first.strip
|
141
|
+
end
|
142
|
+
|
143
|
+
def details
|
144
|
+
[
|
145
|
+
short_category.presence,
|
146
|
+
venue.presence,
|
147
|
+
location.presence,
|
148
|
+
("Limit #{mentor_multiple_mentees_limit}" if mentor? && mentor_multiple_mentees_limit.present?)
|
149
|
+
].compact.join(', ').html_safe
|
150
|
+
end
|
151
|
+
|
152
|
+
# Mentorship roles
|
105
153
|
def mentor?
|
106
|
-
mentorship_role == 'mentor'
|
154
|
+
mentorship_role.to_s == 'mentor'
|
107
155
|
end
|
108
156
|
|
109
157
|
def mentee?
|
110
|
-
mentorship_role == 'mentee'
|
158
|
+
mentorship_role.to_s == 'mentee'
|
159
|
+
end
|
160
|
+
|
161
|
+
# Venues
|
162
|
+
def in_person?
|
163
|
+
venue == 'In-person'
|
164
|
+
end
|
165
|
+
|
166
|
+
def virtual?
|
167
|
+
venue == 'Virtual'
|
168
|
+
end
|
169
|
+
|
170
|
+
def either?
|
171
|
+
venue == 'Either'
|
111
172
|
end
|
112
173
|
|
113
174
|
end
|
@@ -27,6 +27,48 @@ module EffectiveMentorshipsUser
|
|
27
27
|
has_many :mentorship_groups, through: :mentorship_group_users
|
28
28
|
|
29
29
|
scope :deep_effective_mentorships_user, -> { all }
|
30
|
+
|
31
|
+
scope :mentorships_opted_in, -> (mentorship_cycle) {
|
32
|
+
raise('expected an EffectiveMentorships.MentorshipCycle') unless mentorship_cycle.kind_of?(Effective::MentorshipCycle)
|
33
|
+
|
34
|
+
opted_in = EffectiveMentorships.MentorshipRegistration.opt_in.where(mentorship_cycle: mentorship_cycle)
|
35
|
+
where(id: opted_in.select(:user_id))
|
36
|
+
}
|
37
|
+
|
38
|
+
scope :mentorships_opted_out, -> (mentorship_cycle) {
|
39
|
+
raise('expected an EffectiveMentorships.MentorshipCycle') unless mentorship_cycle.kind_of?(Effective::MentorshipCycle)
|
40
|
+
|
41
|
+
opted_out = EffectiveMentorships.MentorshipRegistration.opt_out.where(mentorship_cycle: mentorship_cycle)
|
42
|
+
where(id: opted_out.select(:user_id))
|
43
|
+
}
|
44
|
+
|
45
|
+
scope :mentorships_opted_in_mentors, -> (mentorship_cycle) {
|
46
|
+
raise('expected an EffectiveMentorships.MentorshipCycle') unless mentorship_cycle.kind_of?(Effective::MentorshipCycle)
|
47
|
+
|
48
|
+
opted_in_mentors = EffectiveMentorships.MentorshipRegistration.opt_in.mentors.where(mentorship_cycle: mentorship_cycle)
|
49
|
+
where(id: opted_in_mentors.select(:user_id))
|
50
|
+
}
|
51
|
+
|
52
|
+
scope :mentorships_opted_in_mentees, -> (mentorship_cycle) {
|
53
|
+
raise('expected an EffectiveMentorships.MentorshipCycle') unless mentorship_cycle.kind_of?(Effective::MentorshipCycle)
|
54
|
+
|
55
|
+
opted_in_mentees = EffectiveMentorships.MentorshipRegistration.opt_in.mentees.where(mentorship_cycle: mentorship_cycle)
|
56
|
+
where(id: opted_in_mentees.select(:user_id))
|
57
|
+
}
|
58
|
+
|
59
|
+
scope :mentorships_with_groups, -> (mentorship_cycle) {
|
60
|
+
raise('expected an EffectiveMentorships.MentorshipCycle') unless mentorship_cycle.kind_of?(Effective::MentorshipCycle)
|
61
|
+
|
62
|
+
grouped = Effective::MentorshipGroupUser.where(mentorship_cycle: mentorship_cycle)
|
63
|
+
where(id: grouped.select(:user_id))
|
64
|
+
}
|
65
|
+
|
66
|
+
scope :mentorships_without_groups, -> (mentorship_cycle) {
|
67
|
+
raise('expected an EffectiveMentorships.MentorshipCycle') unless mentorship_cycle.kind_of?(Effective::MentorshipCycle)
|
68
|
+
|
69
|
+
grouped = Effective::MentorshipGroupUser.where(mentorship_cycle: mentorship_cycle)
|
70
|
+
where.not(id: grouped.select(:user_id))
|
71
|
+
}
|
30
72
|
end
|
31
73
|
|
32
74
|
# Used for the dashboard datatables. Which cycles can we register for?
|
@@ -19,7 +19,6 @@ module Effective
|
|
19
19
|
registration_start_at :datetime
|
20
20
|
registration_end_at :datetime
|
21
21
|
|
22
|
-
max_pairings_mentor :integer
|
23
22
|
max_pairings_mentee :integer
|
24
23
|
|
25
24
|
mentorship_groups_count :integer
|
@@ -41,6 +40,7 @@ module Effective
|
|
41
40
|
|
42
41
|
validates :title, presence: true, uniqueness: true
|
43
42
|
validates :start_at, presence: true
|
43
|
+
validates :max_pairings_mentee, numericality: { greater_than_or_equal_to: 1, allow_blank: true }
|
44
44
|
|
45
45
|
validate(if: -> { start_at.present? && end_at.present? }) do
|
46
46
|
errors.add(:end_at, 'must be after the start date') unless end_at > start_at
|