mumuki-domain 9.12.0 → 9.13.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d20f0f5d9cfe938c4a33f561f9e4df1e5e84ab18296fda644038b87166d631fc
4
- data.tar.gz: bf7adb112a37b84a8fb4f8fa7dc74db1c5df29dc0d8763005256e98e381b7951
3
+ metadata.gz: cce9f2ab048f758a4122c66f8a3da650a28c3a2ef10aefd8887a89091ba7a2af
4
+ data.tar.gz: c55a063f04e3ae7d32750db8b7f520a2bd3f8d37f4411201011fec953ee99079
5
5
  SHA512:
6
- metadata.gz: fbcc0dcdd8fd5134d463f61f18da8dfc872b7142f221f16ea3d99dac828bdbcf628d47b924559ac40e3224597955ad575720dc318b385297509cc3364b5c9897
7
- data.tar.gz: 4a2a358f2b888268d4193b0b9b50873702ac293430c26e5d64576f7c02b185fc4263cbc0b30c02758c611240e9646bb917277ed5ec37951521762db028f0fb52
6
+ metadata.gz: d203713ba3bcb38b7d36971a77718ff3887e82d51199e9423635f62a5a244d75433f5aefb7fbfe9c0994971b178dafc655eae03a4b8c9d48bcd0ccc655785441
7
+ data.tar.gz: c3b3db4bc2faac6b2ec976aa380fdd5ad203ee248f6fc96a7dccee55c58a794d7c7f11944be3ef75f311bd5f791e87590c676192194c3c4247e4dc53a51f67cf
@@ -0,0 +1,22 @@
1
+ class Organization::Status::Base
2
+
3
+ attr_reader :organization
4
+
5
+ implements :teacher_access_mode, :student_access_mode, :ex_student_access_mode, :outsider_access_mode, :validate!
6
+
7
+ def initialize(organization)
8
+ @organization = organization
9
+ end
10
+
11
+ def access_mode(user)
12
+ if user&.teacher_of? organization
13
+ teacher_access_mode(user)
14
+ elsif user&.student_of? organization
15
+ student_access_mode(user)
16
+ elsif user&.ex_student_of? organization
17
+ ex_student_access_mode(user)
18
+ else
19
+ outsider_access_mode(user)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ class Organization::Status::Disabled < Organization::Status::Base
2
+
3
+ def teacher_access_mode(user)
4
+ OrganizationAccessMode::Full.new user, organization
5
+ end
6
+
7
+ def student_access_mode(user)
8
+ OrganizationAccessMode::ReadOnly.new user, organization, :faqs, :profile, :exercises, :discussions
9
+ end
10
+
11
+ def ex_student_access_mode(user)
12
+ OrganizationAccessMode::ReadOnly.new user, organization, :faqs, :profile
13
+ end
14
+
15
+ def outsider_access_mode(user)
16
+ if organization.public?
17
+ OrganizationAccessMode::Gone.new user, organization
18
+ else
19
+ OrganizationAccessMode::Forbidden.new user, organization
20
+ end
21
+ end
22
+
23
+ def validate!(user = nil)
24
+ raise Mumuki::Domain::DisabledOrganizationError unless user
25
+ end
26
+
27
+ end
28
+
@@ -0,0 +1,26 @@
1
+ class Organization::Status::Enabled < Organization::Status::Base
2
+
3
+ def teacher_access_mode(user)
4
+ OrganizationAccessMode::Full.new user, organization
5
+ end
6
+
7
+ def student_access_mode(user)
8
+ OrganizationAccessMode::Full.new user, organization
9
+ end
10
+
11
+ def ex_student_access_mode(user)
12
+ OrganizationAccessMode::ReadOnly.new user, organization, :faqs, :profile, :discussions, exercises: :submitted
13
+ end
14
+
15
+ def outsider_access_mode(user)
16
+ if organization.public?
17
+ OrganizationAccessMode::Full.new user, organization
18
+ else
19
+ OrganizationAccessMode::Forbidden.new user, organization
20
+ end
21
+ end
22
+
23
+ def validate!(_user = nil)
24
+ end
25
+
26
+ end
@@ -0,0 +1,27 @@
1
+ class Organization::Status::InPreparation < Organization::Status::Base
2
+
3
+ def teacher_access_mode(user)
4
+ OrganizationAccessMode::Full.new user, organization
5
+ end
6
+
7
+ def student_access_mode(user)
8
+ OrganizationAccessMode::ComingSoon.new user, organization
9
+ end
10
+
11
+ def ex_student_access_mode(user)
12
+ OrganizationAccessMode::Forbidden.new user, organization
13
+ end
14
+
15
+ def outsider_access_mode(user)
16
+ if organization.public?
17
+ OrganizationAccessMode::ComingSoon.new user, organization
18
+ else
19
+ OrganizationAccessMode::Forbidden.new user, organization
20
+ end
21
+ end
22
+
23
+ def validate!(user = nil)
24
+ raise Mumuki::Domain::UnpreparedOrganizationError unless user
25
+ end
26
+
27
+ end
@@ -30,4 +30,10 @@ module WithAssignments
30
30
  def assignment_for(user, organization=Organization.current)
