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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/admin/mentorship_bulk_groups_controller.rb +19 -0
  3. data/app/datatables/admin/effective_mentorship_bulk_group_mentees_datatable.rb +65 -0
  4. data/app/datatables/admin/effective_mentorship_bulk_group_mentors_datatable.rb +66 -0
  5. data/app/datatables/admin/effective_mentorship_bulk_groups_datatable.rb +32 -0
  6. data/app/datatables/admin/effective_mentorship_cycles_datatable.rb +0 -1
  7. data/app/datatables/admin/effective_mentorship_groups_datatable.rb +59 -7
  8. data/app/datatables/admin/effective_mentorship_registrations_datatable.rb +18 -3
  9. data/app/datatables/effective_mentorships_available_cycles_datatable.rb +1 -1
  10. data/app/datatables/effective_mentorships_groups_datatable.rb +1 -1
  11. data/app/datatables/effective_mentorships_registrations_datatable.rb +1 -0
  12. data/app/helpers/effective_mentorships_helper.rb +1 -0
  13. data/app/jobs/effective/mentorships_bulk_create_groups_job.rb +10 -0
  14. data/app/jobs/effective/mentorships_bulk_notify_groups_job.rb +10 -0
  15. data/app/mailers/effective/mentorships_mailer.rb +41 -3
  16. data/app/models/concerns/effective_mentorships_bulk_group.rb +368 -0
  17. data/app/models/concerns/effective_mentorships_group.rb +80 -5
  18. data/app/models/concerns/effective_mentorships_registration.rb +69 -8
  19. data/app/models/concerns/effective_mentorships_user.rb +42 -0
  20. data/app/models/effective/mentorship_bulk_group.rb +6 -0
  21. data/app/models/effective/mentorship_cycle.rb +1 -1
  22. data/app/models/effective/mentorship_group_user.rb +15 -0
  23. data/app/views/admin/mentorship_bulk_groups/_content.html.haml +1 -0
  24. data/app/views/admin/mentorship_bulk_groups/_creation.html.haml +9 -0
  25. data/app/views/admin/mentorship_bulk_groups/_layout.html.haml +3 -0
  26. data/app/views/admin/mentorship_bulk_groups/_selection.html.haml +24 -0
  27. data/app/views/admin/mentorship_bulk_groups/finished.html.haml +35 -0
  28. data/app/views/admin/mentorship_bulk_groups/group.html.haml +31 -0
  29. data/app/views/admin/mentorship_bulk_groups/grouping.html.haml +10 -0
  30. data/app/views/admin/mentorship_bulk_groups/notify.html.haml +49 -0
  31. data/app/views/admin/mentorship_bulk_groups/notifying.html.haml +10 -0
  32. data/app/views/admin/mentorship_bulk_groups/publish.html.haml +30 -0
  33. data/app/views/admin/mentorship_bulk_groups/review.html.haml +49 -0
  34. data/app/views/admin/mentorship_bulk_groups/start.html.haml +8 -0
  35. data/app/views/admin/mentorship_cycles/_form_mentorship_cycle.html.haml +0 -4
  36. data/app/views/admin/mentorship_groups/_form_mentorship_group.html.haml +11 -4
  37. data/app/views/effective/mentorship_registrations/_fields.html.haml +2 -2
  38. data/app/views/effective/mentorships/_dashboard.html.haml +1 -1
  39. data/app/views/effective/mentorships_mailer/mentorship_group_created_to_mentee.liquid +14 -0
  40. data/app/views/effective/mentorships_mailer/mentorship_group_created_to_mentor.liquid +14 -0
  41. data/config/effective_mentorships.rb +1 -0
  42. data/config/locales/effective_mentorships.en.yml +1 -0
  43. data/config/routes.rb +12 -5
  44. data/db/migrate/101_create_effective_mentorships.rb +26 -2
  45. data/lib/effective_mentorships/engine.rb +1 -0
  46. data/lib/effective_mentorships/version.rb +1 -1
  47. data/lib/effective_mentorships.rb +6 -2
  48. 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
- acts_as_archived
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
- archived :boolean
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
- validates :title, presence: true, uniqueness: true
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: { greater_than: 0 }, if: -> { opt_in? && mentor? }
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?
@@ -0,0 +1,6 @@
1
+ # Used to create the bulk group of mentorship requests
2
+ module Effective
3
+ class MentorshipBulkGroup < ActiveRecord::Base
4
+ effective_mentorships_bulk_group
5
+ end
6
+ end
@@ -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