mumuki-laboratory 5.5.0 → 5.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/assets/javascripts/application/discussions.js +43 -0
- data/app/assets/stylesheets/application/_modules.scss +2 -0
- data/app/assets/stylesheets/application/modules/_checkboxes.scss +21 -8
- data/app/assets/stylesheets/application/modules/_discussion.scss +339 -0
- data/app/assets/stylesheets/application/modules/_pagination.scss +10 -0
- data/app/controllers/application_controller.rb +4 -9
- data/app/controllers/book_discussions_controller.rb +7 -0
- data/app/controllers/chapters_controller.rb +2 -0
- data/app/controllers/discussions_controller.rb +65 -0
- data/app/controllers/discussions_messages_controller.rb +25 -0
- data/app/controllers/exercises_controller.rb +1 -0
- data/app/controllers/guide_container_controller.rb +1 -0
- data/app/controllers/messages_controller.rb +1 -1
- data/app/controllers/users_controller.rb +1 -0
- data/app/helpers/application_helper.rb +7 -0
- data/app/helpers/assignment_result_helper.rb +10 -30
- data/app/helpers/breadcrumbs_helper.rb +7 -3
- data/app/helpers/contextualization_result_helper.rb +31 -0
- data/app/helpers/discussions_helper.rb +163 -0
- data/app/helpers/exercise_input_helper.rb +33 -5
- data/app/helpers/icons_helper.rb +20 -3
- data/app/helpers/messages_helper.rb +4 -0
- data/app/helpers/status_helper.rb +2 -2
- data/app/models/assignment.rb +31 -47
- data/app/models/book.rb +3 -0
- data/app/models/chapter.rb +2 -0
- data/app/models/concerns/contextualization.rb +85 -0
- data/app/models/concerns/submittable/solvable.rb +1 -0
- data/app/models/concerns/with_assignments.rb +1 -1
- data/app/models/concerns/with_discussion_creation.rb +9 -0
- data/app/models/concerns/with_discussion_creation/subscription.rb +33 -0
- data/app/models/concerns/with_discussion_creation/upvote.rb +28 -0
- data/app/models/concerns/with_discussion_status.rb +11 -0
- data/app/models/concerns/with_discussions.rb +23 -0
- data/app/models/concerns/with_randomizations.rb +34 -0
- data/app/models/concerns/with_scoped_queries.rb +47 -0
- data/app/models/concerns/with_scoped_queries/filter.rb +15 -0
- data/app/models/concerns/with_scoped_queries/page.rb +10 -0
- data/app/models/concerns/with_scoped_queries/sort.rb +47 -0
- data/app/models/discussion.rb +128 -0
- data/app/models/exercise.rb +10 -1
- data/app/models/guide.rb +1 -1
- data/app/models/message.rb +24 -3
- data/app/models/organization.rb +4 -0
- data/app/models/submission/confirmation.rb +1 -1
- data/app/models/submission/console_submission.rb +1 -1
- data/app/models/submission/submission.rb +13 -0
- data/app/models/subscription.rb +12 -0
- data/app/models/topic.rb +1 -1
- data/app/models/upvote.rb +4 -0
- data/app/models/user.rb +3 -2
- data/app/views/book_discussions/index.html.erb +23 -0
- data/app/views/chapters/show.html.erb +0 -1
- data/app/views/discussions/_message.html.erb +22 -0
- data/app/views/discussions/_message_container.html.erb +8 -0
- data/app/views/discussions/_new_message.html.erb +19 -0
- data/app/views/discussions/index.html.erb +30 -0
- data/app/views/discussions/show.html.erb +76 -0
- data/app/views/exercise_solutions/_contextualization_results.html.erb +21 -0
- data/app/views/exercise_solutions/_contextualization_results_container.html.erb +4 -0
- data/app/views/exercise_solutions/_expectations.html.erb +9 -3
- data/app/views/exercise_solutions/_kids_results.html.erb +1 -1
- data/app/views/exercise_solutions/_results.html.erb +21 -55
- data/app/views/exercise_solutions/_results_title.html.erb +2 -2
- data/app/views/exercises/_exercise_assignment.html.erb +20 -0
- data/app/views/exercises/_read_only.html.erb +104 -0
- data/app/views/exercises/show.html.erb +4 -20
- data/app/views/layouts/_discussions.html.erb +68 -0
- data/app/views/layouts/_kids.html.erb +9 -6
- data/app/views/layouts/_messages.html.erb +1 -1
- data/app/views/layouts/_result.html.erb +2 -2
- data/app/views/layouts/_test_results.html.erb +6 -6
- data/app/views/layouts/application.html.erb +10 -9
- data/app/views/layouts/exercise_inputs/forms/_form.html.erb +5 -6
- data/app/views/layouts/exercise_inputs/forms/_interactive_form.html.erb +5 -5
- data/app/views/layouts/exercise_inputs/forms/_kids_form.html.erb +9 -17
- data/app/views/layouts/exercise_inputs/forms/_playground_form.html.erb +5 -5
- data/app/views/layouts/exercise_inputs/forms/_problem_form.html.erb +11 -11
- data/app/views/layouts/exercise_inputs/forms/_reading_form.html.erb +1 -1
- data/app/views/layouts/exercise_inputs/layouts/_input_bottom.html.erb +1 -1
- data/app/views/layouts/exercise_inputs/layouts/_input_kids.html.erb +7 -7
- data/app/views/layouts/exercise_inputs/layouts/_input_right.html.erb +1 -1
- data/app/views/layouts/exercise_inputs/read_only_editors/_code.html.erb +3 -0
- data/app/views/layouts/exercise_inputs/read_only_editors/_custom.html.erb +6 -0
- data/app/views/layouts/exercise_inputs/read_only_editors/_multiple_choice.html.erb +8 -0
- data/app/views/layouts/exercise_inputs/read_only_editors/_single_choice.html.erb +8 -0
- data/app/views/layouts/modals/_kids_context.html.erb +2 -2
- data/app/views/layouts/modals/_new_discussion.html.erb +27 -0
- data/app/views/users/show.html.erb +23 -3
- data/config/routes.rb +21 -1
- data/db/migrate/20180504173548_create_discussions.rb +12 -0
- data/db/migrate/20180504185845_add_discussion_id_to_message.rb +5 -0
- data/db/migrate/20180605143727_add_submission_to_discussion.rb +16 -0
- data/db/migrate/20180619182555_create_subscriptions.rb +9 -0
- data/db/migrate/20180702153442_create_upvotes.rb +8 -0
- data/db/migrate/20180702175220_add_upvotes_count_to_discussions.rb +5 -0
- data/db/migrate/20180704150839_rename_assignment_status_to_submission_status.rb +5 -0
- data/lib/mumuki/laboratory.rb +2 -0
- data/lib/mumuki/laboratory/controllers.rb +2 -1
- data/lib/mumuki/laboratory/controllers/content.rb +12 -0
- data/lib/mumuki/laboratory/controllers/notifications.rb +31 -0
- data/lib/mumuki/laboratory/controllers/results_rendering.rb +1 -1
- data/lib/mumuki/laboratory/engine.rb +0 -2
- data/lib/mumuki/laboratory/evaluation/manual.rb +1 -1
- data/lib/mumuki/laboratory/locales/en.yml +37 -1
- data/lib/mumuki/laboratory/locales/es.yml +42 -1
- data/lib/mumuki/laboratory/locales/pt.yml +33 -1
- data/lib/mumuki/laboratory/status.rb +51 -44
- data/lib/mumuki/laboratory/status/discussion/closed.rb +15 -0
- data/lib/mumuki/laboratory/status/discussion/discussion.rb +56 -0
- data/lib/mumuki/laboratory/status/discussion/opened.rb +27 -0
- data/lib/mumuki/laboratory/status/discussion/pending_review.rb +15 -0
- data/lib/mumuki/laboratory/status/discussion/solved.rb +19 -0
- data/lib/mumuki/laboratory/status/submission/aborted.rb +11 -0
- data/lib/mumuki/laboratory/status/submission/errored.rb +15 -0
- data/lib/mumuki/laboratory/status/{failed.rb → submission/failed.rb} +2 -2
- data/lib/mumuki/laboratory/status/submission/manual_evaluation_pending.rb +15 -0
- data/lib/mumuki/laboratory/status/{passed.rb → submission/passed.rb} +2 -2
- data/lib/mumuki/laboratory/status/{passed_with_warnings.rb → submission/passed_with_warnings.rb} +2 -2
- data/lib/mumuki/laboratory/status/submission/pending.rb +11 -0
- data/lib/mumuki/laboratory/status/submission/running.rb +11 -0
- data/lib/mumuki/laboratory/status/submission/submission.rb +49 -0
- data/lib/mumuki/laboratory/status/{unknown.rb → submission/unknown.rb} +2 -2
- data/lib/mumuki/laboratory/version.rb +1 -1
- data/spec/controllers/chapters_controller_spec.rb +17 -0
- data/spec/controllers/discussions_controller_spec.rb +19 -0
- data/spec/dummy/config/environments/development.rb +0 -2
- data/spec/dummy/config/environments/test.rb +0 -2
- data/spec/dummy/db/schema.rb +42 -2
- data/spec/evaluation_helper.rb +1 -1
- data/spec/factories/discussion_factory.rb +8 -0
- data/spec/features/dynamic_exam_spec.rb +1 -1
- data/spec/helpers/exercise_input_helper_spec.rb +25 -0
- data/spec/helpers/test_results_rendering_spec.rb +7 -7
- data/spec/models/assignment_spec.rb +17 -2
- data/spec/models/discussion_spec.rb +153 -0
- metadata +108 -27
- data/app/models/concerns/with_status.rb +0 -43
- data/app/models/status_rendering_verbosity.rb +0 -40
- data/lib/mumuki/laboratory/controllers/messages.rb +0 -9
- data/lib/mumuki/laboratory/status/aborted.rb +0 -7
- data/lib/mumuki/laboratory/status/base.rb +0 -47
- data/lib/mumuki/laboratory/status/errored.rb +0 -15
- data/lib/mumuki/laboratory/status/manual_evaluation_pending.rb +0 -15
- data/lib/mumuki/laboratory/status/pending.rb +0 -11
- data/lib/mumuki/laboratory/status/running.rb +0 -11
- data/spec/models/randomizer_spec.rb +0 -18
- data/spec/models/verbosity_spec.rb +0 -24
@@ -1,10 +1,10 @@
|
|
1
1
|
module ExerciseInputHelper
|
2
2
|
def render_exercise_input_layout(exercise)
|
3
|
-
render "layouts/exercise_inputs/layouts/#{exercise.layout}"
|
3
|
+
render "layouts/exercise_inputs/layouts/#{exercise.layout}", exercise: exercise
|
4
4
|
end
|
5
5
|
|
6
6
|
def render_exercise_input_form(exercise)
|
7
|
-
render "layouts/exercise_inputs/forms/#{exercise
|
7
|
+
render "layouts/exercise_inputs/forms/#{input_form_for(exercise)}_form", exercise: exercise
|
8
8
|
end
|
9
9
|
|
10
10
|
def render_exercise_input_editor(form, exercise)
|
@@ -15,14 +15,38 @@ module ExerciseInputHelper
|
|
15
15
|
exercise.custom? ? 'mu-custom-editor-default-value' : 'default_content'
|
16
16
|
end
|
17
17
|
|
18
|
+
def render_exercise_read_only_editor(exercise, content)
|
19
|
+
render "layouts/exercise_inputs/read_only_editors/#{exercise.editor}", exercise: exercise, content: content
|
20
|
+
end
|
21
|
+
|
22
|
+
def input_form_for(exercise)
|
23
|
+
if exercise&.input_kids?
|
24
|
+
'kids'
|
25
|
+
else
|
26
|
+
exercise.class.name.underscore
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def should_render_exercise_tabs?(exercise, &block)
|
31
|
+
!exercise.hidden? && (exercise.queriable? || exercise.extra_visible? || block&.call)
|
32
|
+
end
|
33
|
+
|
18
34
|
def should_render_problem_tabs?(exercise, user)
|
19
|
-
|
35
|
+
should_render_exercise_tabs?(exercise) { exercise.has_messages_for? user }
|
36
|
+
end
|
37
|
+
|
38
|
+
def should_render_read_only_exercise_tabs?(discussion)
|
39
|
+
should_render_exercise_tabs?(discussion.exercise) { discussion.has_submission? }
|
20
40
|
end
|
21
41
|
|
22
42
|
def should_render_message_input?(exercise, organization = Organization.current)
|
23
43
|
exercise.is_a?(Problem) && !exercise.hidden? && organization.raise_hand_enabled?
|
24
44
|
end
|
25
45
|
|
46
|
+
def should_render_need_help_dropdown?(assignment, organization = Organization.current)
|
47
|
+
!assignment.passed? && organization.ask_for_help_enabled?
|
48
|
+
end
|
49
|
+
|
26
50
|
def render_submit_button(exercise)
|
27
51
|
options = submit_button_options(exercise)
|
28
52
|
text = t(options.t) if options.t.present?
|
@@ -34,9 +58,13 @@ module ExerciseInputHelper
|
|
34
58
|
</#{options.tag}>}.html_safe
|
35
59
|
end
|
36
60
|
|
37
|
-
def render_custom_editor(exercise)
|
61
|
+
def render_custom_editor(exercise, read_only=false)
|
38
62
|
custom_editor_tag = "mu-#{exercise.language}-custom-editor"
|
39
|
-
"<#{custom_editor_tag}> </#{custom_editor_tag}>".html_safe
|
63
|
+
"<#{custom_editor_tag} #{custom_editor_read_only if read_only}> </#{custom_editor_tag}>".html_safe
|
64
|
+
end
|
65
|
+
|
66
|
+
def custom_editor_read_only
|
67
|
+
"read-only=true"
|
40
68
|
end
|
41
69
|
|
42
70
|
def input_kids?
|
data/app/helpers/icons_helper.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module IconsHelper
|
2
2
|
#FIXME refactor names
|
3
3
|
def status_icon(status_like)
|
4
|
-
fa_icon *icon_for_status(status_like.
|
4
|
+
fa_icon *icon_for_status(status_like.to_submission_status)
|
5
5
|
end
|
6
6
|
|
7
7
|
def fixed_fa_icon(name, options={})
|
@@ -19,8 +19,16 @@ module IconsHelper
|
|
19
19
|
|
20
20
|
private
|
21
21
|
|
22
|
+
def status_fa_icon(status)
|
23
|
+
fa_icon(*icon_for_status(status))
|
24
|
+
end
|
25
|
+
|
22
26
|
def exercise_status_fa_icon(exercise)
|
23
|
-
|
27
|
+
status_fa_icon(exercise.status_for(current_user))
|
28
|
+
end
|
29
|
+
|
30
|
+
def discussion_status_fa_icon(discussion)
|
31
|
+
status_fa_icon(discussion.status)
|
24
32
|
end
|
25
33
|
|
26
34
|
def icon_for_status(s)
|
@@ -28,8 +36,17 @@ module IconsHelper
|
|
28
36
|
[iconized[:type], class: "text-#{iconized[:class]} status-icon"]
|
29
37
|
end
|
30
38
|
|
39
|
+
def label_for_status(s)
|
40
|
+
iconized = s.iconize
|
41
|
+
%Q{
|
42
|
+
<span class="text-#{iconized[:class]} status-label">
|
43
|
+
#{fa_icon "#{iconized[:type]}"}
|
44
|
+
<span>#{t s}</span>
|
45
|
+
</span>
|
46
|
+
}.html_safe
|
47
|
+
end
|
48
|
+
|
31
49
|
def icon_for_read(read)
|
32
50
|
tag('i', class: "fa fa-envelope#{read ? '-o' : ''}")
|
33
51
|
end
|
34
|
-
|
35
52
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module StatusHelper
|
2
2
|
def class_for_status(s)
|
3
|
-
s.
|
3
|
+
s.to_submission_status.iconize[:class].to_s
|
4
4
|
end
|
5
5
|
|
6
6
|
def icon_type_for_status(s)
|
7
|
-
s.
|
7
|
+
s.to_submission_status.iconize[:type].to_s
|
8
8
|
end
|
9
9
|
|
10
10
|
def class_for_exercise(exercise)
|
data/app/models/assignment.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Assignment < ApplicationRecord
|
2
|
-
include
|
2
|
+
include Contextualization
|
3
3
|
include WithMessages
|
4
4
|
|
5
5
|
belongs_to :exercise
|
@@ -10,14 +10,9 @@ class Assignment < ApplicationRecord
|
|
10
10
|
|
11
11
|
validates_presence_of :exercise, :submitter
|
12
12
|
|
13
|
-
|
14
|
-
serialize field
|
15
|
-
define_method(field) { self[field]&.map { |it| it.symbolize_keys } }
|
16
|
-
end
|
13
|
+
delegate :language, :name, to: :exercise
|
17
14
|
|
18
|
-
|
19
|
-
delegate :output_content_type, to: :language
|
20
|
-
delegate :should_retry?, to: :status
|
15
|
+
alias_attribute :status, :submission_status
|
21
16
|
|
22
17
|
scope :by_exercise_ids, -> (exercise_ids) {
|
23
18
|
where(exercise_id: exercise_ids) if exercise_ids
|
@@ -27,48 +22,10 @@ class Assignment < ApplicationRecord
|
|
27
22
|
joins(:submitter).where('users.name' => usernames) if usernames
|
28
23
|
}
|
29
24
|
|
30
|
-
def queries_with_results
|
31
|
-
queries.zip(query_results).map do |query, result|
|
32
|
-
{query: query, status: result&.dig(:status).defaulting(:pending), result: result&.dig(:result)}
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
25
|
def evaluate_manually!(teacher_evaluation)
|
37
26
|
update! status: teacher_evaluation[:status], manual_evaluation_comment: teacher_evaluation[:manual_evaluation]
|
38
27
|
end
|
39
28
|
|
40
|
-
def single_visual_result?
|
41
|
-
test_results.size == 1 && test_results.first[:title].blank? && visible_success_output?
|
42
|
-
end
|
43
|
-
|
44
|
-
def single_visual_result_html
|
45
|
-
output_content_type.to_html test_results.first[:result]
|
46
|
-
end
|
47
|
-
|
48
|
-
def results_visible?
|
49
|
-
(visible_success_output? || should_retry?) && !exercise.choices?
|
50
|
-
end
|
51
|
-
|
52
|
-
def result_preview
|
53
|
-
result.truncate(100) if should_retry?
|
54
|
-
end
|
55
|
-
|
56
|
-
def result_html
|
57
|
-
output_content_type.to_html(result)
|
58
|
-
end
|
59
|
-
|
60
|
-
def feedback_html
|
61
|
-
output_content_type.to_html(feedback)
|
62
|
-
end
|
63
|
-
|
64
|
-
def expectation_results_visible?
|
65
|
-
visible_expectation_results.present?
|
66
|
-
end
|
67
|
-
|
68
|
-
def visible_expectation_results
|
69
|
-
StatusRenderingVerbosity.visible_expectation_results(status, expectation_results || [])
|
70
|
-
end
|
71
|
-
|
72
29
|
def persist_submission!(submission)
|
73
30
|
transaction do
|
74
31
|
messages.destroy_all
|
@@ -107,6 +64,32 @@ class Assignment < ApplicationRecord
|
|
107
64
|
exercise.extra_for submitter
|
108
65
|
end
|
109
66
|
|
67
|
+
def run_update!
|
68
|
+
running!
|
69
|
+
begin
|
70
|
+
update! yield
|
71
|
+
rescue => e
|
72
|
+
errored! e.message
|
73
|
+
raise e
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def passed!
|
78
|
+
update! submission_status: :passed
|
79
|
+
end
|
80
|
+
|
81
|
+
def running!
|
82
|
+
update! submission_status: :running,
|
83
|
+
result: nil,
|
84
|
+
test_results: nil,
|
85
|
+
expectation_results: [],
|
86
|
+
manual_evaluation_comment: nil
|
87
|
+
end
|
88
|
+
|
89
|
+
def errored!(message)
|
90
|
+
update! result: message, submission_status: :errored
|
91
|
+
end
|
92
|
+
|
110
93
|
%w(query try tests).each do |key|
|
111
94
|
name = "run_#{key}!"
|
112
95
|
define_method(name) { |params| exercise.send name, params.merge(extra: extra) }
|
@@ -114,7 +97,7 @@ class Assignment < ApplicationRecord
|
|
114
97
|
|
115
98
|
def as_platform_json
|
116
99
|
navigable_parent = exercise.navigable_parent
|
117
|
-
as_json(except: [:exercise_id, :submission_id, :id, :submitter_id, :solution, :created_at, :updated_at],
|
100
|
+
as_json(except: [:exercise_id, :submission_id, :id, :submitter_id, :solution, :created_at, :updated_at, :submission_status],
|
118
101
|
include: {
|
119
102
|
guide: {
|
120
103
|
only: [:slug, :name],
|
@@ -129,6 +112,7 @@ class Assignment < ApplicationRecord
|
|
129
112
|
'sid' => submission_id,
|
130
113
|
'created_at' => updated_at,
|
131
114
|
'content' => solution,
|
115
|
+
'status' => submission_status,
|
132
116
|
'exercise' => {
|
133
117
|
'eid' => exercise.bibliotheca_id
|
134
118
|
},
|
data/app/models/book.rb
CHANGED
@@ -5,6 +5,9 @@ class Book < Content
|
|
5
5
|
has_many :chapters, -> { order(number: :asc) }, dependent: :delete_all
|
6
6
|
has_many :complements, dependent: :delete_all
|
7
7
|
|
8
|
+
has_many :exercises, through: :chapters
|
9
|
+
has_many :discussions, through: :exercises
|
10
|
+
|
8
11
|
delegate :first_lesson, to: :first_chapter
|
9
12
|
|
10
13
|
def to_s
|
data/app/models/chapter.rb
CHANGED
@@ -0,0 +1,85 @@
|
|
1
|
+
module Contextualization
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
class_methods do
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def submission_mapping
|
9
|
+
class_attrs = Submission.mapping_attributes.map { |it| submission_fields_overrides[it] || it }
|
10
|
+
class_attrs.zip Submission.mapping_attributes
|
11
|
+
end
|
12
|
+
|
13
|
+
def submission_fields_overrides
|
14
|
+
{ status: :submission_status }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
included do
|
19
|
+
serialize :submission_status, Mumuki::Laboratory::Status::Submission
|
20
|
+
validates_presence_of :submission_status
|
21
|
+
|
22
|
+
[:expectation_results, :test_results, :query_results].each do |field|
|
23
|
+
serialize field
|
24
|
+
define_method(field) { self[field]&.map { |it| it.symbolize_keys } }
|
25
|
+
end
|
26
|
+
|
27
|
+
composed_of :submission, mapping: submission_mapping, constructor: :from_attributes
|
28
|
+
|
29
|
+
delegate :visible_success_output?, to: :exercise
|
30
|
+
delegate :output_content_type, to: :language
|
31
|
+
delegate :should_retry?, :to_submission_status, :passed?, :aborted?, to: :submission_status
|
32
|
+
delegate :inspection_keywords, to: :exercise
|
33
|
+
end
|
34
|
+
|
35
|
+
def queries_with_results
|
36
|
+
queries.zip(query_results).map do |query, result|
|
37
|
+
{query: query, status: result&.dig(:status).defaulting(:pending), result: result&.dig(:result)}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def single_visual_result?
|
42
|
+
test_results.size == 1 && test_results.first[:title].blank? && visible_success_output?
|
43
|
+
end
|
44
|
+
|
45
|
+
def single_visual_result_html
|
46
|
+
output_content_type.to_html test_results.first[:result]
|
47
|
+
end
|
48
|
+
|
49
|
+
def results_visible?
|
50
|
+
(visible_success_output? || should_retry?) && !exercise.choices?
|
51
|
+
end
|
52
|
+
|
53
|
+
def result_preview
|
54
|
+
result.truncate(100) if should_retry?
|
55
|
+
end
|
56
|
+
|
57
|
+
def result_html
|
58
|
+
output_content_type.to_html(result)
|
59
|
+
end
|
60
|
+
|
61
|
+
def feedback_html
|
62
|
+
output_content_type.to_html(feedback)
|
63
|
+
end
|
64
|
+
|
65
|
+
def failed_expectation_results
|
66
|
+
(expectation_results || []).select { |it| it[:result].failed? }
|
67
|
+
end
|
68
|
+
|
69
|
+
def expectation_results_visible?
|
70
|
+
failed_expectation_results.present?
|
71
|
+
end
|
72
|
+
|
73
|
+
def visible_expectation_results
|
74
|
+
exercise.input_kids? ? failed_expectation_results.first(1) : failed_expectation_results
|
75
|
+
end
|
76
|
+
|
77
|
+
def humanized_expectation_results
|
78
|
+
visible_expectation_results.map do |it|
|
79
|
+
{
|
80
|
+
result: it[:result],
|
81
|
+
explanation: Mumukit::Inspection::Expectation.parse(it).translate(inspection_keywords)
|
82
|
+
}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -60,7 +60,7 @@ module WithAssignments
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def status_for(user)
|
63
|
-
assignment_for(user).defaulting(Mumuki::Laboratory::Status::Unknown, &:status) if user
|
63
|
+
assignment_for(user).defaulting(Mumuki::Laboratory::Status::Submission::Unknown, &:status) if user
|
64
64
|
end
|
65
65
|
|
66
66
|
def last_submission_date_for(user)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module WithDiscussionCreation::Subscription
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
has_many :discussions, foreign_key: 'initiator_id'
|
6
|
+
has_many :subscriptions
|
7
|
+
has_many :watched_discussions, through: :subscriptions, source: :discussion
|
8
|
+
end
|
9
|
+
|
10
|
+
def subscribed_to?(discussion)
|
11
|
+
discussion.subscription_for(self).present?
|
12
|
+
end
|
13
|
+
|
14
|
+
def subscribe_to!(discussion)
|
15
|
+
watched_discussions << discussion
|
16
|
+
end
|
17
|
+
|
18
|
+
def unsubscribe_to!(discussion)
|
19
|
+
watched_discussions.delete(discussion)
|
20
|
+
end
|
21
|
+
|
22
|
+
def toggle_subscription!(discussion)
|
23
|
+
if subscribed_to?(discussion)
|
24
|
+
unsubscribe_to!(discussion)
|
25
|
+
else
|
26
|
+
subscribe_to!(discussion)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def unread_discussions
|
31
|
+
subscriptions.where(read: false).map(&:discussion)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module WithDiscussionCreation::Upvote
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
has_many :upvotes
|
6
|
+
has_many :upvoted_discussions, through: :upvotes, source: :discussion
|
7
|
+
end
|
8
|
+
|
9
|
+
def upvoted?(discussion)
|
10
|
+
discussion.upvote_for(self).present?
|
11
|
+
end
|
12
|
+
|
13
|
+
def upvote!(discussion)
|
14
|
+
upvoted_discussions << discussion
|
15
|
+
end
|
16
|
+
|
17
|
+
def undo_upvote!(discussion)
|
18
|
+
upvoted_discussions.delete(discussion)
|
19
|
+
end
|
20
|
+
|
21
|
+
def toggle_upvote!(discussion)
|
22
|
+
if upvoted?(discussion)
|
23
|
+
undo_upvote!(discussion)
|
24
|
+
else
|
25
|
+
upvote!(discussion)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|