mumuki-domain 9.20.0 → 9.23.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 444b1f0d9b9045b65edc00adfa94535e351fb2d0c906e1f5f4ddce6a8ae7da8c
4
- data.tar.gz: 9363d9f7b2f7db38f13913a4396417af31583e8d8f45443d3e3792f8add84f8c
3
+ metadata.gz: 91e7710d2d997039351f464c293d25fea0b8de59208431647e209dfaa67dad9c
4
+ data.tar.gz: eb4e1571ef6795874fda3a4871692af496fd322ad00009190cce5d3ee92c4fd2
5
5
  SHA512:
6
- metadata.gz: 1e214a051c3d7ea39244492a5a6ce85e9e96089f0ba7ae880f6a051cb75222bfbf40a643de40b950d7555bff1fe71c3c119561212751626489804eda3c0f7157
7
- data.tar.gz: 8262781e1b3e394c222085f7730a869a37b1b8b7145520c429d02f5fba7997cc719aaa3fc1db54d04fc928ecf47dc612a0cd4b670de8b905fc21bedfecda2416
6
+ metadata.gz: 037fbb869e63fa550782f8fbb5c46993b3b901ca1c529d235f98982d86a450afcb7dcc47b1fd5cf39b2a3349c9993be9adc6c52d0a45cd95729a9b45a5d315ce
7
+ data.tar.gz: e2f2997b8479047321fcad632dabb65d0a4f2e24dabbe820da1150dcf38fc922add4a68666faed106930fb7e2dfe4a4c2cec26d3653cfe7c19bd3fda9ef7e16b
@@ -10,6 +10,6 @@ module Gamified
10
10
  end
11
11
 
12
12
  def net_experience
13
- submission_status.exp_given - top_submission_status.exp_given
13
+ submitter.currently_in_exam? ? 0 : (submission_status.exp_given - top_submission_status.exp_given)
14
14
  end
15
15
  end
@@ -0,0 +1,29 @@
1
+ module WithDeletedUser
2
+ def self.prepended(base)
3
+ super
4
+ base.before_destroy :forbid_destroy!, if: :deleted_user?
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ def deleted_user?
9
+ self == User.deleted_user
10
+ end
11
+
12
+ def abbreviated_name
13
+ return super unless deleted_user?
14
+
15
+ I18n.t(:deleted_user, locale: (Organization.current.locale rescue 'en'))
16
+ end
17
+
18
+ module ClassMethods
19
+ def deleted_user
20
+ @deleted_user ||= User.create_with(@buried_profile).find_or_create_by(uid: 'deleted:shibi')
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def forbid_destroy!
27
+ raise '"Deleted User" shibi cannot be destroyed'
28
+ end
29
+ end
@@ -4,7 +4,7 @@ module WithMessages
4
4
  end
5
5
 
6
6
  def send_question!(question)
7
- message = build_message question.merge(sender: submitter.uid, read: true)
7
+ message = build_message question.merge(sender: submitter, read: true)
8
8
  message.save_and_notify!
9
9
  end
10
10
 
@@ -0,0 +1,14 @@
1
+ module WithScopedQueries::Limit
2
+ def self.query_by(params, current_scope, _)
3
+ if params[:limit].present?
4
+ max_limit = [params[:limit].to_i, 25].min
5
+ current_scope.limit(max_limit)
6
+ else
7
+ current_scope
8
+ end
9
+ end
10
+
11
+ def self.add_queriable_attributes_to(klass, _)
12
+ klass.queriable_attributes.merge!(limit: :limit)
13
+ end
14
+ end
@@ -1,10 +1,14 @@
1
1
  module WithScopedQueries::Page
2
2
  def self.query_by(params, current_scope, _)
3
- page_param = params[:page] || 1
4
- current_scope.page(page_param).per(10)
3
+ if params[:limit].present?
4
+ current_scope
5
+ else
6
+ page_param = params[:page] || 1
7
+ current_scope.page(page_param).per(10)
8
+ end
5
9
  end
6
10
 
7
11
  def self.add_queriable_attributes_to(klass, _)
8
- klass.queriable_attributes.merge!(page: :page)
12
+ klass.queriable_attributes.merge!(page: [:page, :limit])
9
13
  end
10
14
  end
@@ -1,7 +1,7 @@
1
1
  module WithScopedQueries
2
2
  extend ActiveSupport::Concern
3
3
 
4
- SCOPING_METHODS = [Filter, Sort, Page]
4
+ SCOPING_METHODS = [Filter, Sort, Page, Limit]
5
5
 
6
6
  included do
7
7
  class_attribute :queriable_attributes, instance_writer: false
@@ -22,14 +22,16 @@ class Discussion < ApplicationRecord
22
22
  .or(where(responsible_moderator_at: nil)) }
23
23
  scope :pending_review, -> { where(status: :pending_review) }
