mumuki-domain 7.11.0 → 8.0.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: 17efbb5ea487285cf39720f0f3bcaab94641669a8f0ba83c78b8931c8ff949b2
4
- data.tar.gz: a6213b8093643e8112ffc85609fbae72c871c343f9374e17ba024ee1b9eb73c3
3
+ metadata.gz: 2e3057a4511ba66a280fe3f5bf53052a33161ecd9a45dfb6851d2dc21ea7ad20
4
+ data.tar.gz: bb89fde6326417de9590369040b1d61a13ec35ea1abe8d365c0d21aa66777315
5
5
  SHA512:
6
- metadata.gz: 821da987d9bc224d803554e8f44f54c200f5dcc9fd38ad90a793e5fb640ad946cf059276a534d8004a84386f2ef75fa448b666b4054049b48dbfb8e76bcce32e
7
- data.tar.gz: 4b92ea6a719cd03dc2b3c9e338cdb470b86a22f9764b0dff4a61f9a5173bee1d389de9d7396cf55b78cf23d63222ecaca6be6ccf14e2cc83d7de0cabc57a090b
6
+ metadata.gz: 586446caac1b0eeecf18d5754e1fb1120e1d0f5a87a4d386152f64af9d6f0b5f18b089676cc994c7f717baa3382b120d7ea71e011263e8761ad5b830dbfefb02
7
+ data.tar.gz: 77d0ddcfaea1ffaae2d22e5cb7e9b30e08b3d6ef4d303fad9df0062294353dab7834f35fd8fdf339fa770cc233c293f6bf6173442262f11e98eef2521bf3d952
@@ -70,9 +70,8 @@ class ApplicationRecord < ActiveRecord::Base
70
70
  end
71
71
 
72
72
  def update_and_notify!(data)
73
- update! data
74
- notify!
75
- self
73
+ assign_attributes data
74
+ save_and_notify!
76
75
  end
77
76
 
78
77
  def self.aggregate_of(association)
@@ -105,7 +104,7 @@ class ApplicationRecord < ActiveRecord::Base
105
104
  obj
106
105
  end
107
106
 
108
- def self.whitelist_attributes(a_hash, options={})
107
+ def self.whitelist_attributes(a_hash, options = {})
109
108
  attributes = attribute_names
110
109
  attributes += reflections.keys if options[:relations]
111
110
  a_hash.with_indifferent_access.slice(*attributes).except(*options[:except])
@@ -52,6 +52,14 @@ class Assignment < Progress
52
52
  self.organization = Organization.current
53
53
  end
54
54
 
55
+ def recontextualize!
56
+ if organization != Organization.current
57
+ dirty_parent_by_submission! if organization.present? && exercise.used_in?(organization)
58
+ self.organization = Organization.current
59
+ self.parent_id = nil
60
+ end
61
+ end
62
+
55
63
  def set_default_top_submission_status
56
64
  self.top_submission_status ||= 0
57
65
  end
@@ -145,6 +153,10 @@ class Assignment < Progress
145
153
  end
146
154
  end
147
155
 
156
+ def manual_evaluation_pending!
157
+ update! submission_status: :manual_evaluation_pending
158
+ end
159
+
148
160
  def passed!
149
161
  update! submission_status: :passed
150
162
  end