31
31
  find_assignment_for(user, organization) || user.build_assignment(self, organization)
32
32
  end
33
+
34
+ def has_progress_for?(user, organization)
35
+ user.present? && find_assignment_for(user, organization).present?
36
+ end
37
+
38
+
33
39
  end
@@ -0,0 +1,32 @@
1
+ module WithOrganizationStatus
2
+
3
+ def status
4
+ @status ||= _status
5
+ end
6
+
7
+ def access_mode(user)
8
+ status.access_mode(user)
9
+ end
10
+
11
+ def validate_active!
12
+ status.validate!
13
+ end
14
+
15
+ def validate_active_for!(user)
16
+ status.validate!(user)
17
+ access_mode(user).validate_active!
18
+ end
19
+
20
+ private
21
+
22
+ def _status
23
+ if disabled?
24
+ Organization::Status::Disabled.new self
25
+ elsif in_preparation?
26
+ Organization::Status::InPreparation.new self
27
+ else
28
+ Organization::Status::Enabled.new self
29
+ end
30
+ end
31
+
32
+ end
@@ -7,6 +7,10 @@ module WithProgress
7
7
  progress_for(user, organization).completion_percentage
8
8
  end
9
9
 
10
+ def has_progress_for?(user, organization)
11
+ progress_for(user, organization).persisted?
12
+ end
13
+
10
14
  def dirty_progresses!
11
15
  Indicator.dirty_by_content_change! self
12
16
  end
@@ -6,6 +6,7 @@ class Organization < ApplicationRecord
6
6
  include Mumukit::Login::OrganizationHelpers
7
7
 
8
8
  include WithTargetAudience
9
+ include WithOrganizationStatus
9
10
 
10
11
  serialize :profile, Mumuki::Domain::Organization::Profile
11
12
  serialize :settings, Mumuki::Domain::Organization::Settings