24
24
  scope :unread_first, -> { includes(:subscriptions).reorder('subscriptions.read', created_at: :desc) }
25
+ scope :by_recent, -> (_) { where('created_at > ?', Time.now - 6.months)}
25
26
 
26
27
  after_create :subscribe_initiator!
27
28
 
28
29
  markdown_on :description
29
30
 
30
31
  sortable :responses_count, :upvotes_count, :created_at, default: :created_at_desc
31
- filterable :status, :language, :requires_attention
32
+ filterable :status, :language, :requires_attention, :recent
32
33
  pageable
34
+ limitable
33
35
 
34
36
  delegate :language, to: :item
35
37
  delegate :to_discussion_status, to: :status
@@ -101,7 +103,7 @@ class Discussion < ApplicationRecord
101
103
  end
102
104
 
103
105
  def submit_message!(message, user)
104
- message.merge!(sender: user.uid)
106
+ message.merge!(sender: user)
105
107
  messages.create(message)
106
108
  user.subscribe_to! self
107
109
  mark_subscriptions_as_unread!(user)
@@ -140,7 +142,7 @@ class Discussion < ApplicationRecord
140
142
  end
141
143
 
142
144
  def responses_count
143
- visible_messages.where.not(sender: initiator.uid).count
145
+ visible_messages.where.not(sender: initiator).count
144
146
  end
145
147
 
146
148
  def has_responses?
@@ -4,18 +4,20 @@ class Message < ApplicationRecord
4
4
  belongs_to :discussion, optional: true
5
5
  belongs_to :assignment, optional: true
6
6
  belongs_to :approved_by, class_name: 'User', optional: true
7
+ belongs_to :sender, class_name: 'User'
7
8
 
8
9
  has_one :exercise, through: :assignment
9
10
 
10
- validates_presence_of :content, :sender
11
+ validates_presence_of :content
11
12
  validate :ensure_contextualized
12
13
 
14
+ before_create :mark_from_moderator!
13
15
  after_save :update_counters_cache!
14
16
 
15
17
  markdown_on :content
16
18
 
17
19
  # Visible messages are those that can be publicly seen
18
- # in forums. non-direct messages are never visible.
20
+ # in forums. Direct messages are never visible.
19
21
  scope :visible, -> () do
20
22
  where.not(deletion_motive: :self_deleted)
21
23
  .or(where(deletion_motive: nil))
@@ -49,19 +51,15 @@ class Message < ApplicationRecord
49
51
  end
50
52
 
51
53
  def from_initiator?
52
- sender_user == discussion&.initiator
54
+ sender == discussion&.initiator
53
55
  end
54
56
 
55
57
  def from_moderator?
56
- sender_user.moderator_here?
58
+ from_moderator || sender.moderator_here?
57
59
  end
58
60
 
59
61
  def from_user?(user)
60
- sender_user == user
61
- end
62
-
63
- def sender_user
64
- User.find_by(uid: sender)
62
+ sender == user
65
63
  end
66
64
 
67
65
  def authorized?(user)
@@ -74,9 +72,10 @@ class Message < ApplicationRecord
74
72
 
75
73
  def to_resource_h
76
74
  as_json(except: [:id, :type, :discussion_id, :approved, :approved_at, :approved_by_id,
77
- :not_actually_a_question, :deletion_motive, :deleted_at, :deleted_by_id],
75
+ :not_actually_a_question, :deletion_motive, :deleted_at, :deleted_by_id,
76
+ :from_moderator, :sender_id],
78
77
  include: {exercise: {only: [:bibliotheca_id]}})
79
- .merge(organization: Organization.current.name)
78
+ .merge(organization: Organization.current.name, sender: sender.uid)
80
79
  end
81
80
 
82
81
  def read!
@@ -103,6 +102,10 @@ class Message < ApplicationRecord
103
102
  approved? || from_moderator?
104
103
  end
105
104
 
105
+ def mark_from_moderator!
106
+ self.from_moderator = from_moderator?
107
+ end
108
+
106
109
  def update_counters_cache!
107
110
  discussion&.update_counters!
108
111
  end
@@ -122,7 +125,7 @@ class Message < ApplicationRecord
122
125
  def self.import_from_resource_h!(resource_h)
123
126
  if resource_h['submission_id'].present?
124
127
  assignment = Assignment.find_by(submission_id: resource_h['submission_id'])
125
- assignment&.receive_answer! sender: resource_h['message']['sender'],
128
+ assignment&.receive_answer! sender: User.locate!(resource_h['message']['sender']),
126
129
  content: resource_h['message']['content']
127
130
  end
128
131
  end
data/app/models/user.rb CHANGED
@@ -6,20 +6,30 @@ class User < ApplicationRecord
6
6
  WithNotifications,
7
7
  WithDiscussionCreation,