@@ -0,0 +1,65 @@
1
+ module WithTermsAcceptance
2
+ def has_forum_terms_to_accept?
3
+ !has_accepted_all?(forum_terms)
4
+ end
5
+
6
+ def has_profile_terms_to_accept?
7
+ !has_accepted_all?(profile_terms)
8
+ end
9
+
10
+ def has_role_terms_to_accept?
11
+ !has_accepted_all?(role_specific_terms)
12
+ end
13
+
14
+ def role_specific_terms
15
+ @role_specific_terms ||= Term.role_specific_terms_for(self)
16
+ end
17
+
18
+ def forum_terms
19
+ @forum_terms ||= Term.forum_related_terms
20
+ end
21
+
22
+ def profile_terms
23
+ @profile_terms ||= Term.profile_terms_for(self)
24
+ end
25
+
26
+ def accept_profile_terms!
27
+ accept_terms! profile_terms
28
+ end
29
+
30
+ def accept_forum_terms!
31
+ accept_terms! forum_terms
32
+ end
33
+
34
+ def has_accepted?(term)
35
+ term_accepted_at_for(term.scope).try { |it| it > term.updated_at }.present?
36
+ end
37
+
38
+ private
39
+
40
+ def unaccepted_terms_in(terms)
41
+ terms.reject { |term| has_accepted? term}
42
+ end
43
+
44
+ def unaccepted_terms_scopes_in(terms)
45
+ unaccepted_terms_in(terms).map(&:scope)
46
+ end
47
+
48
+ def has_accepted_all?(terms)
49
+ unaccepted_terms_in(terms).blank?
50
+ end
51
+
52
+ def term_accepted_at_for(role)
53
+ send term_acceptance_field_for(role)
54
+ end
55
+
56
+ def term_acceptance_field_for(role)
57
+ "#{role}_terms_accepted_at"
58
+ end
59
+
60
+ def accept_terms!(terms)
61
+ update! unaccepted_terms_scopes_in(terms).to_h { |scope| [term_acceptance_field_for(scope), Time.now] }
62
+ end
63
+
64
+ end
65
+
@@ -5,7 +5,7 @@ class Exam < ApplicationRecord
5
5
  include TerminalNavigation
6
6
 
7
7
  belongs_to :organization
8
- belongs_to :course, optional: true
8
+ belongs_to :course
9
9
 
10
10
  has_many :authorizations, class_name: 'ExamAuthorization', dependent: :destroy
11
11
  has_many :users, through: :authorizations
@@ -186,8 +186,6 @@ class Exam < ApplicationRecord
186
186
  exam[:start_time] = exam[:start_time].to_time
187
187
  exam[:end_time] = exam[:end_time].to_time
188
188
  exam[:classroom_id] = exam[:eid] if exam[:eid].present?
189
- exam[:passing_criterion_type] = exam.dig(:passing_criterion, :type)
190
- exam[:passing_criterion_value] = exam.dig(:passing_criterion, :value)
191
189
  end
192
190
 
193
191
  def self.remove_previous_version(eid, guide_id)