@@ -0,0 +1,2 @@
1
+ module OrganizationAccessMode
2
+ end
@@ -0,0 +1,45 @@
1
+ class OrganizationAccessMode::Base
2
+ attr_reader :user, :organization
3
+
4
+ def initialize(user, organization)
5
+ @user = user
6
+ @organization = organization
7
+ end
8
+
9
+ def validate_active!
10
+ end
11
+
12
+ def faqs_here?
13
+ organization.faqs.present?
14
+ end
15
+
16
+ def submit_solutions_here?
17
+ false
18
+ end
19
+
20
+ def resolve_discussions_here?
21
+ false
22
+ end
23
+
24
+ def discuss_here?
25
+ organization.forum_enabled? && user.discusser_of?(organization) &&
26
+ user.trusted_as_discusser_in?(organization) && !user.banned_from_forum?
27
+ end
28
+
29
+ def show_discussion_element?
30
+ false
31
+ end
32
+
33
+ def show_content_element?
34
+ false
35
+ end
36
+
37
+ def validate_discuss_here!(_discussion)
38
+ raise Mumuki::Domain::ForbiddenError
39
+ end
40
+
41
+ def validate_content_here!(content)
42
+ raise Mumuki::Domain::ForbiddenError unless show_content?(content)
43
+ end
44
+ end
45
+
@@ -0,0 +1,5 @@
1
+ class OrganizationAccessMode::ComingSoon < OrganizationAccessMode::Forbidden
2
+ def validate_active!
3
+ raise Mumuki::Domain::UnpreparedOrganizationError
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ class OrganizationAccessMode::Forbidden < OrganizationAccessMode::Base
2
+ def validate_active!
3
+ raise Mumuki::Domain::ForbiddenError if organization.private? && user.present?
4
+ end
5
+
6
+ def faqs_here?
7
+ false
8
+ end
9
+
10
+ def profile_here?
11
+ false
12
+ end
13
+
14
+ def discuss_here?
15
+ false
16
+ end
17
+
18
+ def show_content?(_content)
19
+ false
20
+ end
21
+
22
+ end
@@ -0,0 +1,28 @@
1
+ class OrganizationAccessMode::Full < OrganizationAccessMode::Base
2
+ def profile_here?
3
+ true
4
+ end
5
+
6
+ def submit_solutions_here?
7
+ true
8
+ end
9
+
10
+ def show_discussion_element?
11
+ true
12
+ end
13
+
14
+ def resolve_discussions_here?
15
+ discuss_here?
16
+ end
17
+
18
+ def validate_discuss_here!(_discussion)
19
+ end
20
+
21
+ def show_content?(_content)
22
+ true
23
+ end
24
+
25
+ def show_content_element?
26
+ true
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ class OrganizationAccessMode::Gone < OrganizationAccessMode::Forbidden
2
+ def validate_active!
3
+ raise Mumuki::Domain::DisabledOrganizationError
4
+ end
5
+ end
@@ -0,0 +1,33 @@
1
+ class OrganizationAccessMode::ReadOnly < OrganizationAccessMode::Base
2
+ def initialize(user, organization, *global_scopes, **specific_scopes)
3
+ super user, organization
4
+ @scopes = global_scopes.map { |scope| [scope, :all] }.to_h.merge specific_scopes
5
+ end
6
+
7
+ def faqs_here?
8
+ has_scope(:faqs) && super
9
+ end
10
+
11
+ def profile_here?
12
+ has_scope(:profile)
13
+ end
14
+
15
+ def discuss_here?
16
+ has_scope(:discussions) && super
17
+ end
18
+
19
+ def validate_discuss_here!(discussion)
20
+ super(discussion) unless discussion&.initiator == user
21
+ end
22
+
23
+ def show_content?(content)
24
+ has_scope(:exercises) ||
25
+ (has_scope(:exercises, :submitted) && content.has_progress_for?(user, organization))
26
+ end
27
+
28
+ private
29
+
30
+ def has_scope(key, value = :all)
31
+ @scopes[key] == value
32
+ end
33
+ end
data/app/models/user.rb CHANGED
@@ -201,7 +201,7 @@ class User < ApplicationRecord
201
201
  # This is true only when this organization has the forum enabled and the user
202
202
  # has the discusser pseudo-permission and the discusser is trusted
203
203
  def can_discuss_in?(organization)
204
- organization.forum_enabled? && discusser_of?(organization) && trusted_as_discusser_in?(organization) && !banned_from_forum?
204
+ organization.access_mode(self).discuss_here?
205
205
  end
206
206
 
207
207
  def trusted_as_discusser_in?(organization)
@@ -283,6 +283,10 @@ class User < ApplicationRecord
283
283
  }