8
8
  Awardee,
9
- Disabling,
10
9
  WithTermsAcceptance,
11
10
  WithPreferences,
12
11
  Onomastic,
13
12
  Mumuki::Domain::Helpers::User
14
13
 
14
+ prepend WithDeletedUser
15
+
15
16
  serialize :permissions, Mumukit::Auth::Permissions
16
17
  serialize :ignored_notifications, Array
17
18
 
18
- has_many :notifications
19
- has_many :assignments, foreign_key: :submitter_id
20
- has_many :indicators
21
- has_many :user_stats, class_name: 'UserStats'
22
- has_many :messages, -> { order(created_at: :desc) }, through: :assignments
19
+ before_destroy :clean_belongings!
20
+
21
+ has_many :api_clients, dependent: :delete_all
22
+ has_many :assignments, foreign_key: :submitter_id, dependent: :delete_all
23
+ has_many :certificates, dependent: :delete_all
24
+ has_many :exam_authorizations, dependent: :delete_all
25
+ has_many :exam_authorization_requests, dependent: :delete_all
26
+ has_many :notifications, dependent: :delete_all
27
+ has_many :indicators, dependent: :delete_all
28
+ has_many :user_stats, class_name: 'UserStats', dependent: :delete_all
29
+
30
+ has_many :discussions, foreign_key: :initiator_id
31
+ has_many :forum_messages, -> { where.not(discussion_id: nil) }, class_name: 'Message', foreign_key: :sender_id
32
+ has_many :direct_messages, -> { order(created_at: :desc) }, through: :assignments, source: :messages
23
33
 
24
34
  has_many :submitted_exercises, through: :assignments, class_name: 'Exercise', source: :exercise
25
35
 
@@ -34,12 +44,8 @@ class User < ApplicationRecord
34
44
 
35
45
  has_one :last_guide, through: :last_exercise, source: :guide
36
46
 
37
- has_many :exam_authorizations
38
-
39
47
  has_many :exams, through: :exam_authorizations
40
48
 
41
- has_many :certificates
42
-
43
49
  enum gender: %i(female male other unspecified)
44
50
  belongs_to :avatar, polymorphic: true, optional: true
45
51
 
@@ -61,7 +67,7 @@ class User < ApplicationRecord
61
67
  end
62
68
 
63
69
  def messages_in_organization(organization = Organization.current)
64
- messages.where('assignments.organization': organization)
70
+ direct_messages.where('assignments.organization': organization)
65
71
  end
66
72
 
67
73
  def passed_submissions_count_in(organization)
@@ -141,9 +147,14 @@ class User < ApplicationRecord
141
147
  super.merge(image_url: profile_picture)
142
148
  end
143
149
 
144
- def verify_name!
145
- self.verified_first_name ||= first_name
146
- self.verified_last_name ||= last_name
150
+ def verify_name!(force: false)
151
+ if force
152
+ self.verified_first_name = first_name
153
+ self.verified_last_name = last_name
154
+ else
155
+ self.verified_first_name ||= first_name
156
+ self.verified_last_name ||= last_name
157
+ end
147
158
  save!
148
159
  end
149
160
 
@@ -151,7 +162,6 @@ class User < ApplicationRecord
151
162
  update! accepts_reminders: false
152
163
  end
153
164
 
154
-
155
165
  def attach!(role, course)
156
166
  add_permission! role, course.slug
157
167
  save_and_notify!
@@ -321,7 +331,7 @@ class User < ApplicationRecord
321
331
 
322
332
  target_assignments = assignments.where(location)
323
333
 
324
- messages.where(assignment: target_assignments).delete_all
334
+ direct_messages.where(assignment: target_assignments).delete_all
325
335
 
326
336
  target_assignments.delete_all
327
337
  indicators.where(location).delete_all
@@ -336,6 +346,12 @@ class User < ApplicationRecord
336
346
  ignored_notifications.include? notification.subject
337
347
  end
338
348
 
349
+ def clean_belongings!
350
+ discussions.update_all initiator_id: User.deleted_user.id
351
+ forum_messages.update_all sender_id: User.deleted_user.id
352
+ direct_messages.where(sender: self).delete_all
353
+ end
354
+
339
355
  private
340
356
 
341
357
  def welcome_to_new_organizations!
@@ -371,10 +387,6 @@ class User < ApplicationRecord
371
387
  :uid
372
388
  end
373
389
 
374
- def self.unsubscription_verifier
375
- Rails.application.message_verifier(:unsubscribe)
376
- end
377
-
378
390
  def self.create_if_necessary(user)
379
391
  user[:uid] ||= user[:email]
380
392
  where(uid: user[:uid]).first_or_create(user)
@@ -32,8 +32,8 @@ class UserStats < ApplicationRecord
32
32
 
33
33
  def messages_in_discussions_count(date_range = nil)
