mumuki-domain 7.1.0 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
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