284
284
  end
285
285
 
286
+ def solved_any_exercises?(organization = Organization.current)
287
+ Assignment.exists?(organization: organization, submitter: self)
288
+ end
289
+
286
290
  def save_and_notify!
287
291
  save!
288
292
  notify_permissions_changed!
@@ -52,11 +52,6 @@ module Mumuki::Domain::Helpers::Organization
52
52
  Mumukit::Platform.application.organic_domain(name)
53
53
  end
54
54
 
55
- def validate_active!
56
- raise Mumuki::Domain::DisabledOrganizationError if disabled?
57
- raise Mumuki::Domain::UnpreparedOrganizationError if in_preparation?
58
- end
59
-
60
55
  ## API Exposure
61
56
 
62
57
  def to_param
@@ -16,6 +16,22 @@ module Mumuki::Domain
16
16
  false
17
17
  end
18
18
 
19
+ def ex_student_of?(*)
20
+ false
21
+ end
22
+
23
+ def ex_student_here?
24
+ false
25
+ end
26
+
27
+ def student_of?(*)
28
+ false
29
+ end
30
+
31
+ def student_here?
32
+ false
33
+ end
34
+
19
35
  def teacher_here?
20
36
  false
21
37
  end
@@ -28,7 +28,7 @@ class Mumuki::Domain::Organization::Settings < Mumukit::Platform::Model
28
28
  end
29
29
 
30
30
  def forum_discussions_minimal_role
31
- (@forum_discussions_minimal_role || 'student').to_sym
31
+ (@forum_discussions_minimal_role || 'ex_student').to_sym
32
32
  end
33
33
 
34
34
  def disabled_from=(disabled_from)
@@ -1,5 +1,5 @@
1
1
  module Mumuki
2
2
  module Domain
3
- VERSION = '9.12.0'
3
+ VERSION = '9.13.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: 9.12.0
4
+ version: 9.13.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-08-12 00:00:00.000000000 Z
11
+ date: 2021-08-19 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.9'
33
+ version: '7.11'
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.9'
40
+ version: '7.11'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mumukit-assistant
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -265,6 +265,10 @@ files:
265
265
  - app/models/concerns/navigation/siblings_navigation.rb
266
266
  - app/models/concerns/navigation/terminal_navigation.rb
267
267
  - app/models/concerns/onomastic.rb
268
+ - app/models/concerns/organization/status/base.rb
269
+ - app/models/concerns/organization/status/disabled.rb
270
+ - app/models/concerns/organization/status/enabled.rb
271
+ - app/models/concerns/organization/status/in_preparation.rb
268
272
  - app/models/concerns/submittable/confirmable.rb
269
273
  - app/models/concerns/submittable/queriable.rb
270
274
  - app/models/concerns/submittable/questionable.rb
@@ -292,6 +296,7 @@ files:
292
296
  - app/models/concerns/with_name.rb
293
297
  - app/models/concerns/with_notifications.rb
294
298
  - app/models/concerns/with_number.rb
299
+ - app/models/concerns/with_organization_status.rb
295
300
  - app/models/concerns/with_pg_lock.rb
296
301
  - app/models/concerns/with_preferences.rb
297
302
  - app/models/concerns/with_profile.rb
@@ -336,6 +341,13 @@ files:
336
341
  - app/models/message.rb
337
342
  - app/models/notification.rb
338
343
  - app/models/organization.rb
344
+ - app/models/organization_access_mode.rb
345
+ - app/models/organization_access_mode/base.rb
346
+ - app/models/organization_access_mode/coming_soon.rb
347
+ - app/models/organization_access_mode/forbidden.rb
348
+ - app/models/organization_access_mode/full.rb
349
+ - app/models/organization_access_mode/gone.rb
350
+ - app/models/organization_access_mode/read_only.rb
339
351
  - app/models/preferences.rb
340
352
  - app/models/progress.rb
341
353
  - app/models/stats.rb