@@ -51,7 +51,10 @@ class Guide < Content
51
51
  joins("left join public.assignments assignments
52
52
  on assignments.exercise_id = exercises.id
53
53
  and assignments.submitter_id = #{user.id}
54
- and assignments.submission_status = #{Mumuki::Domain::Status::Submission::Passed.to_i}").
54
+ and assignments.submission_status in (
55
+ #{Mumuki::Domain::Status::Submission::Passed.to_i},
56
+ #{Mumuki::Domain::Status::Submission::ManualEvaluationPending.to_i}
57
+ )").
55
58
  where('assignments.id is null')
56
59
  end
57
60
 
@@ -0,0 +1,40 @@
1
+ class Term < ApplicationRecord
2
+ attribute :locale, :string, default: 'es'
3
+ markdown_on :content
4
+
5
+ GENERAL = %w(legal privacy student)
6
+ ROLE_SPECIFIC = %w(headmaster janitor teacher moderator)
7
+ FORUM_RELATED = %w(forum)
8
+
9
+ validates :locale, uniqueness: { scope: :scope }
10
+ validates :content, :scope, :header, presence: true
11
+
12
+ def self.terms_for(scope, locale)
13
+ where(scope: scope, locale: locale)
14
+ end
15
+
16
+ def self.profile_terms_for(user, locale = I18n.locale)
17
+ general_terms(locale) + role_specific_terms_for(user, locale)
18
+ end
19
+
20
+ def self.role_specific_terms_for(user, locale = I18n.locale)
21
+ terms_for(current_role_terms_for(user), locale)
22
+ end
23
+
24
+ def self.general_terms(locale = I18n.locale)
25
+ terms_for(GENERAL, locale)
26
+ end
27
+
28
+ def self.forum_related_terms(locale = I18n.locale)
29
+ terms_for(FORUM_RELATED, locale)
30
+ end
31
+
32
+ def self.current_role_terms_for(user)
33
+ return [] unless user.present?
34
+ (user.any_granted_roles & ROLE_SPECIFIC).to_a
35
+ end
36
+
37
+ def accepted_by?(user)
38
+ user.term_accepted_at_for(scope).try { |it| it > updated_at }.present?
39
+ end
40
+ end
@@ -48,7 +48,10 @@ class Topic < Content
48
48
  joins("left join public.assignments assignments
49
49
  on assignments.exercise_id = exercises.id
50
50
  and assignments.submitter_id = #{user.id}
51
- and assignments.submission_status = #{Mumuki::Domain::Status::Submission::Passed.to_i}").
51
+ and assignments.submission_status in (
52
+ #{Mumuki::Domain::Status::Submission::Passed.to_i},
53
+ #{Mumuki::Domain::Status::Submission::ManualEvaluationPending.to_i}
54
+ )").
52
55
  where('assignments.id is null').
53
56
  group('public.guides.id', 'lessons.number').map(&:lesson)
54
57
  end
@@ -6,12 +6,13 @@ class User < ApplicationRecord
6
6
  WithDiscussionCreation,
7
7
  Awardee,
8
8
  Disabling,
9
+ WithTermsAcceptance,
9
10
  Mumuki::Domain::Helpers::User
10
11
 
11
12
  serialize :permissions, Mumukit::Auth::Permissions
12
13
 
13
- has_many :assignments, foreign_key: :submitter_id
14
14
 
15
+ has_many :assignments, foreign_key: :submitter_id
15
16
  has_many :messages, -> { order(created_at: :desc) }, through: :assignments
16
17
 
17
18
  has_many :submitted_exercises, through: :assignments, class_name: 'Exercise', source: :exercise
@@ -37,6 +38,7 @@ class User < ApplicationRecord
37
38
  before_validation :set_uid!
38
39
  validates :uid, presence: true
39
40
 
41
+ validates :terms_of_service, acceptance: true
40
42
  after_save :welcome_to_new_organizations!, if: :gained_access_to_new_orga?
41
43
  after_initialize :init
42
44
  PLACEHOLDER_IMAGE_URL = 'user_shape.png'.freeze
@@ -137,9 +139,9 @@ class User < ApplicationRecord
137
139
 
138
140
  def interpolations
139
141
  {
140
- 'user_email' => email,
141
- 'user_first_name' => first_name,
142
- 'user_last_name' => last_name
142
+ 'user_email' => email,
143
+ 'user_first_name' => first_name,
144
+ 'user_last_name' => last_name
143
145
  }
144
146
  end
145
147
 
@@ -249,6 +251,21 @@ class User < ApplicationRecord
249
251
  end
250
252
  end
251
253
 
254
+ def notify_permissions_changed!
255
+ return if permissions_before_last_save == permissions
256
+ Mumukit::Nuntius.notify! 'user-permissions-changed', user: {
257
+ uid: uid,
258
+ old_permissions: permissions_before_last_save.as_json,
259
+ new_permissions: permissions.as_json
260
+ }
261
+ end
262
+
263
+ def save_and_notify!
264
+ save!
265
+ notify_permissions_changed!
266
+ self
267
+ end
268
+
252
269
  private
253
270
 
254
271
  def welcome_to_new_organizations!
@@ -0,0 +1,14 @@
1
+ class AddTermsForUser < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :users, :headmaster_terms_accepted_at, :datetime
4
+ add_column :users, :janitor_terms_accepted_at, :datetime
5
+ add_column :users, :moderator_terms_accepted_at, :datetime
6
+ add_column :users, :student_terms_accepted_at, :datetime
7
+ add_column :users, :teacher_terms_accepted_at, :datetime
8
+
9
+ add_column :users, :privacy_terms_accepted_at, :datetime
10
+ add_column :users, :legal_terms_accepted_at, :datetime
11
+
12
+ add_column :users, :forum_terms_accepted_at, :datetime
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ class CreateTerms < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :terms do |t|
4
+ t.string :locale
5
+ t.string :scope
6
+ t.text :content
7
+ t.text :header
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -15,6 +15,7 @@ require_relative './factories/login_settings_factory'
15
15
  require_relative './factories/medal_factory'
16
16
  require_relative './factories/message_factory'
17
17
  require_relative './factories/organization_factory'
18
+ require_relative './factories/term_factory'
18
19
  require_relative './factories/topic_factory'
19
20
  require_relative './factories/usage_factory'
20
21
  require_relative './factories/user_factory'
@@ -0,0 +1,7 @@
1
+ FactoryBot.define do
2
+ factory :term do
3
+ content { Faker::Lorem.sentence(word_count: 100) }
4
+ header { Faker::Lorem.sentence(word_count: 5) }
5
+ end
6
+ end
7
+
@@ -41,7 +41,7 @@ module Mumuki::Domain::Helpers::Organization
41
41
  end
42
42
 
43
43
  def url_for(path)
44
- Mumukit::Platform.application.organic_url_for(name, path)
44
+ Mumukit::Platform.laboratory.organic_url_for(name, path)
45
45
  end
46
46
 
47
47
  def url
@@ -8,6 +8,7 @@ module Mumuki::Domain::Helpers::User
8
8
  delegate :has_role?,
9
9
  :add_permission!,
10
10
  :remove_permission!,
11
+ :update_permission!,
11
12
  :has_permission?,
12
13
  :has_permission_delegation?,
13
14
  :protect!,
@@ -15,6 +16,7 @@ module Mumuki::Domain::Helpers::User
15
16
  :protect_permissions_assignment!,
16
17
  :student_granted_organizations,
17
18
  :any_granted_organizations,
19
+ :any_granted_roles,
18
20
  to: :permissions
19
21
 
20
22
  def platform_class_name
@@ -56,6 +56,25 @@ module Mumuki::Domain
56
56
  []
57
57
  end
58
58
 
59
+ def any_granted_roles
60
+ []
61
+ end
62
+
63
+ # ========
64
+ # Terms
65
+ # ========
66
+
67
+ # It avoids role terms acceptance redirections
68
+ def has_role_terms_to_accept?
69
+ false
70
+ end
71
+
72
+ # It makes terms UI to be shown as if no terms were accepted
73
+ # It does not force any term to be accepted though
74
+ def has_accepted?(term)
75
+ false
76
+ end
77
+
59
78
  # ========
60
79
  # Visiting
61
80
  # ========
@@ -36,6 +36,6 @@ class Mumuki::Domain::Organization::Profile < Mumukit::Platform::Model
36
36
  end
37
37
 
38
38
  def open_graph_image_url
39
- @open_graph_image_url ||= Mumukit::Platform.application.url_for("logo-alt.png") # Best image size: 256x256
39
+ @open_graph_image_url ||= Mumukit::Platform.laboratory.url_for("logo-alt.png") # Best image size: 256x256
40
40
  end
41
41
  end
@@ -27,8 +27,10 @@ class Mumuki::Domain::Submission::Base
27
27
  results
28
28
  end
29
29
 
30
- def dry_run!(assignment, evaluation)
31
- evaluation.evaluate! assignment, self
30
+ # By default evaluation strategy is ignored.
31
+ # Subclasses may override this behaviour
32
+ def dry_run!(assignment, _evaluation)
33
+ evaluate! assignment
32
34
  end
33
35
 
34
36
  def with_client_result(result)
@@ -51,7 +53,7 @@ class Mumuki::Domain::Submission::Base
51
53
 
52
54
  def save_submission!(assignment)
53
55
  assignment.content = content
54
- assignment.organization = Organization.current
56
+ assignment.recontextualize!
55
57
  assignment.save!
56
58
  end
57
59
 
@@ -1,6 +1,10 @@
1
1
  class Mumuki::Domain::Submission::Solution < Mumuki::Domain::Submission::PersistentSubmission
2
2
  attr_accessor :content
3
3
 
4
+ def dry_run!(assignment, evaluation)
5
+ evaluation.evaluate! assignment, self
6
+ end
7
+
4
8
  def try_evaluate!(assignment)
5
9
  assignment
6
10
  .run_tests!({client_result: client_result}.compact.merge(content: content))
@@ -1,5 +1,5 @@
1
1
  module Mumuki
2
2
  module Domain
3
- VERSION = '7.11.0'
3
+ VERSION = '8.0.0'
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.11.0
4
+ version: 8.0.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: 2020-10-30 00:00:00.000000000 Z
11
+ date: 2020-11-20 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.8'
33
+ version: '7.9'
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.8'
40
+ version: '7.9'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mumukit-assistant
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '1.13'
89
+ version: '1.18'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '1.13'
96
+ version: '1.18'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: mumukit-directives
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +128,14 @@ dependencies:
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '5.2'
131
+ version: '6.0'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '5.2'
138
+ version: '6.0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: mumukit-sync
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -296,6 +296,7 @@ files:
296
296
  - app/models/concerns/with_scoped_queries/sort.rb
297
297
  - app/models/concerns/with_slug.rb
298
298
  - app/models/concerns/with_target_audience.rb
299
+ - app/models/concerns/with_terms_acceptance.rb
299
300
  - app/models/concerns/with_usages.rb
300
301
  - app/models/concerns/with_user_navigation.rb
301
302
  - app/models/content.rb
@@ -323,6 +324,7 @@ files:
323
324
  - app/models/progress.rb
324
325
  - app/models/stats.rb
325
326
  - app/models/subscription.rb
327
+ - app/models/term.rb
326
328
  - app/models/topic.rb
327
329
  - app/models/upvote.rb
328
330
  - app/models/usage.rb
@@ -627,11 +629,13 @@ files:
627
629
  - db/migrate/20200828162829_add_medal_to_content.rb
628
630
  - db/migrate/20200915123020_add_polymorphic_avatars_to_users.rb
629
631
  - db/migrate/20200915131621_add_once_completed_to_indicators.rb
632
+ - db/migrate/20201007143455_add_terms_for_user.rb
630
633
  - db/migrate/20201009193949_add_status_updated_fields_to_discussion.rb
631
634
  - db/migrate/20201019191036_add_misplaced_flag_to_submission.rb
632
635
  - db/migrate/20201026222942_add_display_name_and_description_to_organizations.rb
633
636
  - db/migrate/20201026225312_add_organization_wins_page_flag.rb
634
637
  - db/migrate/20201027134205_add_immersible_to_organization.rb
638
+ - db/migrate/20201027152806_create_terms.rb
635
639
  - lib/mumuki/domain.rb
636
640
  - lib/mumuki/domain/area.rb
637
641
  - lib/mumuki/domain/engine.rb
@@ -671,6 +675,7 @@ files:
671
675
  - lib/mumuki/domain/factories/medal_factory.rb
672
676
  - lib/mumuki/domain/factories/message_factory.rb
673
677
  - lib/mumuki/domain/factories/organization_factory.rb
678
+ - lib/mumuki/domain/factories/term_factory.rb
674
679
  - lib/mumuki/domain/factories/topic_factory.rb
675
680
  - lib/mumuki/domain/factories/usage_factory.rb
676
681
  - lib/mumuki/domain/factories/user_factory.rb