mumuki-laboratory 6.1.5 → 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +5 -5
  2. data/app/assets/javascripts/application.js +1 -0
  3. data/app/assets/javascripts/application/codemirror-builder.js +11 -1
  4. data/app/assets/javascripts/application/codemirror.js +0 -1
  5. data/app/assets/javascripts/application/discussions.js +15 -2
  6. data/app/assets/javascripts/application/free-form.js +1 -1
  7. data/app/assets/javascripts/application/kids.js +3 -3
  8. data/app/assets/javascripts/application/load-error-svg.js +1 -1
  9. data/app/controllers/invitations_controller.rb +1 -1
  10. data/app/helpers/application_helper.rb +0 -22
  11. data/app/helpers/assets_helper.rb +12 -0
  12. data/app/helpers/assignment_result_helper.rb +1 -1
  13. data/app/helpers/assistance_box_helper.rb +9 -0
  14. data/app/helpers/editor_helper.rb +13 -0
  15. data/app/helpers/locale_helper.rb +11 -0
  16. data/app/helpers/menu_bar_helper.rb +13 -0
  17. data/app/helpers/multiple_file_editor_helper.rb +5 -0
  18. data/app/helpers/open_graph_helper.rb +12 -0
  19. data/app/helpers/page_title_helper.rb +11 -0
  20. data/app/views/exercise_solutions/_kids_results.html.erb +1 -1
  21. data/app/views/exercises/_read_only.html.erb +3 -1
  22. data/app/views/invitations/show.html.erb +1 -1
  23. data/app/views/layouts/_kids.html.erb +1 -1
  24. data/app/views/layouts/_main.html.erb +5 -20
  25. data/app/views/layouts/application.html.erb +2 -7
  26. data/app/views/layouts/exercise_inputs/editors/_multiple_files.html.erb +11 -12
  27. data/app/views/layouts/exercise_inputs/layouts/_input_kids.html.erb +1 -1
  28. data/app/views/layouts/exercise_inputs/read_only_editors/_code.html.erb +1 -1
  29. data/app/views/layouts/exercise_inputs/read_only_editors/_free_form.html.erb +1 -1
  30. data/app/views/layouts/exercise_inputs/read_only_editors/_multiple_files.html.erb +29 -0
  31. data/app/views/layouts/mailer.html.erb +1 -1
  32. data/app/views/layouts/modals/_kids_context.html.erb +1 -1
  33. data/config/initializers/form_builder.rb +4 -5
  34. data/lib/events.rb +1 -4
  35. data/lib/mumuki/laboratory/locales/en.yml +0 -1
  36. data/lib/mumuki/laboratory/locales/es.yml +0 -1
  37. data/lib/mumuki/laboratory/locales/pt.yml +0 -1
  38. data/lib/mumuki/laboratory/version.rb +1 -1
  39. data/public/character/kids/{yellow_context.svg → kibi_context.svg} +2 -2
  40. data/public/{amarillo.svg → kibi.svg} +2 -2
  41. data/public/{anim_amarillo.svg → kibi_animated.svg} +2 -2
  42. data/public/{amarillo_fracaso.svg → kibi_failure.svg} +2 -2
  43. data/public/{amarillo_exito.svg → kibi_success.svg} +2 -2
  44. data/public/{amarillo_exito_bailarin.svg → kibi_success_dancing.svg} +2 -2
  45. data/spec/capybara_helper.rb +4 -4
  46. data/spec/helpers/application_helper_spec.rb +0 -16
  47. data/spec/helpers/page_title_helper_spec.rb +19 -0
  48. data/spec/spec_helper.rb +2 -1
  49. data/vendor/assets/javascripts/codemirror-autorefresh.js +46 -0
  50. metadata +76 -163
  51. data/spec/factories/api_client_factory.rb +0 -18
  52. data/spec/factories/assignments_factory.rb +0 -7
  53. data/spec/factories/book_factory.rb +0 -7
  54. data/spec/factories/chapter_factory.rb +0 -16
  55. data/spec/factories/complement_factory.rb +0 -6
  56. data/spec/factories/course_factory.rb +0 -9
  57. data/spec/factories/discussion_factory.rb +0 -8
  58. data/spec/factories/exam_factory.rb +0 -9
  59. data/spec/factories/exercise_factory.rb +0 -73
  60. data/spec/factories/guide_factory.rb +0 -30
  61. data/spec/factories/invitation_factory.rb +0 -7
  62. data/spec/factories/lesson_factory.rb +0 -7
  63. data/spec/factories/login_settings_factory.rb +0 -5
  64. data/spec/factories/message_factory.rb +0 -11
  65. data/spec/factories/organization_factory.rb +0 -26
  66. data/spec/factories/topic_factory.rb +0 -9
  67. data/spec/factories/user_factory.rb +0 -8
  68. data/spec/models/api_client_spec.rb +0 -6
  69. data/spec/models/assignment_spec.rb +0 -191
  70. data/spec/models/book_import_spec.rb +0 -49
  71. data/spec/models/book_spec.rb +0 -114
  72. data/spec/models/course_spec.rb +0 -22
  73. data/spec/models/discussion_spec.rb +0 -174
  74. data/spec/models/event_generation_spec.rb +0 -189
  75. data/spec/models/event_publishing_spec.rb +0 -36
  76. data/spec/models/exam_spec.rb +0 -151
  77. data/spec/models/exercise_spec.rb +0 -494
  78. data/spec/models/guide_import_spec.rb +0 -300
  79. data/spec/models/guide_spec.rb +0 -83
  80. data/spec/models/interactive_spec.rb +0 -143
  81. data/spec/models/language_spec.rb +0 -56
  82. data/spec/models/lesson_spec.rb +0 -90
  83. data/spec/models/message_spec.rb +0 -87
  84. data/spec/models/navigation_spec.rb +0 -70
  85. data/spec/models/organization_spec.rb +0 -124
  86. data/spec/models/playground_spec.rb +0 -23
  87. data/spec/models/problem_spec.rb +0 -80
  88. data/spec/models/query_spec.rb +0 -21
  89. data/spec/models/question_spec.rb +0 -37
  90. data/spec/models/reading_spec.rb +0 -10
  91. data/spec/models/solution_spec.rb +0 -66
  92. data/spec/models/stats_spec.rb +0 -15
  93. data/spec/models/string_spec.rb +0 -9
  94. data/spec/models/topic_import_spec.rb +0 -42
  95. data/spec/models/usage_spec.rb +0 -77
  96. data/spec/models/user_changed_spec.rb +0 -35
  97. data/spec/models/user_spec.rb +0 -276
  98. data/spec/models/with_expectations_spec.rb +0 -56
