mumuki-domain 7.7.3 → 7.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/assignment.rb +15 -1
  3. data/app/models/avatar.rb +7 -1
  4. data/app/models/concerns/contextualization.rb +1 -0
  5. data/app/models/concerns/gamified.rb +15 -0
  6. data/app/models/concerns/navigation/siblings_navigation.rb +2 -2
  7. data/app/models/concerns/submittable/submittable.rb +1 -1
  8. data/app/models/concerns/with_assignments.rb +1 -1
  9. data/app/models/concerns/with_progress.rb +1 -1
  10. data/app/models/concerns/with_reminders.rb +1 -1
  11. data/app/models/concerns/with_target_audience.rb +13 -0
  12. data/app/models/guide.rb +1 -1
  13. data/app/models/organization.rb +7 -0
  14. data/app/models/user.rb +81 -5
  15. data/app/models/user_stats.rb +16 -0
  16. data/db/migrate/20200616160640_create_user_stats.rb +10 -0
  17. data/db/migrate/20200617142217_add_top_submission_status_to_assignments.rb +5 -0
  18. data/db/migrate/20200717143830_add_target_audience_to_organizations_and_avatars.rb +6 -0
  19. data/db/migrate/20200804191643_add_incognito_mode_enabled_to_organization.rb +5 -0
  20. data/lib/mumuki/domain.rb +1 -0
  21. data/lib/mumuki/domain/extensions.rb +1 -0
  22. data/lib/mumuki/domain/extensions/time.rb +5 -0
  23. data/lib/mumuki/domain/factories.rb +2 -1
  24. data/lib/mumuki/domain/factories/avatar_factory.rb +6 -0
  25. data/lib/mumuki/domain/factories/user_factory.rb +0 -1
  26. data/lib/mumuki/domain/helpers/organization.rb +4 -0
  27. data/lib/mumuki/domain/helpers/user.rb +6 -10
  28. data/lib/mumuki/domain/incognito.rb +123 -0
  29. data/lib/mumuki/domain/organization/profile.rb +2 -1
  30. data/lib/mumuki/domain/organization/settings.rb +13 -3
  31. data/lib/mumuki/domain/status/submission/passed.rb +4 -0
  32. data/lib/mumuki/domain/status/submission/passed_with_warnings.rb +4 -0
  33. data/lib/mumuki/domain/status/submission/skipped.rb +4 -0
  34. data/lib/mumuki/domain/status/submission/submission.rb +8 -0
  35. data/lib/mumuki/domain/submission/base.rb +5 -1
  36. data/lib/mumuki/domain/version.rb +1 -1
  37. metadata +14 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d90b804c5db198580621210484a9cf0f11fa731691ee6186f98182ca9451dbc
4
- data.tar.gz: 29d6e0e3a262005498185ba6840b1fde83b36d0981c378734022099783981d36
3
+ metadata.gz: 0ebe5d37552a117a8d4ee657170a55eefdea340126a6b44f4a31b670420029b4
4
+ data.tar.gz: 8efe4d2b2e478ee887d7c346031e2b0fc87ea3c243991e6cd8d42909c1b361aa
5
5
  SHA512:
6
- metadata.gz: 81415fdb4e315df30ee1b4556d5cc56fe1252a5bb967fa338606aca498cc7fed213ff54230a5c93e9402a4b2acdd9df86180106ff4d3c1ae04e1aca8448901ec
7
- data.tar.gz: 1296ed07fbc39995631d85b440982b6b8100a46c2b99f7d9c22dbc9a5b5aab1f3544ea833d1646897f6309d38aa0f6a68c7de606290d38f6cc8f1881b54842aa
6
+ metadata.gz: ac6768c2f693a49e9d9d63e4c5c55100d98705edd6e4141b49c69c63078a7a72d7b843be81f289f1ea1770abc464bfa365f4895efa79e7caae2504abadac0db8
7
+ data.tar.gz: 12b89e6ebf0e13bcdb0634eb18abfb96bb816296a482503fe504ad54860993a87b93337593fb9e77a7437907dc88ae1d30916dc104e3d8f4f250ab8272fbef7a
@@ -1,6 +1,7 @@
1
1
  class Assignment < Progress
