effective_mentorships 0.2.3 → 0.3.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/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/helpers/effective_mentorships_helper.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
|