@@ -1,18 +0,0 @@
1
- FactoryBot.define do
2
- factory :api_client do |t|
3
- transient do
4
- role { :janitor }
5
- grant { 'test/*' }
6
- end
7
-
8
- description { "foo" }
9
- user {
10
- create :user,
11
- first_name: 'foo',
12
- last_name: 'bar',
13
- email: 'foo+1@bar.com',
14
- uid: 'foo+1@bar.com',
15
- permissions: { role => grant }
16
- }
17
- end
18
- end
@@ -1,7 +0,0 @@
1
- FactoryBot.define do
2
- factory :assignment do
3
- status { :pending }
4
- exercise
5
- submitter { create(:user) }
6
- end
7
- end
@@ -1,7 +0,0 @@
1
- FactoryBot.define do
2
- factory :book do
3
- name { Faker::Lorem.sentence(3) }
4
- description { Faker::Lorem.sentence(30) }
5
- slug { "mumuki/mumuki-test-book-#{SecureRandom.uuid}" }
6
- end
7
- end
@@ -1,16 +0,0 @@
1
- FactoryBot.define do
2
-
3
- factory :chapter do
4
- number { Faker::Number.between(1, 40) }
5
- book { Organization.current.book rescue nil }
6
-
7
- transient do
8
- lessons { [] }
9
- name { Faker::Lorem.sentence(3) }
10
- end
11
-
12
- after(:build) do |chapter, evaluator|
13
- chapter.topic = build(:topic, name: evaluator.name, lessons: evaluator.lessons) unless evaluator.topic
14
- end
15
- end
16
- end
@@ -1,6 +0,0 @@
1
- FactoryBot.define do
2
-
3
- factory :complement, traits: [:guide_container] do
4
- book { Organization.current.book rescue nil }
5
- end
6
- end
@@ -1,9 +0,0 @@
1
- FactoryBot.define do
2
- factory :course do
3
- period { '2016' }
4
- shifts { %w(morning) }
5
- days { %w(monday wednesday) }
6
- description { 'test' }
7
- organization_id { 1 }
8
- end
9
- end
@@ -1,8 +0,0 @@
1
- FactoryBot.define do
2
- factory :discussion do
3
- title { 'A discussion' }
4
- description { 'A discussion description' }
5
- initiator { create(:user) }
6
- item { create(:exercise) }
7
- end
8
- end
@@ -1,9 +0,0 @@
1
- FactoryBot.define do
2
-
3
- factory :exam, traits: [:guide_container] do
4
- duration { Faker::Number.between(10, 60).minutes }
5
- organization { Organization.current }
6
- start_time { 5.minutes.ago }
7
- end_time { 10.minutes.since }
8
- end
9
- end
@@ -1,73 +0,0 @@
1
- FactoryBot.define do
2
-
3
- factory :language do
4
- sequence(:name) { |n| "lang#{n}" }
5
-
6
- runner_url { Faker::Internet.url }
7
- queriable { true }
8
- end
9
-
10
- factory :haskell, parent: :language do
11
- name { 'haskell' }
12
- end
13
-
14
- factory :bash, parent: :language do
15
- name { 'bash' }
16
- triable { true }
17
- stateful_console { true }
18
- end
19
-
20
- factory :text_language, parent: :language do
21
- name { 'text' }
22
- end
23
-
24
- factory :gobstones, parent: :language do
25
- name { 'gobstones' }
26
- extension { 'gbs' }
27
- queriable { false }
28
- end
29
-
30
- factory :exercise_base do
31
- language { guide ? guide.language : create(:language) }
32
- sequence(:bibliotheca_id) { |n| n }
33
- sequence(:number) { |n| n }
34
-
35
- locale { :en }
36
- guide
37
- end
38
-
39
- factory :challenge, parent: :exercise_base do
40
- layout { 'input_right' }
41
- end
42
-
43
- factory :reading, class: Reading, parent: :exercise_base do
44
- name { 'A reading' }
45
- description { 'Simple reading' }
46
- end
47
-
48
- factory :problem, class: Problem, parent: :challenge do
49
- name { 'A problem' }
50
- description { 'Simple problem' }
51
- test { 'dont care' }
52
- end
53
-
54
- factory :interactive, class: Interactive, parent: :challenge do
55
- name { 'An interactive problem' }
56
- description { 'Simple interactive problem' }
57
- goal { :query_passes }
58
- language { create(:bash) }
59
- end
60
-
61
- factory :playground, class: Playground, parent: :challenge do
62
- name { 'A Playground' }
63
- description { 'Simple playground' }
64
- end
65
-
66
- factory :exercise, parent: :problem
67
-
68
- factory :x_equal_5_exercise, parent: :exercise do
69
- test { 'describe "x" $ do
70
- it "should be equal 5" $ do
71
- x `shouldBe` 5' }
72
- end
73
- end
@@ -1,30 +0,0 @@
1
- FactoryBot.define do
2
-
3
- factory :guide do
4
- sequence(:name) { |n| "guide#{n}" }
5
- locale { 'en' }
6
- description { 'A Guide' }
7
- slug { "flbulgarelli/mumuki-sample-guide-#{SecureRandom.uuid}" }
8
- language
9
- end
10
-
11
- trait :guide_container do
12
- transient do
13
- exercises { [] }
14
- name { Faker::Lorem.sentence(3) }
15
- description { Faker::Lorem.sentence(10) }
16
- language { create(:language) }
17
- slug { "mumuki/mumuki-test-lesson-#{SecureRandom.uuid}" }
18
- end
19
-
20
- after(:build) do |lesson, evaluator|
21
- lesson.guide = build(:guide,
22
- name: evaluator.name,
23
- slug: evaluator.slug,
24
- exercises: evaluator.exercises,
25
- description: evaluator.description,
26
- language: evaluator.language) unless evaluator.guide
27
- end
28
- end
29
-
30
- end
@@ -1,7 +0,0 @@
1
- FactoryBot.define do
2
- factory :invitation do
3
- code { Faker::Lorem.sentence(6) }
4
- course { "foo/bar" }
5
- expiration_date { 5.minutes.since }
6
- end
7
- end
@@ -1,7 +0,0 @@
1
- FactoryBot.define do
2
-
3
- factory :lesson, traits: [:guide_container] do
4
- sequence(:number)
5
- topic
6
- end
7
- end
@@ -1,5 +0,0 @@
1
- FactoryBot.define do
2
- factory :all_login_settings, class: Mumukit::Login::Settings do
3
- login_methods { Mumukit::Login::Settings.login_methods }
4
- end
5
- end
@@ -1,11 +0,0 @@
1
- FactoryBot.define do
2
-
3
- factory :message do
4
- exercise_id { Faker::Internet.number(2) }
5
- assignment
6
- submission_id { assignment.id }
7
- sender { Faker::Internet.email }
8
- type { 'success' }
9
- content { Faker::Lorem.sentence(3) }
10
- end
11
- end
@@ -1,26 +0,0 @@
1
- FactoryBot.define do
2
-
3
- factory :organization do
4
- contact_email { Faker::Internet.email }
5
- description { 'a great org' }
6
- locale { 'en' }
7
- settings {}
8
- book
9
- end
10
-
11
- factory :base, parent: :organization do
12
- public { true }
13
- name { 'base' }
14
- login_methods { Mumukit::Login::Settings.login_methods }
15
- end
16
-
17
- factory :public_organization, parent: :organization do
18
- public { true }
19
- name { 'the-public-org' }
20
- login_methods { Mumukit::Login::Settings.login_methods }
21
- end
22
-
23
- factory :private_organization, parent: :organization do
24
- name { 'the-private-org' }
25
- end
26
- end
@@ -1,9 +0,0 @@
1
- FactoryBot.define do
2
-
3
- factory :topic do
4
- name { Faker::Lorem::sentence(3) }
5
- description { Faker::Lorem.paragraph(2) }
6
- slug { "mumuki/mumuki-sample-topic-#{SecureRandom.uuid}" }
7
- locale { :en }
8
- end
9
- end
@@ -1,8 +0,0 @@
1
- FactoryBot.define do
2
- factory :user do
3
- email { Faker::Internet.email }
4
- uid { email }
5
- first_name { Faker::Name.first_name }
6
- last_name { Faker::Name.last_name }
7
- end
8
- end
@@ -1,6 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ApiClient, type: :model do
4
- let(:api_client) {create :api_client}
5
- it {expect { Mumukit::Auth::Token.decode(api_client.token).verify_client!}.to_not raise_error }
6
- end
@@ -1,191 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Assignment, organization_workspace: :test do
4
-
5
- describe 'messages' do
6
- let(:student) { create(:user) }
7
- let(:problem) { create(:problem, manual_evaluation: true) }
8
- let(:assignment) { problem.assignment_for(student) }
9
- let(:message) { assignment.messages.first }
10
-
11
- before { problem.submit_solution! student, content: '...' }
12
-
13
- describe '.send_question!' do
14
- before { problem.submit_question! student, content: 'How can i solve this?' }
15
-
16
- it { expect(assignment.new_record?).to be false }
17
- it { expect(assignment.has_messages?).to be true }
18
- it { expect(message.sender).to eq student.uid }
19
- it { expect(message.content).to eq 'How can i solve this?' }
20
- it { expect(message.read).to be true }
21
- it { expect(message.assignment).to eq assignment }
22
- it { expect(message.submission_id).to eq assignment.submission_id }
23
- it { expect(message.date).to_not be nil }
24
- end
25
-
26
- describe '.receive_answer!' do
27
- before { problem.submit_question! student, content: 'How can i solve this?' }
28
- before { assignment.receive_answer! sender: 'bot@mumuki.org', content: 'Check this link' }
29
-
30
- it { expect(assignment.has_messages?).to be true }
31
- it { expect(assignment.messages.count).to eq 2 }
32
- it { expect(message.sender).to eq 'bot@mumuki.org' }
33
- it { expect(message.content).to eq 'Check this link' }
34
- it { expect(message.read).to be false }
35
- it { expect(message.assignment).to eq assignment }
36
- it { expect(message.submission_id).to eq assignment.submission_id }
37
- end
38
- end
39
-
40
- describe 'manual evaluation' do
41
- let(:user) { create(:user) }
42
- let(:exercise) { create(:exercise, manual_evaluation: true, test: nil, expectations: []) }
43
- let(:assignment) { exercise.submit_solution!(user, content: '') }
44
-
45
- it { expect(assignment.status).to eq :manual_evaluation_pending }
46
- end
47
-
48
- describe '#results_visible?' do
49
- let(:gobstones) { create(:language, visible_success_output: true) }
50
- let(:gobstones_exercise) { create(:exercise, language: gobstones) }
51
-
52
- let(:failed_submission) { create(:assignment, status: :failed) }
53
- let(:passed_submission) { create(:assignment, status: :passed, expectation_results: []) }
54
- let(:passed_submission_with_visible_output_language) { create(:assignment, status: :passed, exercise: gobstones_exercise) }
55
- let(:manual_evaluation_pending_submission) { create(:assignment, status: :manual_evaluation_pending) }
56
-
57
- it { expect(passed_submission.results_visible?).to be false }
58
- it { expect(failed_submission.should_retry?).to be true }
59
- it { expect(failed_submission.results_visible?).to be true }
60
- it { expect(passed_submission_with_visible_output_language.results_visible?).to be true }
61
- it { expect(manual_evaluation_pending_submission.results_visible?).to be false }
62
- end
63
- describe '#expectation_results_visible?' do
64
- let(:haskell) { create(:language, visible_success_output: true) }
65
- let(:exercise) { create(:exercise) }
66
- context 'should show expectation with failed submissions' do
67
- let(:failed_submission) { create(:assignment, status: :failed, expectation_results: [{binding: "foo", inspection: "HasBinding", result: :failed}]) }
68
- it { expect(failed_submission.expectation_results_visible?).to be true }
69
- it { expect(failed_submission.failed_expectation_results.size).to eq 1 }
70
- end
71
- context 'should show expectation with errored submissions' do
72
- let(:errored_submission) { create(:assignment, status: :errored, expectation_results: [{binding: "foo", inspection: "HasBinding", result: :failed}]) }
73
- it { expect(errored_submission.expectation_results_visible?).to be true }
74
- end
75
- end
76
- describe '#showable_results_visible?' do
77
- let(:failed_submission) { create(:assignment, exercise: problem, status: :failed, expectation_results: [{binding: "foo", inspection: "HasBinding", result: :failed},
78
- {binding: "bar", inspection: "HasBinding", result: :failed}]) }
79
-
80
- context 'should show all failed expectation results for regular problems' do
81
- let(:problem) { create(:problem) }
82
- it { expect(failed_submission.visible_expectation_results.size).to eq 2 }
83
- end
84
-
85
- context 'should show only the first failed expectation result for kids problems' do
86
- let(:problem) { create(:problem, layout: 'input_kids') }
87
- it { expect(failed_submission.visible_expectation_results.size).to eq 1 }
88
- end
89
- end
90
- describe '#run_update!' do
91
- let(:assignment) { create(:assignment) }
92
- context 'when run passes unstructured' do
93
- before { assignment.run_update! { {result: 'ok', status: :passed} } }
94
- it { expect(assignment.status).to eq(:passed) }
95
- it { expect(assignment.result).to eq('ok') }
96
- end
97
-
98
- context 'when run fails unstructured' do
99
- before { assignment.run_update! { {result: 'ups', status: :failed} } }
100
- it { expect(assignment.status).to eq(:failed) }
101
- it { expect(assignment.result).to eq('ups') }
102
- end
103
-
104
- context 'when run aborts unstructured' do
105
- before { assignment.run_update! { {result: 'took more thn 4 seconds', status: :aborted} } }
106
- it { expect(assignment.status).to eq(:aborted) }
107
- it { expect(assignment.result).to eq('took more thn 4 seconds') }
108
- end
109
-
110
- context 'when run passes with warnings unstructured' do
111
- let(:runner_response) do
112
- {status: :passed_with_warnings,
113
- test_results: [{title: 'true is true', status: :passed, result: ''},
114
- {title: 'false is false', status: :passed, result: ''}],
115
- expectation_results: [{binding: 'bar', inspection: 'HasBinding', result: :passed},
116
- {binding: 'foo', inspection: 'HasBinding', result: :failed}],
117
- feedback: 'foo'}
118
- end
119
- before { assignment.run_update! { runner_response } }
120
-
121
- it { expect(assignment.status).to eq(:passed_with_warnings) }
122
- it { expect(assignment.result).to be_blank }
123
- it { expect(assignment.test_results).to eq(runner_response[:test_results]) }
124
- it { expect(assignment.expectation_results).to eq(runner_response[:expectation_results]) }
125
- it { expect(assignment.feedback).to eq('foo') }
126
- end
127
- context 'when run raises exception' do
128
- before do
129
- begin
130
- assignment.run_update! { raise 'ouch' }
131
- rescue
132
- end
133
- end
134
- it { expect(assignment.status).to eq(:errored) }
135
- it { expect(assignment.result).to eq('ouch') }
136
- end
137
- end
138
-
139
- describe '#update_submissions_count!' do
140
- let(:exercise) { create(:exercise) }
141
- let(:user) { create(:user) }
142
-
143
- before do
144
- exercise.submit_solution!(user)
145
- exercise.submit_solution!(user)
146
- exercise.submit_solution!(user)
147
- end
148
-
149
- it { expect(exercise.reload.submissions_count).to eq(3) }
150
- end
151
-
152
- describe '#submission_id' do
153
- let(:exercise) { create(:exercise) }
154
- let(:user) { create(:user) }
155
-
156
- before { exercise.submit_solution!(user, content: 'foo') }
157
-
158
- it do
159
- submission_id = exercise.assignment_for(user).submission_id
160
- expect(submission_id).to be_present
161
-
162
- exercise.submit_solution!(user, content: 'bar')
163
-
164
- new_submission_id = exercise.assignment_for(user).submission_id
165
- expect(new_submission_id).to be_present
166
- expect(new_submission_id).to_not eq submission_id
167
- end
168
- end
169
-
170
- describe '#evaluate_manually!' do
171
-
172
- let(:user) { create(:user) }
173
- let(:exercise) { create(:exercise, manual_evaluation: true, test: nil, expectations: []) }
174
- let(:assignment) { exercise.submit_solution!(user, content: '') }
175
- let(:evaluated_assignment) { Assignment.find assignment.id }
176
-
177
- before { Assignment.evaluate_manually! submission_id: assignment.submission_id, manual_evaluation: '**Good**', status: 'passed_with_warnings' }
178
-
179
- it { expect(evaluated_assignment.status).to eq :passed_with_warnings }
180
- it { expect(evaluated_assignment.manual_evaluation_comment).to eq '**Good**' }
181
- end
182
-
183
- describe '#extra' do
184
- let(:user) { create(:user, email: 'some_email', first_name: 'some_first_name', last_name: 'some_last_name') }
185
- let(:exercise) { create(:exercise, extra: "/*...user_email...*/\n/*...user_first_name...*/\n/*...user_last_name...*/") }
186
- let(:assignment) { exercise.submit_solution!(user, content: '') }
187
-
188
- it { expect(assignment.extra).to eq "some_email\nsome_first_name\nsome_last_name\n" }
189
- end
190
-
191
- end