34
34
  date_filter = { created_at: date_range }.compact
35
- result = Message.joins(:discussion)
36
- .where({sender: user.uid, deletion_motive: nil, discussions: { organization: organization }}.merge(date_filter))
35
+ result = user.forum_messages.joins(:discussion)
36
+ .where({deletion_motive: nil, discussions: { organization: organization }}.merge(date_filter))
37
37
  .group(:approved)
38
38
  .count
39
39
  unapproved = result[false] || 0
@@ -0,0 +1,5 @@
1
+ class ReferenceSenderViaIdInMessages < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_reference :messages, :sender, index: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddFromModeratorToMessages < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :messages, :from_moderator, :boolean
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class RemoveSenderUidFromMessages < ActiveRecord::Migration[5.1]
2
+ def change
3
+ remove_column :messages, :sender, :string
4
+ end
5
+ end
@@ -1,6 +1,6 @@
1
1
  FactoryBot.define do
2
-
3
2
  factory :message do
4
3
  content { Faker::Lorem.sentence(word_count: 3) }
4
+ sender { create(:user) }
5
5
  end
6
6
  end
@@ -33,8 +33,4 @@ module Mumuki::Domain::Status::Discussion
33
33
  reachable_statuses_for_initiator(discussion)
34
34
  end
35
35
  end
36
-
37
- def as_json(_options={})
38
- to_s
39
- end
40
36
  end
@@ -31,10 +31,6 @@ module Mumuki::Domain::Status::Submission
31
31
  group.iconize
32
32
  end
33
33
 
34
- def as_json(_options={})
35
- to_s
36
- end
37
-
38
34
  def completed?
39
35
  solved?
40
36
  end
@@ -50,8 +46,4 @@ module Mumuki::Domain::Status::Submission
50
46
  def exp_given
51
47
  0
52
48
  end
53
-
54
- def dup
55
- self
56
- end
57
49
  end
@@ -25,6 +25,14 @@ module Mumuki::Domain::Status
25
25
  self.equal? parent.to_mumuki_status(other) rescue false
26
26
  end
27
27
 
28
+ def as_json(_options={})
29
+ to_s
30
+ end
31
+
32
+ def dup
33
+ self
34
+ end
35
+
28
36
  class_methods do
29
37
  def load(i)
30
38
  cast(i)
@@ -1,5 +1,5 @@
1
1
  module Mumuki
2
2
  module Domain
3
- VERSION = '9.20.0'
3
+ VERSION = '9.23.0'
4
4
  end
5
5
  end
data/lib/mumuki/domain.rb CHANGED
@@ -1,4 +1,5 @@
1
- require "mumuki/domain/engine"
1
+ require 'email_validator/strict'
2
+ require 'mumuki/domain/engine'
2
3
 
3
4
  require 'mumukit/core'
4
5
  require 'mumukit/core/activemodel'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mumuki-domain
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.20.0
4
+ version: 9.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Franco Leonardo Bulgarelli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-22 00:00:00.000000000 Z
11
+ date: 2021-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 5.1.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: email_validator
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: mumukit-auth
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -279,6 +293,7 @@ files:
279
293
  - app/models/concerns/with_assignments.rb
280
294
  - app/models/concerns/with_assignments_batch.rb
281
295
  - app/models/concerns/with_case_insensitive_search.rb
296
+ - app/models/concerns/with_deleted_user.rb
282
297
  - app/models/concerns/with_description.rb
283
298
  - app/models/concerns/with_discussion_creation.rb
284
299
  - app/models/concerns/with_discussion_creation/subscription.rb
@@ -306,6 +321,7 @@ files:
306
321
  - app/models/concerns/with_responsible_moderator.rb
307
322
  - app/models/concerns/with_scoped_queries.rb
308
323
  - app/models/concerns/with_scoped_queries/filter.rb
324
+ - app/models/concerns/with_scoped_queries/limit.rb
309
325
  - app/models/concerns/with_scoped_queries/page.rb
310
326
  - app/models/concerns/with_scoped_queries/sort.rb
311
327
  - app/models/concerns/with_slug.rb
@@ -687,6 +703,9 @@ files:
687
703
  - db/migrate/20210719145706_add_new_fields_to_notifications.rb
688
704
  - db/migrate/20210803175124_add_ignored_notifications_to_users.rb
689
705
  - db/migrate/20210929223144_add_authorization_requests_limit_to_exam_registration.rb
706
+ - db/migrate/20211004062332_reference_sender_via_id_in_messages.rb
707
+ - db/migrate/20211020224011_add_from_moderator_to_messages.rb
708
+ - db/migrate/20211104182009_remove_sender_uid_from_messages.rb
690
709
  - lib/mumuki/domain.rb
691
710
  - lib/mumuki/domain/area.rb
692
711
  - lib/mumuki/domain/engine.rb