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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/assignment.rb +19 -2
  3. data/app/models/book.rb +12 -6
  4. data/app/models/chapter.rb +7 -7
  5. data/app/models/complement.rb +0 -1
  6. data/app/models/concerns/contextualization.rb +1 -1
  7. data/app/models/concerns/guide_container.rb +1 -1
  8. data/app/models/concerns/navigation/siblings_navigation.rb +8 -0
  9. data/app/models/concerns/navigation/terminal_navigation.rb +9 -1
  10. data/app/models/{topic_container.rb → concerns/topic_container.rb} +1 -1
  11. data/app/models/concerns/with_assignments.rb +2 -1
  12. data/app/models/concerns/with_content.rb +21 -0
  13. data/app/models/concerns/with_progress.rb +27 -0
  14. data/app/models/content.rb +5 -0
  15. data/app/models/discussion.rb +1 -1
  16. data/app/models/exam.rb +0 -1
  17. data/app/models/exercise.rb +2 -4
  18. data/app/models/guide.rb +22 -19
  19. data/app/models/indicator.rb +77 -0
  20. data/app/models/lesson.rb +2 -7
  21. data/app/models/progress.rb +15 -0
  22. data/app/models/topic.rb +6 -16
  23. data/app/models/usage.rb +1 -1
  24. data/db/migrate/20191029200548_create_indicators.rb +12 -0
  25. data/db/migrate/20191105171244_add_parent_to_assignments.rb +5 -0
  26. data/db/migrate/20191211153004_add_dirtiness_to_indicators.rb +6 -0
  27. data/db/migrate/20191217184525_add_progress_fields_to_indicators.rb +6 -0
  28. data/db/migrate/20200127142401_add_private_to_topics_and_books.rb +6 -0
  29. data/db/migrate/20200213175736_add_verified_names_to_users.rb +6 -0
  30. data/lib/mumuki/domain/factories/discussion_factory.rb +1 -0
  31. data/lib/mumuki/domain/status/submission/skipped.rb +15 -0
  32. data/lib/mumuki/domain/status/submission/submission.rb +6 -1
  33. data/lib/mumuki/domain/version.rb +1 -1
  34. metadata +13 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe0f9389e1714c564320f373c82d35b3b84a3c27bd68af16584c68c4f38639f8
4
- data.tar.gz: ca0b57c648127393d93ffab7c5beee55d6abdb31e80f37f33b787f33470ec171
3
+ metadata.gz: 46c76161ad2c80f0450efda0f61a7c8078fd74d9529d83b092cb5432a48338a5
4
+ data.tar.gz: 77909e5fea91cd48d83e636f56d53013a087e99c3cd96731bdd2ba52026736d6
5
5
  SHA512:
6
- metadata.gz: 1cd397c42e1b6f16d4b903a5829087758eeb75ca190c2eb0902866a688a124f982e18fca28ca997d26b118eb8a0efa3a35f37b23b3e0a3ffab292fd7ee6c70ee
7
- data.tar.gz: 49a329e6663553e44e6865e44224d9f27fa0befefd6bdcfb04fe460800a9b42a5f7aadd56c09793dbf7c8983531aae6a54f7a75659676e0eb3b9e23795590e7c
6
+ metadata.gz: fe48bf99aa63f58b03c74607cfb07d92909857dda352018c491e5a17e24f00d5953deeb404c630b73a4f004939a422e22871b2522b0b15a7a736c6e37b76a3aa
7
+ data.tar.gz: 495cd2a7a075d36a0f7743158c0c4eb06e0989ebd9bda43c45379ff15976158d23a9118ddcd7e7b28362163fed70275ad13a12080f912cd953d53bffa8b5b576
@@ -1,4 +1,4 @@
1
- class Assignment < ApplicationRecord
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: [:exercise_id, :submission_id, :organization_id, :id, :submitter_id, :solution, :created_at, :updated_at, :submission_status, :submitted_at],
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 :children, :topics
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
- self.assign_attributes resource_h.except(:chapters, :complements, :id, :description)
32
- self.description = resource_h[:description]&.squeeze(' ')
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
- rebuild_chapters! resource_h[:chapters].map { |it| Topic.find_by!(slug: it).as_chapter_of(self) }
35
- rebuild_complements! resource_h[:complements].to_a.map { |it| Guide.find_by(slug: it)&.as_complement_of(self) }.compact
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
@@ -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
@@ -4,7 +4,6 @@ class Complement < ApplicationRecord
4
4
 
5
5
  validates_presence_of :book
6
6
 
7
- belongs_to :guide
8
7
  belongs_to :book
9
8
 
10
9
  include TerminalNavigation
@@ -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
 
