mumuki-domain 7.1.0 → 7.2.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 +4 -4
- data/app/models/assignment.rb +19 -2
- data/app/models/book.rb +12 -6
- data/app/models/chapter.rb +7 -7
- data/app/models/complement.rb +0 -1
- data/app/models/concerns/contextualization.rb +1 -1
- data/app/models/concerns/guide_container.rb +1 -1
- data/app/models/concerns/navigation/siblings_navigation.rb +8 -0
- data/app/models/concerns/navigation/terminal_navigation.rb +9 -1
- data/app/models/{topic_container.rb → concerns/topic_container.rb} +1 -1
- data/app/models/concerns/with_assignments.rb +2 -1
- data/app/models/concerns/with_content.rb +21 -0
- data/app/models/concerns/with_progress.rb +27 -0
- data/app/models/content.rb +5 -0
- data/app/models/discussion.rb +1 -1
- data/app/models/exam.rb +0 -1
- data/app/models/exercise.rb +2 -4
- data/app/models/guide.rb +22 -19
- data/app/models/indicator.rb +77 -0
- data/app/models/lesson.rb +2 -7
- data/app/models/progress.rb +15 -0
- data/app/models/topic.rb +6 -16
- data/app/models/usage.rb +1 -1
- data/db/migrate/20191029200548_create_indicators.rb +12 -0
- data/db/migrate/20191105171244_add_parent_to_assignments.rb +5 -0
- data/db/migrate/20191211153004_add_dirtiness_to_indicators.rb +6 -0
- data/db/migrate/20191217184525_add_progress_fields_to_indicators.rb +6 -0
- data/db/migrate/20200127142401_add_private_to_topics_and_books.rb +6 -0
- data/db/migrate/20200213175736_add_verified_names_to_users.rb +6 -0
- data/lib/mumuki/domain/factories/discussion_factory.rb +1 -0
- data/lib/mumuki/domain/status/submission/skipped.rb +15 -0
- data/lib/mumuki/domain/status/submission/submission.rb +6 -1
- data/lib/mumuki/domain/version.rb +1 -1
- metadata +13 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 46c76161ad2c80f0450efda0f61a7c8078fd74d9529d83b092cb5432a48338a5
|
|
4
|
+
data.tar.gz: 77909e5fea91cd48d83e636f56d53013a087e99c3cd96731bdd2ba52026736d6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fe48bf99aa63f58b03c74607cfb07d92909857dda352018c491e5a17e24f00d5953deeb404c630b73a4f004939a422e22871b2522b0b15a7a736c6e37b76a3aa
|
|
7
|
+
data.tar.gz: 495cd2a7a075d36a0f7743158c0c4eb06e0989ebd9bda43c45379ff15976158d23a9118ddcd7e7b28362163fed70275ad13a12080f912cd953d53bffa8b5b576
|
data/app/models/assignment.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class Assignment <
|
|
1
|
+
class Assignment < Progress
|
|
2
2
|
include Contextualization
|
|
3
3
|
include WithMessages
|
|
4
4
|
|
|
@@ -36,6 +36,19 @@ class Assignment < ApplicationRecord
|
|
|
36
36
|
self.expectation_results = []
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
alias_method :parent_content, :guide
|
|
40
|
+
alias_method :user, :submitter
|
|
41
|
+
|
|
42
|
+
after_save :dirty_parent_by_submission!, if: :completion_changed?
|
|
43
|
+
|
|
44
|
+
def completion_changed?
|
|
45
|
+
completed_before_last_save? != completed?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def completed_before_last_save?
|
|
49
|
+
status_before_last_save.completed?
|
|
50
|
+
end
|
|
51
|
+
|
|
39
52
|
def evaluate_manually!(teacher_evaluation)
|
|
40
53
|
update! status: teacher_evaluation[:status], manual_evaluation_comment: teacher_evaluation[:manual_evaluation]
|
|
41
54
|
end
|
|
@@ -106,6 +119,10 @@ class Assignment < ApplicationRecord
|
|
|
106
119
|
update! submission_status: :passed
|
|
107
120
|
end
|
|
108
121
|
|
|
122
|
+
def skipped!
|
|
123
|
+
update! submission_status: :skipped
|
|
124
|
+
end
|
|
125
|
+
|
|
109
126
|
def running!
|
|
110
127
|
update! submission_status: :running,
|
|
111
128
|
result: nil,
|
|
@@ -128,7 +145,7 @@ class Assignment < ApplicationRecord
|
|
|
128
145
|
end
|
|
129
146
|
|
|
130
147
|
def to_resource_h
|
|
131
|
-
as_json(except:
|
|
148
|
+
as_json(except: %i(exercise_id submission_id organization_id id submitter_id solution created_at updated_at submission_status submitted_at parent_id),
|
|
132
149
|
include: {
|
|
133
150
|
guide: {
|
|
134
151
|
only: [:slug, :name],
|
data/app/models/book.rb
CHANGED
|
@@ -13,7 +13,7 @@ class Book < Content
|
|
|
13
13
|
|
|
14
14
|
delegate :first_lesson, to: :first_chapter
|
|
15
15
|
|
|
16
|
-
alias_method :
|
|
16
|
+
alias_method :structural_children, :chapters
|
|
17
17
|
|
|
18
18
|
def to_s
|
|
19
19
|
slug
|
|
@@ -24,15 +24,17 @@ class Book < Content
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def next_lesson_for(user)
|
|
27
|
-
user.try(:last_lesson)|| first_lesson
|
|
27
|
+
user.try(:last_lesson) || first_lesson
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def import_from_resource_h!(resource_h)
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
dirty_progress_if_structural_children_changed! do
|
|
32
|
+
self.assign_attributes resource_h.except(:chapters, :complements, :id, :description)
|
|
33
|
+
self.description = resource_h[:description]&.squeeze(' ')
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
rebuild_chapters! resource_h[:chapters].map { |it| Topic.find_by!(slug: it).as_chapter_of(self) }
|
|
36
|
+
rebuild_complements! resource_h[:complements].to_a.map { |it| Guide.find_by(slug: it)&.as_complement_of(self) }.compact
|
|
37
|
+
end
|
|
36
38
|
end
|
|
37
39
|
|
|
38
40
|
def to_expanded_resource_h
|
|
@@ -56,4 +58,8 @@ class Book < Content
|
|
|
56
58
|
dup.chapters = chapters.map { |chapter| chapter.topic.fork_to!(organization, syncer, quiet: true).as_chapter_of(dup) }
|
|
57
59
|
dup.complements = complements.map { |complement| complement.guide.fork_to!(organization, syncer, quiet: true).as_complement_of(dup) }
|
|
58
60
|
end
|
|
61
|
+
|
|
62
|
+
def structural_parent
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
59
65
|
end
|
data/app/models/chapter.rb
CHANGED
|
@@ -2,28 +2,28 @@ class Chapter < ApplicationRecord
|
|
|
2
2
|
include WithStats
|
|
3
3
|
include WithNumber
|
|
4
4
|
|
|
5
|
+
include SiblingsNavigation
|
|
6
|
+
include TerminalNavigation
|
|
7
|
+
|
|
5
8
|
include FriendlyName
|
|
6
9
|
|
|
7
10
|
include TopicContainer
|
|
8
11
|
|
|
9
12
|
belongs_to :book, optional: true
|
|
10
|
-
belongs_to :topic
|
|
11
13
|
|
|
12
14
|
has_many :exercises, through: :topic
|
|
13
15
|
|
|
14
|
-
include SiblingsNavigation
|
|
15
|
-
include TerminalNavigation
|
|
16
16
|
|
|
17
17
|
def used_in?(organization)
|
|
18
18
|
organization.book == self.book
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def pending_siblings_for(user)
|
|
22
|
-
book.pending_chapters(user)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
21
|
def index_usage!(organization = Organization.current)
|
|
26
22
|
organization.index_usage_of! topic, self
|
|
27
23
|
lessons.each { |lesson| lesson.index_usage! organization }
|
|
28
24
|
end
|
|
25
|
+
|
|
26
|
+
def structural_parent
|
|
27
|
+
book
|
|
28
|
+
end
|
|
29
29
|
end
|
data/app/models/complement.rb
CHANGED
|
@@ -25,7 +25,7 @@ module Contextualization
|
|
|
25
25
|
|
|
26
26
|
delegate :visible_success_output?, to: :exercise
|
|
27
27
|
delegate :output_content_type, to: :language
|
|
28
|
-
delegate :should_retry?, :to_submission_status, *Mumuki::Domain::Status::Submission.test_selectors, to: :submission_status
|
|
28
|
+
delegate :should_retry?, :to_submission_status, :completed?, *Mumuki::Domain::Status::Submission.test_selectors, to: :submission_status
|
|
29
29
|
delegate :inspection_keywords, to: :exercise
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -8,6 +8,14 @@ module SiblingsNavigation
|
|
|
8
8
|
pending_siblings_for(user).sort_by(&:number).first
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
def siblings
|
|
12
|
+
structural_parent.structural_children
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def pending_siblings_for(user, organization=Organization.current)
|
|
16
|
+
siblings.reject { |it| it.progress_for(user, organization).completed? }
|
|
17
|
+
end
|
|
18
|
+
|
|
11
19
|
# Names
|
|
12
20
|
|
|
13
21
|
def navigable_name
|
|
@@ -18,6 +18,7 @@ module WithAssignments
|
|
|
18
18
|
messages_for(user).present?
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
# TODO: When the organization is used in this one, please change guide.pending_exercises
|
|
21
22
|
def find_assignment_for(user, _organization)
|
|
22
23
|
assignments.find_by(submitter: user)
|
|
23
24
|
end
|
|
@@ -26,7 +27,7 @@ module WithAssignments
|
|
|
26
27
|
assignment_for(user).status if user
|
|
27
28
|
end
|
|
28
29
|
|
|
29
|
-
def assignment_for(user, organization
|
|
30
|
+
def assignment_for(user, organization=Organization.current)
|
|
30
31
|
find_assignment_for(user, organization) || user.assignments.build(exercise: self, organization: organization)
|
|
31
32
|
end
|
|
32
33
|
end
|
|
@@ -5,8 +5,29 @@ module WithContent
|
|
|
5
5
|
before_destroy :destroy_usages!
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
class_methods do
|
|
9
|
+
def associated_content(content_name)
|
|
10
|
+
belongs_to content_name
|
|
11
|
+
validates_presence_of content_name
|
|
12
|
+
|
|
13
|
+
alias_method :content, content_name
|
|
14
|
+
|
|
15
|
+
define_method(:associated_content_name) { content_name }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def progress_for(user, organization=Organization.current)
|
|
20
|
+
content.progress_for(user, organization)
|
|
21
|
+
end
|
|
22
|
+
|
|
8
23
|
private
|
|
9
24
|
|
|
25
|
+
# Generally we are calling progress_for for each sibling. That method needs the
|
|
26
|
+
# content. With this includes call we're avoiding the N + 1 queries.
|
|
27
|
+
def siblings
|
|
28
|
+
super.includes(associated_content_name)
|
|
29
|
+
end
|
|
30
|
+
|
|
10
31
|
def destroy_usages!
|
|
11
32
|
Usage.destroy_usages_for self
|
|
12
33
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module WithProgress
|
|
2
|
+
def progress_for(user, organization)
|
|
3
|
+
Indicator.find_or_initialize_by(user: user, organization: organization, content: self)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def completion_percentage_for(user, organization=Organization.current)
|
|
7
|
+
progress_for(user, organization).completion_percentage
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def dirty_progresses!
|
|
11
|
+
Indicator.dirty_by_content_change! self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def dirty_progress_if_structural_children_changed!
|
|
15
|
+
old_structural_children = structural_children.to_a
|
|
16
|
+
yield
|
|
17
|
+
Indicator.dirty_by_content_change! self if structural_children_changed?(old_structural_children)
|
|
18
|
+
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def structural_children_changed?(old_structural_children)
|
|
25
|
+
(Set.new(structural_children) ^ Set.new(old_structural_children)).present?
|
|
26
|
+
end
|
|
27
|
+
end
|
data/app/models/content.rb
CHANGED
|
@@ -7,6 +7,7 @@ class Content < ApplicationRecord
|
|
|
7
7
|
include WithSlug
|
|
8
8
|
include WithUsages
|
|
9
9
|
include WithName
|
|
10
|
+
include WithProgress
|
|
10
11
|
|
|
11
12
|
def to_resource_h(*args)
|
|
12
13
|
to_expanded_resource_h(*args).compact
|
|
@@ -27,4 +28,8 @@ class Content < ApplicationRecord
|
|
|
27
28
|
syncer.export! dup
|
|
28
29
|
end
|
|
29
30
|
end
|
|
31
|
+
|
|
32
|
+
def public?
|
|
33
|
+
!private?
|
|
34
|
+
end
|
|
30
35
|
end
|
data/app/models/discussion.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
class Discussion < ApplicationRecord
|
|
2
|
-
include WithDiscussionStatus,
|
|
2
|
+
include WithDiscussionStatus, WithScopedQueries, Contextualization
|
|
3
3
|
|
|
4
4
|
belongs_to :item, polymorphic: true
|
|
5
5
|
has_many :messages, -> { order(:created_at) }, dependent: :destroy
|
data/app/models/exam.rb
CHANGED
data/app/models/exercise.rb
CHANGED
|
@@ -28,6 +28,8 @@ class Exercise < ApplicationRecord
|
|
|
28
28
|
|
|
29
29
|
defaults { self.submissions_count = 0 }
|
|
30
30
|
|
|
31
|
+
alias_method :progress_for, :assignment_for
|
|
32
|
+
|
|
31
33
|
serialize :choices, Array
|
|
32
34
|
serialize :settings, Hash
|
|
33
35
|
|
|
@@ -45,10 +47,6 @@ class Exercise < ApplicationRecord
|
|
|
45
47
|
guide.usage_in_organization(organization).present?
|
|
46
48
|
end
|
|
47
49
|
|
|
48
|
-
def pending_siblings_for(user)
|
|
49
|
-
guide.pending_exercises(user)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
50
|
def structural_parent
|
|
53
51
|
guide
|
|
54
52
|
end
|
data/app/models/guide.rb
CHANGED
|
@@ -19,7 +19,7 @@ class Guide < Content
|
|
|
19
19
|
|
|
20
20
|
enum type: [:learning, :practice]
|
|
21
21
|
|
|
22
|
-
alias_method :
|
|
22
|
+
alias_method :structural_children, :exercises
|
|
23
23
|
|
|
24
24
|
def clear_progress!(user, organization=Organization.current)
|
|
25
25
|
transaction do
|
|
@@ -41,6 +41,11 @@ class Guide < Content
|
|
|
41
41
|
exercises.count
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
def next_exercise(user)
|
|
45
|
+
pending_exercises(user).order('public.exercises.number asc').first
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# TODO: Make use of pending_siblings logic
|
|
44
49
|
def pending_exercises(user)
|
|
45
50
|
exercises.
|
|
46
51
|
joins("left join public.assignments assignments
|
|
@@ -50,10 +55,6 @@ class Guide < Content
|
|
|
50
55
|
where('assignments.id is null')
|
|
51
56
|
end
|
|
52
57
|
|
|
53
|
-
def next_exercise(user)
|
|
54
|
-
pending_exercises(user).order('public.exercises.number asc').first
|
|
55
|
-
end
|
|
56
|
-
|
|
57
58
|
def first_exercise
|
|
58
59
|
exercises.first
|
|
59
60
|
end
|
|
@@ -72,25 +73,27 @@ class Guide < Content
|
|
|
72
73
|
end
|
|
73
74
|
|
|
74
75
|
def import_from_resource_h!(resource_h)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
dirty_progress_if_structural_children_changed! do
|
|
77
|
+
self.assign_attributes whitelist_attributes(resource_h)
|
|
78
|
+
self.language = Language.for_name(resource_h.dig(:language, :name))
|
|
79
|
+
self.save!
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
resource_h[:exercises]&.each_with_index do |e, i|
|
|
82
|
+
exercise = Exercise.find_by(guide_id: self.id, bibliotheca_id: e[:id])
|
|
83
|
+
exercise_type = e[:type] || 'problem'
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
exercise = exercise ?
|
|
86
|
+
exercise.ensure_type!(exercise_type.as_module_name) :
|
|
87
|
+
exercise_type.as_module.new(guide_id: self.id, bibliotheca_id: e[:id])
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
+
exercise.import_from_resource_h! (i+1), e
|
|
90
|
+
end
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
new_ids = resource_h[:exercises].map { |it| it[:id] }
|
|
93
|
+
self.exercises.where.not(bibliotheca_id: new_ids).destroy_all
|
|
92
94
|
|
|
93
|
-
|
|
95
|
+
reload
|
|
96
|
+
end
|
|
94
97
|
end
|
|
95
98
|
|
|
96
99
|
# Keep this list up to date with
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
class Indicator < Progress
|
|
2
|
+
belongs_to :user
|
|
3
|
+
belongs_to :content, polymorphic: true
|
|
4
|
+
belongs_to :organization
|
|
5
|
+
|
|
6
|
+
has_many :indicators, foreign_key: :parent_id, class_name: 'Indicator'
|
|
7
|
+
has_many :assignments, foreign_key: :parent_id
|
|
8
|
+
|
|
9
|
+
def propagate_up!(&block)
|
|
10
|
+
instance_eval &block
|
|
11
|
+
parent&.instance_eval { propagate_up! &block }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.dirty_by_content_change!(content)
|
|
15
|
+
where(content: content).update_all dirty_by_content_change: true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def dirty_by_submission!
|
|
19
|
+
propagate_up! { update! dirty_by_submission: true }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def rebuild!
|
|
23
|
+
if dirty_by_content_change?
|
|
24
|
+
propagate_up! do
|
|
25
|
+
refresh_children_count!
|
|
26
|
+
refresh_children_passed_count!
|
|
27
|
+
clean!
|
|
28
|
+
save!
|
|
29
|
+
end
|
|
30
|
+
elsif dirty_by_submission?
|
|
31
|
+
refresh_children_passed_count!
|
|
32
|
+
clean!
|
|
33
|
+
save!
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def clean!
|
|
38
|
+
self.dirty_by_submission = false
|
|
39
|
+
self.dirty_by_content_change = false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def refresh_children_count!
|
|
43
|
+
self.children_count = content.structural_children.count
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def refresh_children_passed_count!
|
|
47
|
+
self.children_passed_count = children.count(&:completed?)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def completion_percentage
|
|
51
|
+
rebuild!
|
|
52
|
+
children_passed_count.fdiv children_count
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def completed?
|
|
56
|
+
rebuild!
|
|
57
|
+
children_passed_count == children_count
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def children
|
|
63
|
+
indicators.presence || assignments
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
%i(children_count children_passed_count).each do |selector|
|
|
67
|
+
define_method selector do
|
|
68
|
+
send "refresh_#{selector}!" unless self[selector]
|
|
69
|
+
|
|
70
|
+
self[selector]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def parent_content
|
|
75
|
+
content.usage_in_organization(organization).structural_parent
|
|
76
|
+
end
|
|
77
|
+
end
|
data/app/models/lesson.rb
CHANGED
|
@@ -2,12 +2,11 @@ class Lesson < ApplicationRecord
|
|
|
2
2
|
include WithNumber
|
|
3
3
|
include FriendlyName
|
|
4
4
|
|
|
5
|
+
include ParentNavigation, SiblingsNavigation
|
|
6
|
+
|
|
5
7
|
include GuideContainer
|
|
6
8
|
|
|
7
9
|
belongs_to :topic
|
|
8
|
-
belongs_to :guide
|
|
9
|
-
|
|
10
|
-
include ParentNavigation, SiblingsNavigation
|
|
11
10
|
|
|
12
11
|
alias_method :chapter, :navigable_parent
|
|
13
12
|
|
|
@@ -15,10 +14,6 @@ class Lesson < ApplicationRecord
|
|
|
15
14
|
guide.usage_in_organization(organization) == self
|
|
16
15
|
end
|
|
17
16
|
|
|
18
|
-
def pending_siblings_for(user)
|
|
19
|
-
topic.pending_lessons(user)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
17
|
def structural_parent
|
|
23
18
|
topic
|
|
24
19
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class Progress < ApplicationRecord
|
|
2
|
+
self.abstract_class = true
|
|
3
|
+
|
|
4
|
+
before_save :parent, unless: :parent_id?
|
|
5
|
+
belongs_to :parent, class_name: 'Indicator', optional: true
|
|
6
|
+
|
|
7
|
+
def parent
|
|
8
|
+
assign_attributes(parent: parent_content&.progress_for(user, organization)) unless super
|
|
9
|
+
super
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def dirty_parent_by_submission!
|
|
13
|
+
parent&.dirty_by_submission!
|
|
14
|
+
end
|
|
15
|
+
end
|
data/app/models/topic.rb
CHANGED
|
@@ -9,28 +9,18 @@ class Topic < Content
|
|
|
9
9
|
|
|
10
10
|
markdown_on :appendix
|
|
11
11
|
|
|
12
|
-
alias_method :
|
|
13
|
-
|
|
14
|
-
def pending_lessons(user)
|
|
15
|
-
guides.
|
|
16
|
-
joins('left join public.exercises exercises
|
|
17
|
-
on exercises.guide_id = guides.id').
|
|
18
|
-
joins("left join public.assignments assignments
|
|
19
|
-
on assignments.exercise_id = exercises.id
|
|
20
|
-
and assignments.submitter_id = #{user.id}
|
|
21
|
-
and assignments.submission_status = #{Mumuki::Domain::Status::Submission::Passed.to_i}").
|
|
22
|
-
where('assignments.id is null').
|
|
23
|
-
group('public.guides.id', 'lessons.number').map(&:lesson)
|
|
24
|
-
end
|
|
12
|
+
alias_method :structural_children, :lessons
|
|
25
13
|
|
|
26
14
|
def first_lesson
|
|
27
15
|
lessons.first
|
|
28
16
|
end
|
|
29
17
|
|
|
30
18
|
def import_from_resource_h!(resource_h)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
19
|
+
dirty_progress_if_structural_children_changed! do
|
|
20
|
+
self.assign_attributes resource_h.except(:lessons, :description)
|
|
21
|
+
self.description = resource_h[:description].squeeze(' ')
|
|
22
|
+
rebuild_lessons! resource_h[:lessons].to_a.map { |it| lesson_for(it) }
|
|
23
|
+
end
|
|
34
24
|
end
|
|
35
25
|
|
|
36
26
|
def to_expanded_resource_h
|
data/app/models/usage.rb
CHANGED
|
@@ -18,7 +18,7 @@ class Usage < ApplicationRecord
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def destroy_children_usages!
|
|
21
|
-
item.
|
|
21
|
+
item.structural_children.each { |child| Usage.destroy_all_where(parent_item: child, organization: organization) }
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def index_children!(children)
|
|
@@ -10,9 +10,10 @@ require_relative './errored'
|
|
|
10
10
|
require_relative './aborted'
|
|
11
11
|
require_relative './passed_with_warnings'
|
|
12
12
|
require_relative './manual_evaluation_pending'
|
|
13
|
+
require_relative './skipped'
|
|
13
14
|
|
|
14
15
|
module Mumuki::Domain::Status::Submission
|
|
15
|
-
STATUSES = [Pending, Running, Passed, Failed, Errored, Aborted, PassedWithWarnings, ManualEvaluationPending]
|
|
16
|
+
STATUSES = [Pending, Running, Passed, Failed, Errored, Aborted, PassedWithWarnings, ManualEvaluationPending, Skipped]
|
|
16
17
|
|
|
17
18
|
test_selectors.each do |selector|
|
|
18
19
|
define_method(selector) { false }
|
|
@@ -35,4 +36,8 @@ module Mumuki::Domain::Status::Submission
|
|
|
35
36
|
def as_json(_options={})
|
|
36
37
|
to_s
|
|
37
38
|
end
|
|
39
|
+
|
|
40
|
+
def completed?
|
|
41
|
+
passed?
|
|
42
|
+
end
|
|
38
43
|
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.
|
|
4
|
+
version: 7.2.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-
|
|
11
|
+
date: 2020-03-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -263,6 +263,7 @@ files:
|
|
|
263
263
|
- app/models/concerns/submittable/solvable.rb
|
|
264
264
|
- app/models/concerns/submittable/submittable.rb
|
|
265
265
|
- app/models/concerns/submittable/triable.rb
|
|
266
|
+
- app/models/concerns/topic_container.rb
|
|
266
267
|
- app/models/concerns/with_assignments.rb
|
|
267
268
|
- app/models/concerns/with_case_insensitive_search.rb
|
|
268
269
|
- app/models/concerns/with_content.rb
|
|
@@ -281,6 +282,7 @@ files:
|
|
|
281
282
|
- app/models/concerns/with_name.rb
|
|
282
283
|
- app/models/concerns/with_number.rb
|
|
283
284
|
- app/models/concerns/with_profile.rb
|
|
285
|
+
- app/models/concerns/with_progress.rb
|
|
284
286
|
- app/models/concerns/with_randomizations.rb
|
|
285
287
|
- app/models/concerns/with_reminders.rb
|
|
286
288
|
- app/models/concerns/with_scoped_queries.rb
|
|
@@ -304,15 +306,16 @@ files:
|
|
|
304
306
|
- app/models/exercise/queriable_challenge.rb
|
|
305
307
|
- app/models/exercise/reading.rb
|
|
306
308
|
- app/models/guide.rb
|
|
309
|
+
- app/models/indicator.rb
|
|
307
310
|
- app/models/invitation.rb
|
|
308
311
|
- app/models/language.rb
|
|
309
312
|
- app/models/lesson.rb
|
|
310
313
|
- app/models/message.rb
|
|
311
314
|
- app/models/organization.rb
|
|
315
|
+
- app/models/progress.rb
|
|
312
316
|
- app/models/stats.rb
|
|
313
317
|
- app/models/subscription.rb
|
|
314
318
|
- app/models/topic.rb
|
|
315
|
-
- app/models/topic_container.rb
|
|
316
319
|
- app/models/upvote.rb
|
|
317
320
|
- app/models/usage.rb
|
|
318
321
|
- app/models/user.rb
|
|
@@ -589,6 +592,12 @@ files:
|
|
|
589
592
|
- db/migrate/20190918140026_add_custom_expectations.rb
|
|
590
593
|
- db/migrate/20190929180601_add_expectations_to_language.rb
|
|
591
594
|
- db/migrate/20191022180238_remove_choice_values_from_exercises.rb
|
|
595
|
+
- db/migrate/20191029200548_create_indicators.rb
|
|
596
|
+
- db/migrate/20191105171244_add_parent_to_assignments.rb
|
|
597
|
+
- db/migrate/20191211153004_add_dirtiness_to_indicators.rb
|
|
598
|
+
- db/migrate/20191217184525_add_progress_fields_to_indicators.rb
|
|
599
|
+
- db/migrate/20200127142401_add_private_to_topics_and_books.rb
|
|
600
|
+
- db/migrate/20200213175736_add_verified_names_to_users.rb
|
|
592
601
|
- lib/mumuki/domain.rb
|
|
593
602
|
- lib/mumuki/domain/engine.rb
|
|
594
603
|
- lib/mumuki/domain/evaluation.rb
|
|
@@ -654,6 +663,7 @@ files:
|
|
|
654
663
|
- lib/mumuki/domain/status/submission/passed_with_warnings.rb
|
|
655
664
|
- lib/mumuki/domain/status/submission/pending.rb
|
|
656
665
|
- lib/mumuki/domain/status/submission/running.rb
|
|
666
|
+
- lib/mumuki/domain/status/submission/skipped.rb
|
|
657
667
|
- lib/mumuki/domain/status/submission/submission.rb
|
|
658
668
|
- lib/mumuki/domain/store.rb
|
|
659
669
|
- lib/mumuki/domain/store/bibliotheca.rb
|