2
2
  include Contextualization
3
3
  include WithMessages
4
+ include Gamified
4
5
 
5
6
  markdown_on :extra_preview
6
7
 
@@ -41,6 +42,8 @@ class Assignment < Progress
41
42
  alias_method :parent_content, :guide
42
43
  alias_method :user, :submitter
43
44
 
45
+ after_initialize :set_default_top_submission_status
46
+ before_save :award_experience_points!, :update_top_submission!, if: :submission_status_changed?
44
47
  after_save :dirty_parent_by_submission!, if: :completion_changed?
45
48
  before_validation :set_current_organization!, unless: :organization
46
49
 
@@ -49,6 +52,10 @@ class Assignment < Progress
49
52
  self.organization = Organization.current
50
53
  end
51
54
 
55
+ def set_default_top_submission_status
56
+ self.top_submission_status ||= 0
57
+ end
58
+
52
59
  def completion_changed?
53
60
  completed_before_last_save? != completed?
54
61
  end
@@ -161,7 +168,10 @@ class Assignment < Progress
161
168
  end
162
169
 
163
170
  def to_resource_h
164
- as_json(except: %i(exercise_id submission_id organization_id id submitter_id solution created_at updated_at submission_status submitted_at parent_id),
171
+ excluded_fields = %i(created_at exercise_id id organization_id parent_id solution submission_id
172
+ submission_status submitted_at submitter_id top_submission_status updated_at)
173
+
174
+ as_json(except: excluded_fields,
165
175
  include: {
166
176
  guide: {
167
177
  only: [:slug, :name],
@@ -224,6 +234,10 @@ class Assignment < Progress
224
234
  exercise.files_for(current_content)
225
235
  end
226
236
 
237
+ def update_top_submission!
238
+ self.top_submission_status = submission_status unless submission_status.improved_by?(top_submission_status)
239
+ end
240
+
227
241
  private
228
242
 
229
243
  def update_submissions_count!
@@ -1,5 +1,11 @@
1
1
  class Avatar < ApplicationRecord
2
+ include WithTargetAudience
3
+
4
+ def self.sample_for(user)
5
+ with_current_audience_for(user).sample
6
+ end
7
+
2
8
  def self.sample
3
- Avatar.order('RANDOM()').first
9
+ order('RANDOM()').first
4
10
  end
5
11
  end
@@ -16,6 +16,7 @@ module Contextualization
16
16
  end
17
17
 
18
18
  included do
19
+ serialize :top_submission_status, Mumuki::Domain::Status::Submission
19
20
  serialize :submission_status, Mumuki::Domain::Status::Submission
20
21
  validates_presence_of :submission_status
21
22
 
@@ -0,0 +1,15 @@
1
+ module Gamified
2
+ def award_experience_points!
3
+ points = net_experience
4
+
5
+ if points > 0
6
+ stats = UserStats.stats_for(submitter)
7
+ stats.add_exp!(points)
8
+ stats.save!
9
+ end
10
+ end
11
+
12
+ def net_experience
13
+ submission_status.exp_given - top_submission_status.exp_given
14
+ end
15
+ end
@@ -1,11 +1,11 @@
1
1
  module SiblingsNavigation
2
2
 
3
3
  def next_for(user)
4
- pending_siblings_for(user).select { |it| it.number > number }.sort_by(&:number).first
4
+ user.pending_siblings_at(self).select { |it| it.number > number }.sort_by(&:number).first
5
5
  end
6
6
 
7
7
  def restart(user)
8
- pending_siblings_for(user).sort_by(&:number).first
8
+ user.pending_siblings_at(self).sort_by(&:number).first
9
9
  end
10
10
 
11
11
  def siblings
@@ -5,7 +5,7 @@ module Submittable
5
5
 
6
6
  def find_assignment_and_submit!(user, submission)
7
7
  assignment = assignment_for user
8
- results = submission.run! assignment, evaluation_class.new
8
+ results = user.run_submission! submission, assignment, evaluation_class.new
9
9
  [assignment, results]
10
10
  end
11
11
  end
@@ -28,6 +28,6 @@ module WithAssignments
28
28
  end
29
29
 
30
30
  def assignment_for(user, organization=Organization.current)
31
- find_assignment_for(user, organization) || user.assignments.build(exercise: self, organization: organization)
31
+ find_assignment_for(user, organization) || user.build_assignment(self, organization)
32
32
  end
33
33
  end
@@ -1,6 +1,6 @@
1
1
  module WithProgress
2
2
  def progress_for(user, organization)
3
- Indicator.find_or_initialize_by(user: user, organization: organization, content: self)
3
+ user.progress_at(self, organization)
4
4
  end
5
5
 
6
6
  def completion_percentage_for(user, organization=Organization.current)
@@ -9,7 +9,7 @@ module WithReminders
9
9
  end
10
10
 
11
11
  def remind!
12
- build_reminder.deliver
12
+ build_reminder.deliver_now
13
13
  update! last_reminded_date: Time.now
14
14
  end
15
15
 
@@ -0,0 +1,13 @@
1
+ module WithTargetAudience
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ enum target_audience: [:grown_ups, :kids]
6
+ end
7
+
8
+ class_methods do
9
+ def with_current_audience_for(user)
10
+ where(target_audience: user.current_audience)
11
+ end
12
+ end
13
+ end
@@ -42,7 +42,7 @@ class Guide < Content
42
42
  end
43
43
 
44
44
  def next_exercise(user)
45
- pending_exercises(user).order('public.exercises.number asc').first
45
+ user.next_exercise_at(self)
46
46
  end
47
47
 
48
48
  # TODO: Make use of pending_siblings logic
@@ -5,6 +5,8 @@ class Organization < ApplicationRecord
5
5
 
6
6
  include Mumukit::Login::OrganizationHelpers
7
7
 
8
+ include WithTargetAudience
9
+
8
10
  serialize :profile, Mumuki::Domain::Organization::Profile
9
11
  serialize :settings, Mumuki::Domain::Organization::Settings
10
12
  serialize :theme, Mumuki::Domain::Organization::Theme
@@ -18,6 +20,7 @@ class Organization < ApplicationRecord
18
20
  has_many :usages
19
21
 
20
22
  validates_presence_of :contact_email, :locale
23
+ validates_presence_of :welcome_email_template, if: :greet_new_users?
21
24
  validates :name, uniqueness: true,
22
25
  presence: true,
23
26
  format: { with: Mumukit::Platform::Organization.anchored_valid_name_regex }
@@ -127,6 +130,10 @@ class Organization < ApplicationRecord
127
130
  update! progressive_display_lookahead: lookahead
128
131
  end
129
132
 
133
+ def display_name
134
+ name.gsub(/\W/, ' ').titleize
135
+ end
136
+
130
137
  private
131
138
 
132
139
  def ensure_consistent_public_login
@@ -30,15 +30,16 @@ class User < ApplicationRecord
30
30
 
31
31
  has_many :exams, through: :exam_authorizations
32
32
 
33
- after_initialize :init
34
-
35
33
  enum gender: %i(female male other unspecified)
36
-
37
34
  belongs_to :avatar, optional: true
38
35
 
39
36
  before_validation :set_uid!
40
37
  validates :uid, presence: true
41
38
 
39
+ after_save :welcome_to_new_organizations!, if: :gained_access_to_new_orga?
40
+ after_initialize :init
41
+ PLACEHOLDER_IMAGE_URL = 'user_shape.png'.freeze
42
+
42
43
  resource_fields :uid, :social_id, :email, :permissions, :verified_first_name, :verified_last_name, *profile_fields
43
44
 
44
45
  def last_lesson
@@ -145,10 +146,14 @@ class User < ApplicationRecord
145
146
  exams.any? { |e| e.in_progress_for? self }
146
147
  end
147
148
 
148
- def profile_picture
149
+ def custom_profile_picture
149
150
  avatar&.image_url || image_url
150
151
  end
151
152
 
153
+ def profile_picture
154
+ custom_profile_picture || placeholder_image_url
155
+ end
156
+
152
157
  def bury!
153
158
  # TODO change avatar
154
159
  update! self.class.buried_profile.merge(accepts_reminders: false, gender: nil, birthdate: nil)
@@ -185,18 +190,81 @@ class User < ApplicationRecord
185
190
  can_discuss_in? Organization.current
186
191
  end
187
192
 
193
+ def can_access_teacher_info_in?(organization)
194
+ teacher_of?(organization) || organization.teacher_training?
195
+ end
196
+
188
197
  def name_initials
189
198
  name.split.map(&:first).map(&:capitalize).join(' ')
190
199
  end
191
200
 
201
+ def progress_at(content, organization)
202
+ Indicator.find_or_initialize_by(user: self, organization: organization, content: content)
203
+ end
204
+
205
+ def build_assignment(exercise, organization)
206
+ assignments.build(exercise: exercise, organization: organization)
207
+ end
208
+
209
+ def pending_siblings_at(content)
210
+ content.pending_siblings_for(self)
211
+ end
212
+
213
+ def next_exercise_at(guide)
214
+ guide.pending_exercises(self).order('public.exercises.number asc').first
215
+ end
216
+
217
+ def run_submission!(submission, assignment, evaluation)
218
+ submission.run! assignment, evaluation
219
+ end
220
+
221
+ def incognito?
222
+ false
223
+ end
224
+
225
+ def current_audience
226
+ current_organic_context&.target_audience
227
+ end
228
+
229
+ def placeholder_image_url
230
+ PLACEHOLDER_IMAGE_URL
231
+ end
232
+
233
+ def age
234
+ if birthdate.present?
235
+ @age ||= Time.now.round_years_since(birthdate.to_time)
236
+ end
237
+ end
238
+
192
239
  private
193
240
 
241
+ def welcome_to_new_organizations!
242
+ new_accessible_organizations.each do |organization|
243
+ UserMailer.welcome_email(self, organization).deliver_now rescue nil if organization.greet_new_users?
244
+ end
245
+ end
246
+
247
+ def gained_access_to_new_orga?
248
+ new_accessible_organizations.present?
249
+ end
250
+
251
+ def new_accessible_organizations
252
+ return [] unless saved_change_to_permissions?
253
+
254
+ old, new = saved_change_to_permissions
255
+ new_organizations = (new.any_granted_organizations - old.any_granted_organizations).to_a
256
+ Organization.where(name: new_organizations)
257
+ end
258
+
194
259
  def set_uid!
195
260
  self.uid ||= email
196
261
  end
197
262
 
198
263
  def init
199
- self.avatar = Avatar.sample unless profile_picture.present?
264
+ if custom_profile_picture.blank?
265
+ self.avatar = Avatar.sample_for(self)
266
+ save if persisted?
267
+ end
200
268
  end
201
269
 
202
270
  def self.sync_key_id_field
@@ -221,4 +289,12 @@ class User < ApplicationRecord
221
289
  def self.buried_profile
222
290
  (@buried_profile || {}).slice(:first_name, :last_name, :email)
223
291
  end
292
+
293
+ def current_organic_context
294
+ if Organization.current?
295
+ Organization.current
296
+ else
297
+ main_organization
298
+ end
299
+ end
224
300
  end
@@ -0,0 +1,16 @@
1
+ class UserStats < ApplicationRecord
2
+ belongs_to :organization
3
+ belongs_to :user
4
+
5
+ def self.stats_for(user)
6
+ UserStats.find_or_initialize_by(user: user, organization: Organization.current)
7
+ end
8
+
9
+ def self.exp_for(user)
10
+ self.stats_for(user).exp
11
+ end
12
+
13
+ def add_exp!(points)
14
+ self.exp += points
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ class CreateUserStats < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :user_stats do |t|
4
+ t.integer :exp, default: 0
5
+
6
+ t.references :user, index: true
7
+ t.references :organization, index: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ class AddTopSubmissionStatusToAssignments < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :assignments, :top_submission_status, :integer
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class AddTargetAudienceToOrganizationsAndAvatars < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :organizations, :target_audience, :integer, default: 0
4
+ add_column :avatars, :target_audience, :integer, default: 0
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class AddIncognitoModeEnabledToOrganization < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :organizations, :incognito_mode_enabled, :boolean
4
+ end
5
+ end
@@ -26,6 +26,7 @@ Mumukit::Platform.configure do |config|
26
26
  end
27
27
 
28
28
  require_relative './domain/area'
29
+ require_relative './domain/incognito'
29
30
  require_relative './domain/evaluation'
30
31
  require_relative './domain/submission'
31
32
  require_relative './domain/status'
@@ -2,3 +2,4 @@ require_relative './extensions/string'
2
2
  require_relative './extensions/array'
3
3
  require_relative './extensions/module'
4
4
  require_relative './extensions/hash'
5
+ require_relative './extensions/time'
@@ -0,0 +1,5 @@
1
+ class Time
2
+ def round_years_since(another_time)
3
+ (self.to_s(:number).to_i - another_time.to_s(:number).to_i) / 10e9.to_i
4
+ end
5
+ end
@@ -1,5 +1,6 @@
1
1
  require_relative './factories/api_client_factory'
2
2
  require_relative './factories/assignments_factory'
3
+ require_relative './factories/avatar_factory'
3
4
  require_relative './factories/book_factory'
4
5
  require_relative './factories/chapter_factory'
5
6
  require_relative './factories/complement_factory'
@@ -15,4 +16,4 @@ require_relative './factories/message_factory'
15
16
  require_relative './factories/organization_factory'
16
17
  require_relative './factories/topic_factory'
17
18
  require_relative './factories/user_factory'
18
- require_relative './factories/usage_factory'
19
+ require_relative './factories/usage_factory'
@@ -0,0 +1,6 @@
1
+ FactoryBot.define do
2
+ factory :avatar do
3
+ image_url { Faker::Internet.url }
4
+ target_audience { :grown_ups }
5
+ end
6
+ end
@@ -6,6 +6,5 @@ FactoryBot.define do
6
6
  last_name { Faker::Name.last_name }
7
7
  gender { 1 }
8
8
  birthdate { Date.today }
9
- avatar { Avatar.new image_url: 'user_shape.png' }
10
9
  end
11
10
  end
@@ -66,6 +66,10 @@ module Mumuki::Domain::Helpers::Organization
66
66
  Mumukit::Platform::Organization.current
67
67
  end
68
68
 
69
+ def current?
70
+ Mumukit::Platform::Organization.current?
71
+ end
72
+
69
73
  def parse(json)
70
74
  json
71
75
  .slice(:name)
@@ -13,6 +13,8 @@ module Mumuki::Domain::Helpers::User
13
13
  :protect!,
14
14
  :protect_delegation!,
15
15
  :protect_permissions_assignment!,
16
+ :student_granted_organizations,
17
+ :any_granted_organizations,
16
18
  to: :permissions
17
19
 
18
20
  def platform_class_name
@@ -71,12 +73,10 @@ module Mumuki::Domain::Helpers::User
71
73
  "#{full_name} <#{email}> [#{uid}]"
72
74
  end
73
75
 
74
- ## Accesible organizations
76
+ ## Accessible organizations
75
77
 
76
- def student_granted_organizations
77
- permissions.student_granted_organizations.map do |org|
78
- Mumukit::Platform::Organization.find_by_name!(org) rescue nil
79
- end.compact
78
+ revamp_accessor :any_granted_organizations, :student_granted_organizations do |_, _, result|
79
+ result.map { |org| Mumukit::Platform::Organization.find_by_name!(org) rescue nil }.compact
80
80
  end
81
81
 
82
82
  def has_student_granted_organizations?
@@ -84,11 +84,7 @@ module Mumuki::Domain::Helpers::User
84
84
  end
85
85
 
86
86
  def main_organization
87
- student_granted_organizations.first
88
- end
89
-
90
- def has_main_organization?
91
- student_granted_organizations.length == 1
87
+ student_granted_organizations.first || any_granted_organizations.first
92
88
  end
93
89
 
94
90
  def has_immersive_main_organization?
@@ -0,0 +1,123 @@
1
+ module Mumuki::Domain
2
+ class IncognitoClass
3
+
4
+ def incognito?
5
+ true
6
+ end
7
+
8
+ # ============
9
+ # Permissions
10
+ # ============
11
+
12
+ def ensure_enabled!
13
+ end
14
+
15
+ def has_student_granted_organizations?
16
+ false
17
+ end
18
+
19
+ def teacher_here?
20
+ false
21
+ end
22
+
23
+ def teacher_of?(*)
24
+ false
25
+ end
26
+
27
+ def profile_completed?
28
+ true
29
+ end
30
+
31
+ def writer?
32
+ false
33
+ end
34
+
35
+ def moderator_here?
36
+ false
37
+ end
38
+
39
+ def can_discuss_here?
40
+ false
41
+ end
42
+
43
+ def can_discuss_in?(*)
44
+ false
45
+ end
46
+
47
+ def can_access_teacher_info_in?(*)
48
+ false
49
+ end
50
+
51
+ # ========
52
+ # Visiting
53
+ # ========
54
+
55
+ def visit!(*)
56
+ end
57
+
58
+ # ========
59
+ # Progress
60
+ # ========
61
+
62
+ def next_exercise_at(guide)
63
+ guide.exercises.first
64
+ end
65
+
66
+ # def completed_containers_with_lookahead(*)
67
+ # raise 'Unsupported operation. Userless mode and progressive display modes are incompatible'
68
+ # end
69
+
70
+ def progress_at(content, organization)
71
+ Indicator.new content: content, organization: organization
72
+ end
73
+
74
+ def build_assignment(exercise, organization)
75
+ Assignment.new exercise: exercise, organization: organization, submitter: self
76
+ end
77
+
78
+ def pending_siblings_at(content)
79
+ []
80
+ end
81
+
82
+ # ============
83
+ # ActiveRecord
84
+ # ============
85
+
86
+ def id
87
+ '<incognito>'
88
+ end
89
+
90
+ def is_a?(other)
91
+ other.is_a?(Class) && other.name == 'User' || super
92
+ end
93
+
94
+ def _read_attribute(key)
95
+ return id if key == 'id'
96
+ raise "unknown attribute #{key}"
97
+ end
98
+
99
+ def new_record?
100
+ false
101
+ end
102
+
103
+ def self.primary_key
104
+ 'id'
105
+ end
106
+
107
+ # ==========
108
+ # Evaluation
109
+ # ==========
110
+
111
+ def interpolations
112
+ []
113
+ end
114
+
115
+ def run_submission!(submission, assignment, evaluation)
116
+ results = submission.dry_run! assignment, evaluation
117
+ assignment.assign_attributes results
118
+ results
119
+ end
120
+ end
121
+
122
+ Incognito = IncognitoClass.new
123
+ end
@@ -11,7 +11,8 @@ class Mumuki::Domain::Organization::Profile < Mumukit::Platform::Model
11
11
  :contact_email,
12
12
  :terms_of_service,
13
13
  :community_link,
14
- :errors_explanations
14
+ :errors_explanations,
15
+ :welcome_email_template
15
16
 
16
17
  def locale_json
17
18
  locale_h.to_json
@@ -8,6 +8,7 @@ class Mumuki::Domain::Organization::Settings < Mumukit::Platform::Model
8
8
  :forum_enabled?,
9
9
  :forum_only_for_trusted?,
10
10
  :gamification_enabled?,
11
+ :greet_new_users?,
11
12
  :immersive?,
12
13
  :in_preparation_until,
13
14
  :login_methods,
@@ -15,7 +16,8 @@ class Mumuki::Domain::Organization::Settings < Mumukit::Platform::Model
15
16
  :login_provider_settings,
16
17
  :public?,
17
18
  :raise_hand_enabled?,
18
- :report_issue_enabled?
19
+ :report_issue_enabled?,
20
+ :teacher_training?
19
21
 
20
22
  def private?
21
23
  !public?
@@ -29,11 +31,19 @@ class Mumuki::Domain::Organization::Settings < Mumukit::Platform::Model
29
31
  (@forum_discussions_minimal_role || 'student').to_sym
30
32
  end
31
33
 
34
+ def disabled_from=(disabled_from)
35
+ @disabled_from = disabled_from&.to_time
36
+ end
37
+
38
+ def in_preparation_until=(in_preparation_until)
39
+ @in_preparation_until = in_preparation_until&.to_time
40
+ end
41
+
32
42
  def disabled?
33
- disabled_from.present? && disabled_from.to_datetime < DateTime.now
43
+ disabled_from.present? && disabled_from < Time.now
34
44
  end
35
45
 
36
46
  def in_preparation?
37
- in_preparation_until.present? && in_preparation_until.to_datetime > DateTime.now
47
+ in_preparation_until.present? && in_preparation_until > Time.now
38
48
  end
39
49
  end
@@ -8,4 +8,8 @@ module Mumuki::Domain::Status::Submission::Passed
8
8
  def self.iconize
9
9
  {class: :success, type: 'check-circle'}
10
10
  end
11
+
12
+ def self.exp_given
13
+ 100
14
+ end
11
15
  end
@@ -12,4 +12,8 @@ module Mumuki::Domain::Status::Submission::PassedWithWarnings
12
12
  def self.iconize
13
13
  {class: :warning, type: 'exclamation-circle'}
14
14
  end
15
+
16
+ def self.exp_given
17
+ 50
18
+ end
15
19
  end
@@ -8,4 +8,8 @@ module Mumuki::Domain::Status::Submission::Skipped
8
8
  def self.iconize
9
9
  {class: :success, type: 'check-circle'}
10
10
  end
11
+
12
+ def self.exp_given
13
+ 100
14
+ end
11
15
  end
@@ -42,4 +42,12 @@ module Mumuki::Domain::Status::Submission
42
42
  def solved?
43
43
  passed? || skipped?
44
44
  end
45
+
46
+ def improved_by?(status)
47
+ self.exp_given < status.exp_given
48
+ end
49
+
50
+ def exp_given
51
+ 0
52
+ end
45
53
  end
@@ -21,12 +21,16 @@ class Mumuki::Domain::Submission::Base
21
21
 
22
22
  def run!(assignment, evaluation)
23
23
  save_submission! assignment
24
- results = evaluation.evaluate! assignment, self
24
+ results = dry_run! assignment, evaluation
25
25
  save_results! results, assignment
26
26
  notify_results! results, assignment
27
27
  results
28
28
  end
29
29
 
30
+ def dry_run!(assignment, evaluation)
31
+ evaluation.evaluate! assignment, self
32
+ end
33
+
30
34
  def with_client_result(result)
31
35
  self.client_result = result if result.present?
32
36
  self
@@ -1,5 +1,5 @@
1
1
  module Mumuki
2
2
  module Domain
3
- VERSION = '7.7.3'
3
+ VERSION = '7.9.2'
4
4
  end
5
5
  end
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: 7.7.3
4
+ version: 7.9.2
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: 2020-08-31 00:00:00.000000000 Z
11
+ date: 2020-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '7.6'
33
+ version: '7.8'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '7.6'
40
+ version: '7.8'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mumukit-assistant
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -256,6 +256,7 @@ files:
256
256
  - app/models/concerns/contextualization.rb
257
257
  - app/models/concerns/disabling.rb
258
258
  - app/models/concerns/friendly_name.rb
259
+ - app/models/concerns/gamified.rb
259
260
  - app/models/concerns/guide_container.rb
260
261
  - app/models/concerns/navigation/parent_navigation.rb
261
262
  - app/models/concerns/navigation/siblings_navigation.rb
@@ -292,6 +293,7 @@ files:
292
293
  - app/models/concerns/with_scoped_queries/page.rb
293
294
  - app/models/concerns/with_scoped_queries/sort.rb
294
295
  - app/models/concerns/with_slug.rb
296
+ - app/models/concerns/with_target_audience.rb
295
297
  - app/models/concerns/with_usages.rb
296
298
  - app/models/concerns/with_user_navigation.rb
297
299
  - app/models/content.rb
@@ -322,6 +324,7 @@ files:
322
324
  - app/models/upvote.rb
323
325
  - app/models/usage.rb
324
326
  - app/models/user.rb
327
+ - app/models/user_stats.rb
325
328
  - app/models/with_stats.rb
326
329
  - db/migrate/20141120231135_create_exercises.rb
327
330
  - db/migrate/20141120231735_create_submissions.rb
@@ -608,11 +611,15 @@ files:
608
611
  - db/migrate/20200601203033_add_course_to_exam.rb
609
612
  - db/migrate/20200605161350_add_passing_criterions_to_exam.rb
610
613
  - db/migrate/20200608132959_add_progressive_display_lookahead_to_organizations.rb
614
+ - db/migrate/20200616160640_create_user_stats.rb
615
+ - db/migrate/20200617142217_add_top_submission_status_to_assignments.rb
611
616
  - db/migrate/20200702165503_add_messages_count_to_discussion.rb
617
+ - db/migrate/20200717143830_add_target_audience_to_organizations_and_avatars.rb
612
618
  - db/migrate/20200728162727_add_not_actually_a_question_field_to_messages.rb
613
619
  - db/migrate/20200728163038_add_requires_moderator_response_to_discussions.rb
614
620
  - db/migrate/20200730221001_add_trusted_for_forum_to_user.rb
615
621
  - db/migrate/20200731081757_add_last_moderator_access_fields_to_discussion.rb
622
+ - db/migrate/20200804191643_add_incognito_mode_enabled_to_organization.rb
616
623
  - lib/mumuki/domain.rb
617
624
  - lib/mumuki/domain/area.rb
618
625
  - lib/mumuki/domain/engine.rb
@@ -633,9 +640,11 @@ files:
633
640
  - lib/mumuki/domain/extensions/hash.rb
634
641
  - lib/mumuki/domain/extensions/module.rb
635
642
  - lib/mumuki/domain/extensions/string.rb
643
+ - lib/mumuki/domain/extensions/time.rb
636
644
  - lib/mumuki/domain/factories.rb
637
645
  - lib/mumuki/domain/factories/api_client_factory.rb
638
646
  - lib/mumuki/domain/factories/assignments_factory.rb
647
+ - lib/mumuki/domain/factories/avatar_factory.rb
639
648
  - lib/mumuki/domain/factories/book_factory.rb
640
649
  - lib/mumuki/domain/factories/chapter_factory.rb
641
650
  - lib/mumuki/domain/factories/complement_factory.rb
@@ -657,6 +666,7 @@ files:
657
666
  - lib/mumuki/domain/helpers/course.rb
658
667
  - lib/mumuki/domain/helpers/organization.rb
659
668
  - lib/mumuki/domain/helpers/user.rb
669
+ - lib/mumuki/domain/incognito.rb
660
670
  - lib/mumuki/domain/locales/activerecord/en.yml
661
671
  - lib/mumuki/domain/locales/activerecord/es-CL.yml
662
672
  - lib/mumuki/domain/locales/activerecord/es.yml