@@ -3,7 +3,7 @@ module GuideContainer
3
3
  include WithContent
4
4
 
5
5
  included do
6
- validates_presence_of :guide
6
+ associated_content :guide
7
7
 
8
8
  delegate :name,
9
9
  :slug,
@@ -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
@@ -10,4 +10,12 @@ module TerminalNavigation
10
10
  def navigable_name
11
11
  name
12
12
  end
13
- end
13
+
14
+ def structural_parent
15
+ nil
16
+ end
17
+
18
+ def siblings
19
+ []
20
+ end
21
+ end
@@ -3,7 +3,7 @@ module TopicContainer
3
3
  include WithContent
4
4
 
5
5
  included do
6
- validates_presence_of :topic
6
+ associated_content :topic
7
7
 
8
8
  delegate :name,
9
9
  :slug,
@@ -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: Organization.current)
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
@@ -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
@@ -1,5 +1,5 @@
1
1
  class Discussion < ApplicationRecord
2
- include WithDiscussionStatus, ParentNavigation, WithScopedQueries, Contextualization
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
@@ -4,7 +4,6 @@ class Exam < ApplicationRecord
4
4
 
5
5
  validates_presence_of :start_time, :end_time
6
6
 
7
- belongs_to :guide
8
7
  belongs_to :organization
9
8
 
10
9
  has_many :authorizations, class_name: 'ExamAuthorization', dependent: :destroy
@@ -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 :children, :exercises
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
- self.assign_attributes whitelist_attributes(resource_h)
76
- self.language = Language.for_name(resource_h.dig(:language, :name))
77
- self.save!
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
- resource_h[:exercises]&.each_with_index do |e, i|
80
- exercise = Exercise.find_by(guide_id: self.id, bibliotheca_id: e[:id])
81
- exercise_type = e[:type] || 'problem'
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
- exercise = exercise ?
84
- exercise.ensure_type!(exercise_type.as_module_name) :
85
- exercise_type.as_module.new(guide_id: self.id, bibliotheca_id: e[:id])
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
- exercise.import_from_resource_h! (i+1), e
88
- end
89
+ exercise.import_from_resource_h! (i+1), e
90
+ end
89
91
 
90
- new_ids = resource_h[:exercises].map { |it| it[:id] }
91
- self.exercises.where.not(bibliotheca_id: new_ids).destroy_all
92
+ new_ids = resource_h[:exercises].map { |it| it[:id] }
93
+ self.exercises.where.not(bibliotheca_id: new_ids).destroy_all
92
94
 
93
- reload
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 :children, :guides
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
- self.assign_attributes resource_h.except(:lessons, :description)
32
- self.description = resource_h[:description].squeeze(' ')
33
- rebuild_lessons! resource_h[:lessons].to_a.map { |it| lesson_for(it) }
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.children.each { |child| Usage.destroy_all_where(item: child, organization: organization) }
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)
@@ -0,0 +1,12 @@
1
+ class CreateIndicators < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :indicators do |t|
4
+ t.references :user
5
+ t.references :organization
6
+ t.references :parent
7
+ t.references :content, polymorphic: true
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ class AddParentToAssignments < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_reference :assignments, :parent
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class AddDirtinessToIndicators < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :indicators, :dirty_by_content_change, :boolean, default: false
4
+ add_column :indicators, :dirty_by_submission, :boolean, default: false
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class AddProgressFieldsToIndicators < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :indicators, :children_passed_count, :integer
4
+ add_column :indicators, :children_count, :integer
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class AddPrivateToTopicsAndBooks < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :topics, :private, :boolean, default: false
4
+ add_column :books, :private, :boolean, default: false
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class AddVerifiedNamesToUsers < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :users, :verified_first_name, :string
4
+ add_column :users, :verified_last_name, :string
5
+ end
6
+ end
@@ -4,5 +4,6 @@ FactoryBot.define do
4
4
  description { 'A discussion description' }
5
5
  initiator { create(:user) }
6
6
  item { create(:exercise) }
7
+ organization { Organization.current rescue nil }
7
8
  end
8
9
  end
@@ -0,0 +1,15 @@
1
+ module Mumuki::Domain::Status::Submission::Skipped
2
+ extend Mumuki::Domain::Status::Submission
3
+
4
+ def self.skipped?
5
+ true
6
+ end
7
+
8
+ def self.passed?
9
+ true
10
+ end
11
+
12
+ def self.iconize
13
+ {class: :success, type: 'check-circle'}
14
+ end
15
+ end
@@ -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
@@ -1,5 +1,5 @@
1
1
  module Mumuki
2
2
  module Domain
3
- VERSION = '7.1.0'
3
+ VERSION = '7.2.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.1.0
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-01-17 00:00:00.000000000 Z
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