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.
Files changed (47) 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/jobs/effective/mentorships_bulk_create_groups_job.rb +10 -0
  13. data/app/jobs/effective/mentorships_bulk_notify_groups_job.rb +10 -0
  14. data/app/mailers/effective/mentorships_mailer.rb +41 -3
  15. data/app/models/concerns/effective_mentorships_bulk_group.rb +368 -0
  16. data/app/models/concerns/effective_mentorships_group.rb +80 -5
  17. data/app/models/concerns/effective_mentorships_registration.rb +69 -8
  18. data/app/models/concerns/effective_mentorships_user.rb +42 -0
  19. data/app/models/effective/mentorship_bulk_group.rb +6 -0
  20. data/app/models/effective/mentorship_cycle.rb +1 -1
  21. data/app/models/effective/mentorship_group_user.rb +15 -0
  22. data/app/views/admin/mentorship_bulk_groups/_content.html.haml +1 -0
  23. data/app/views/admin/mentorship_bulk_groups/_creation.html.haml +9 -0
  24. data/app/views/admin/mentorship_bulk_groups/_layout.html.haml +3 -0
  25. data/app/views/admin/mentorship_bulk_groups/_selection.html.haml +24 -0
  26. data/app/views/admin/mentorship_bulk_groups/finished.html.haml +35 -0
  27. data/app/views/admin/mentorship_bulk_groups/group.html.haml +31 -0
  28. data/app/views/admin/mentorship_bulk_groups/grouping.html.haml +10 -0
  29. data/app/views/admin/mentorship_bulk_groups/notify.html.haml +49 -0
  30. data/app/views/admin/mentorship_bulk_groups/notifying.html.haml +10 -0
  31. data/app/views/admin/mentorship_bulk_groups/publish.html.haml +30 -0
  32. data/app/views/admin/mentorship_bulk_groups/review.html.haml +49 -0
  33. data/app/views/admin/mentorship_bulk_groups/start.html.haml +8 -0
  34. data/app/views/admin/mentorship_cycles/_form_mentorship_cycle.html.haml +0 -4
  35. data/app/views/admin/mentorship_groups/_form_mentorship_group.html.haml +11 -4
  36. data/app/views/effective/mentorship_registrations/_fields.html.haml +2 -2
  37. data/app/views/effective/mentorships/_dashboard.html.haml +1 -1
  38. data/app/views/effective/mentorships_mailer/mentorship_group_created_to_mentee.liquid +14 -0
  39. data/app/views/effective/mentorships_mailer/mentorship_group_created_to_mentor.liquid +14 -0
  40. data/config/effective_mentorships.rb +1 -0
  41. data/config/locales/effective_mentorships.en.yml +1 -0
  42. data/config/routes.rb +12 -5
  43. data/db/migrate/101_create_effective_mentorships.rb +26 -2
  44. data/lib/effective_mentorships/engine.rb +1 -0
  45. data/lib/effective_mentorships/version.rb +1 -1
  46. data/lib/effective_mentorships.rb +6 -2
  47. 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