mumuki-domain 6.5.1 → 6.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/application_record.rb +8 -0
- data/app/models/assignment.rb +3 -3
- data/app/models/book.rb +1 -0
- data/app/models/concerns/syncable.rb +0 -5
- data/app/models/concerns/with_discussion_creation/subscription.rb +6 -2
- data/app/models/concerns/with_discussion_creation.rb +1 -0
- data/app/models/concerns/with_discussions.rb +3 -2
- data/app/models/concerns/with_slug.rb +6 -2
- data/app/models/concerns/with_usages.rb +2 -1
- data/app/models/course.rb +1 -1
- data/app/models/discussion.rb +5 -4
- data/app/models/exam.rb +5 -1
- data/app/models/exercise.rb +20 -4
- data/app/models/guide.rb +8 -1
- data/app/models/invitation.rb +1 -1
- data/app/models/message.rb +1 -1
- data/app/models/organization.rb +16 -3
- data/app/models/user.rb +1 -1
- data/db/migrate/20190326152631_add_settings_to_content.rb +6 -0
- data/db/migrate/20190404181724_add_organization_to_discussion.rb +5 -0
- data/lib/mumuki/domain/status/discussion/discussion.rb +2 -2
- data/lib/mumuki/domain/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0fe12401571cc46abe567d3337c252fcbf0d9a974f37ad207b3d424086b95b7c
|
4
|
+
data.tar.gz: dbc42a3ada461878dd43b5eb8dc14d0ec449349099b01a0b80dbf428f08edcdf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c228e0879bfc3c4e74013e21a5a8f5e5656e4c2da491b340fd89d24ab7bcc015735d42ad8ca66a2a54662a5ba0a15cf1c1a8ba53d145fbe6c8ce76da69815b81
|
7
|
+
data.tar.gz: 6bf1b18815eda0d228a78c6471b6e6d786358dbd1e94ba951d480e830eb03163c83182022bcdd4eeec15fb99ba2e774cfd6947d3f0562ba9277182d297e4a9c3
|
@@ -101,6 +101,14 @@ class ApplicationRecord < ActiveRecord::Base
|
|
101
101
|
a_hash.with_indifferent_access.slice(*attributes).except(*options[:except])
|
102
102
|
end
|
103
103
|
|
104
|
+
def self.organic_on(*selectors)
|
105
|
+
selectors.each do |selector|
|
106
|
+
define_method("#{selector}_in_organization") do |organization = Organization.current|
|
107
|
+
send(selector).where(organization: organization)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
104
112
|
private
|
105
113
|
|
106
114
|
def raise_foreign_key_error!
|
data/app/models/assignment.rb
CHANGED
@@ -16,7 +16,7 @@ class Assignment < ApplicationRecord
|
|
16
16
|
|
17
17
|
validates_presence_of :exercise, :submitter
|
18
18
|
|
19
|
-
delegate :language, :name, :navigable_parent,
|
19
|
+
delegate :language, :name, :navigable_parent, :settings,
|
20
20
|
:limited?, :input_kids?, :choice?, to: :exercise
|
21
21
|
|
22
22
|
alias_attribute :status, :submission_status
|
@@ -118,11 +118,11 @@ class Assignment < ApplicationRecord
|
|
118
118
|
|
119
119
|
%w(query try).each do |key|
|
120
120
|
name = "run_#{key}!"
|
121
|
-
define_method(name) { |params| exercise.send name, params.merge(extra: extra) }
|
121
|
+
define_method(name) { |params| exercise.send name, params.merge(extra: extra, settings: settings) }
|
122
122
|
end
|
123
123
|
|
124
124
|
def run_tests!(params)
|
125
|
-
exercise.run_tests! params.merge(extra: extra, test: test)
|
125
|
+
exercise.run_tests! params.merge(extra: extra, test: test, settings: settings)
|
126
126
|
end
|
127
127
|
|
128
128
|
def to_resource_h
|
data/app/models/book.rb
CHANGED
@@ -59,11 +59,6 @@ module Syncable
|
|
59
59
|
find_or_initialize_by sync_key_id_field => sync_key_id
|
60
60
|
end
|
61
61
|
|
62
|
-
# `locate_resource` is a helpful method that can be used
|
63
|
-
# outside the `Mumukit::Sync` context, thus this mixin provide
|
64
|
-
# a shorter alias
|
65
|
-
alias_method :locate, :locate_resource
|
66
|
-
|
67
62
|
# `locate!` is similar to `locate`, but fails instead of creating a
|
68
63
|
# a new object when not found
|
69
64
|
#
|
@@ -2,9 +2,13 @@ module WithDiscussionCreation::Subscription
|
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
4
|
included do
|
5
|
-
has_many :discussions, foreign_key: 'initiator_id'
|
6
5
|
has_many :subscriptions
|
7
6
|
has_many :watched_discussions, through: :subscriptions, source: :discussion
|
7
|
+
organic_on :watched_discussions
|
8
|
+
end
|
9
|
+
|
10
|
+
def subscriptions_in_organization
|
11
|
+
subscriptions.joins(:discussion).where(discussion: discussions_in_organization)
|
8
12
|
end
|
9
13
|
|
10
14
|
def subscribed_to?(discussion)
|
@@ -28,6 +32,6 @@ module WithDiscussionCreation::Subscription
|
|
28
32
|
end
|
29
33
|
|
30
34
|
def unread_discussions
|
31
|
-
|
35
|
+
subscriptions_in_organization.where(read: false).map(&:discussion)
|
32
36
|
end
|
33
37
|
end
|
@@ -3,10 +3,11 @@ module WithDiscussions
|
|
3
3
|
|
4
4
|
included do
|
5
5
|
has_many :discussions, as: :item, dependent: :destroy
|
6
|
+
organic_on :discussions
|
6
7
|
end
|
7
8
|
|
8
|
-
def discuss!(user, discussion)
|
9
|
-
discussion.merge!(initiator_id: user.id)
|
9
|
+
def discuss!(user, discussion, organization = Organization.current)
|
10
|
+
discussion.merge!(initiator_id: user.id, organization: organization)
|
10
11
|
discussion.merge!(submission: submission_for(user)) if submission_for(user).present?
|
11
12
|
created_discussion = discussions.create discussion
|
12
13
|
user.subscribe_to! created_discussion
|
@@ -8,11 +8,15 @@ module WithSlug
|
|
8
8
|
before_create :normalize_slug!
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
11
|
+
def transparent_params
|
12
12
|
org, repo = slug.split('/')
|
13
13
|
{organization: org, repository: repo}
|
14
14
|
end
|
15
15
|
|
16
|
+
def transparent_id
|
17
|
+
slug
|
18
|
+
end
|
19
|
+
|
16
20
|
def normalize_slug!
|
17
21
|
self.slug = self.slug.to_mumukit_slug.normalize.to_s
|
18
22
|
end
|
@@ -40,7 +44,7 @@ module WithSlug
|
|
40
44
|
all.select { |it| !it.private? || permissions&.writer?(it.slug) }
|
41
45
|
end
|
42
46
|
|
43
|
-
def
|
47
|
+
def find_transparently!(args)
|
44
48
|
find_by!(slug: "#{args[:organization]}/#{args[:repository]}")
|
45
49
|
end
|
46
50
|
|
@@ -4,10 +4,11 @@ module WithUsages
|
|
4
4
|
included do
|
5
5
|
has_many :usages, as: :item
|
6
6
|
before_destroy :ensure_unused!
|
7
|
+
organic_on :usages
|
7
8
|
end
|
8
9
|
|
9
10
|
def usage_in_organization(organization = Organization.current)
|
10
|
-
|
11
|
+
usages_in_organization(organization).first.try(:parent_item)
|
11
12
|
end
|
12
13
|
|
13
14
|
def usage_in_organization_of_type(type, organization = Organization.current)
|
data/app/models/course.rb
CHANGED
@@ -15,7 +15,7 @@ class Course < ApplicationRecord
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def import_from_resource_h!(resource_h)
|
18
|
-
update! Mumukit::Platform::Course::Helpers.
|
18
|
+
update! Mumukit::Platform::Course::Helpers.slice_resource_h(resource_h)
|
19
19
|
end
|
20
20
|
|
21
21
|
def slug=(slug)
|
data/app/models/discussion.rb
CHANGED
@@ -5,6 +5,7 @@ class Discussion < ApplicationRecord
|
|
5
5
|
has_many :messages, -> { order(:created_at) }, dependent: :destroy
|
6
6
|
belongs_to :initiator, class_name: 'User'
|
7
7
|
belongs_to :exercise, foreign_type: :exercise, foreign_key: 'item_id'
|
8
|
+
belongs_to :organization
|
8
9
|
has_many :subscriptions
|
9
10
|
has_many :upvotes
|
10
11
|
|
@@ -23,7 +24,7 @@ class Discussion < ApplicationRecord
|
|
23
24
|
delegate :to_discussion_status, to: :status
|
24
25
|
|
25
26
|
scope :for_user, -> (user) do
|
26
|
-
if user.try(:
|
27
|
+
if user.try(:moderator_here?)
|
27
28
|
all
|
28
29
|
else
|
29
30
|
where.not(status: :closed).where.not(status: :pending_review).or(where(initiator: user))
|
@@ -41,11 +42,11 @@ class Discussion < ApplicationRecord
|
|
41
42
|
end
|
42
43
|
|
43
44
|
def used_in?(organization)
|
44
|
-
|
45
|
+
organization == self.organization
|
45
46
|
end
|
46
47
|
|
47
48
|
def commentable_by?(user)
|
48
|
-
user&.
|
49
|
+
user&.moderator_here? || (opened? && user.present?)
|
49
50
|
end
|
50
51
|
|
51
52
|
def subscribable?
|
@@ -87,7 +88,7 @@ class Discussion < ApplicationRecord
|
|
87
88
|
end
|
88
89
|
|
89
90
|
def authorized?(user)
|
90
|
-
initiator?(user) || user.try(:
|
91
|
+
initiator?(user) || user.try(:moderator_here?)
|
91
92
|
end
|
92
93
|
|
93
94
|
def initiator?(user)
|
data/app/models/exam.rb
CHANGED
@@ -73,7 +73,11 @@ class Exam < ApplicationRecord
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def start!(user)
|
76
|
-
|
76
|
+
return if user.teacher_here?
|
77
|
+
|
78
|
+
authorization = authorization_for(user)
|
79
|
+
raise Mumuki::Domain::ForbiddenError unless authorization
|
80
|
+
authorization.start!
|
77
81
|
end
|
78
82
|
|
79
83
|
def started?(user)
|
data/app/models/exercise.rb
CHANGED
@@ -25,6 +25,8 @@ class Exercise < ApplicationRecord
|
|
25
25
|
defaults { self.submissions_count = 0 }
|
26
26
|
|
27
27
|
serialize :choices, Array
|
28
|
+
serialize :settings, Hash
|
29
|
+
|
28
30
|
validates_presence_of :submissions_count,
|
29
31
|
:guide, :bibliotheca_id
|
30
32
|
|
@@ -64,12 +66,12 @@ class Exercise < ApplicationRecord
|
|
64
66
|
[language&.name, *tag_list].compact
|
65
67
|
end
|
66
68
|
|
67
|
-
def
|
68
|
-
"#{guide.
|
69
|
+
def transparent_id
|
70
|
+
"#{guide.transparent_id}/#{bibliotheca_id}"
|
69
71
|
end
|
70
72
|
|
71
|
-
def
|
72
|
-
guide.
|
73
|
+
def transparent_params
|
74
|
+
guide.transparent_params.merge(bibliotheca_id: bibliotheca_id)
|
73
75
|
end
|
74
76
|
|
75
77
|
def friendly
|
@@ -116,6 +118,7 @@ class Exercise < ApplicationRecord
|
|
116
118
|
free_form_editor_source initial_state final_state))
|
117
119
|
.merge(id: bibliotheca_id, language: language_resource_h, type: type.underscore)
|
118
120
|
.merge(expectations: self[:expectations])
|
121
|
+
.merge(settings: self[:settings])
|
119
122
|
.merge(RANDOMIZED_FIELDS.map { |it| [it, self[it]] }.to_h)
|
120
123
|
.symbolize_keys
|
121
124
|
.compact
|
@@ -193,6 +196,19 @@ class Exercise < ApplicationRecord
|
|
193
196
|
.map { |name, content| Mumuki::Domain::File.new name, content }
|
194
197
|
end
|
195
198
|
|
199
|
+
def self.find_transparently!(params)
|
200
|
+
Guide.find_transparently!(params).locate_exercise! params[:bibliotheca_id]
|
201
|
+
end
|
202
|
+
|
203
|
+
def self.locate!(slug_and_bibliotheca_id)
|
204
|
+
slug, bibliotheca_id = slug_and_bibliotheca_id
|
205
|
+
Guide.locate!(slug).locate_exercise! bibliotheca_id
|
206
|
+
end
|
207
|
+
|
208
|
+
def settings
|
209
|
+
guide.settings.deep_merge super
|
210
|
+
end
|
211
|
+
|
196
212
|
private
|
197
213
|
|
198
214
|
def evaluation_class
|
data/app/models/guide.rb
CHANGED
@@ -8,6 +8,8 @@ class Guide < Content
|
|
8
8
|
numbered :exercises
|
9
9
|
has_many :exercises, -> { order(number: :asc) }, dependent: :destroy
|
10
10
|
|
11
|
+
serialize :settings, Hash
|
12
|
+
|
11
13
|
self.inheritance_column = nil
|
12
14
|
|
13
15
|
enum type: [:learning, :practice]
|
@@ -57,6 +59,11 @@ class Guide < Content
|
|
57
59
|
stats_for(user).done?
|
58
60
|
end
|
59
61
|
|
62
|
+
# Finds an exercise by bibliotheca_id within this guide
|
63
|
+
def locate_exercise!(bibliotheca_id)
|
64
|
+
exercises.find_by!(bibliotheca_id: bibliotheca_id)
|
65
|
+
end
|
66
|
+
|
60
67
|
def import_from_resource_h!(resource_h)
|
61
68
|
self.assign_attributes whitelist_attributes(resource_h)
|
62
69
|
self.language = Language.for_name(resource_h.dig(:language, :name))
|
@@ -80,7 +87,7 @@ class Guide < Content
|
|
80
87
|
end
|
81
88
|
|
82
89
|
def to_resource_h
|
83
|
-
as_json(only: %i(beta type id_format private expectations corollary teacher_info sources learn_more authors collaborators extra))
|
90
|
+
as_json(only: %i(beta type id_format private expectations corollary teacher_info sources learn_more authors collaborators extra settings))
|
84
91
|
.symbolize_keys
|
85
92
|
.merge(super)
|
86
93
|
.merge(exercises: exercises.map(&:to_resource_h))
|
data/app/models/invitation.rb
CHANGED
data/app/models/message.rb
CHANGED
data/app/models/organization.rb
CHANGED
@@ -95,12 +95,25 @@ class Organization < ApplicationRecord
|
|
95
95
|
central? ? 'mumuki' : name
|
96
96
|
end
|
97
97
|
|
98
|
-
|
99
|
-
|
98
|
+
# Tells if the given user can
|
99
|
+
# ask for help in this organization
|
100
|
+
#
|
101
|
+
# Warning: this method does not strictly check user's permission
|
102
|
+
def ask_for_help_enabled?(user)
|
103
|
+
report_issue_enabled? || community_link.present? || can_create_discussions?(user)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Tells if the given user can
|
107
|
+
# create discussion in this organization
|
108
|
+
#
|
109
|
+
# This is true only when this organization has a forum and the user
|
110
|
+
# has the discusser pseudo-permission
|
111
|
+
def can_create_discussions?(user)
|
112
|
+
forum_enabled? && user.discusser_of?(self)
|
100
113
|
end
|
101
114
|
|
102
115
|
def import_from_resource_h!(resource_h)
|
103
|
-
attrs = Mumukit::Platform::Organization::Helpers.
|
116
|
+
attrs = Mumukit::Platform::Organization::Helpers.slice_resource_h resource_h
|
104
117
|
attrs[:book] = Book.locate! attrs[:book]
|
105
118
|
update! attrs
|
106
119
|
end
|
data/app/models/user.rb
CHANGED
@@ -98,7 +98,7 @@ class User < ApplicationRecord
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def import_from_resource_h!(json)
|
101
|
-
update! Mumukit::Platform::User::Helpers.
|
101
|
+
update! Mumukit::Platform::User::Helpers.slice_resource_h json
|
102
102
|
end
|
103
103
|
|
104
104
|
def unsubscribe_from_reminders!
|
@@ -27,11 +27,11 @@ module Mumuki::Domain::Status::Discussion
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def should_be_shown?(count, user)
|
30
|
-
count > 0 || user&.
|
30
|
+
count > 0 || user&.moderator_here?
|
31
31
|
end
|
32
32
|
|
33
33
|
def reachable_statuses_for(user, discussion)
|
34
|
-
if user.
|
34
|
+
if user.moderator_here?
|
35
35
|
reachable_statuses_for_moderator(discussion)
|
36
36
|
else
|
37
37
|
reachable_statuses_for_initiator(discussion)
|
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: 6.
|
4
|
+
version: 6.6.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: 2019-
|
11
|
+
date: 2019-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -142,14 +142,14 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
145
|
+
version: '4.2'
|
146
146
|
type: :runtime
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
152
|
+
version: '4.2'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: mumukit-sync
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -535,6 +535,8 @@ files:
|
|
535
535
|
- db/migrate/20190123180139_add_sources_section.rb
|
536
536
|
- db/migrate/20190123180147_add_learn_more_section.rb
|
537
537
|
- db/migrate/20190312152901_add_content_fk.rb
|
538
|
+
- db/migrate/20190326152631_add_settings_to_content.rb
|
539
|
+
- db/migrate/20190404181724_add_organization_to_discussion.rb
|
538
540
|
- lib/mumuki/domain.rb
|
539
541
|
- lib/mumuki/domain/engine.rb
|
540
542
|
- lib/mumuki/domain/evaluation.rb
|