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,56 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Language do
4
- describe 'name uniqness' do
5
- let!(:gobstones) { create(:language, name: 'Gobstones') }
6
-
7
- it { expect { create :language, name: 'gobstones' }.to raise_exception(ActiveRecord::RecordInvalid) }
8
- it { expect(Language.for_name 'gobstones').to eq gobstones }
9
- it { expect(Language.for_name nil).to be nil}
10
- end
11
-
12
- describe '#import!' do
13
- subject { create(:language, name: 'gobstones', runner_url: 'http://runner.com') }
14
- before { subject.import_from_resource_h! language_resource_h }
15
-
16
- let(:language_resource_h) { {
17
- name: "gobstones",
18
- comment_type: nil,
19
- runner_url: "http://foo",
20
- output_content_type: "html",
21
- prompt: "ム ",
22
- extension: "gbs",
23
- highlight_mode: "gobstones",
24
- visible_success_output: true,
25
- devicon: nil,
26
- triable: false,
27
- feedback: true,
28
- queriable: false,
29
- stateful_console: false,
30
- test_extension: "yml",
31
- test_template: nil,
32
- layout_js_urls: ['http://runner.com/javascripts/a.js'],
33
- layout_html_urls: ["http://runner.com/b.html", "http://runner.com/c.html"],
34
- layout_css_urls: ["http://runner.com/stylesheets/d.css"],
35
- editor_js_urls: ['http://runner.com/javascripts/aa.js'],
36
- editor_html_urls: ["http://runner.com/bb.html", "http://runner.com/cc.html"],
37
- editor_css_urls: ["http://runner.com/stylesheets/dd.css"]
38
- } }
39
-
40
- it { expect(subject.name).to eq 'gobstones' }
41
- it { expect(subject.queriable).to be false }
42
- it { expect(subject.output_content_type).to eq Mumukit::ContentType::Html }
43
- it { expect(subject.visible_success_output).to be true }
44
- it { expect(subject.highlight_mode).to eq 'gobstones' }
45
- it { expect(subject.devicon).to eq 'gobstones' }
46
- it { expect(subject.prompt).to eq 'ム ' }
47
- it { expect(subject.stateful_console).to be false }
48
- it { expect(subject.feedback).to be true }
49
- it { expect(subject.layout_js_urls).to eq ['http://runner.com/javascripts/a.js'] }
50
- it { expect(subject.layout_html_urls).to eq ['http://runner.com/b.html', 'http://runner.com/c.html'] }
51
- it { expect(subject.layout_css_urls).to eq ['http://runner.com/stylesheets/d.css'] }
52
- it { expect(subject.editor_js_urls).to eq ['http://runner.com/javascripts/aa.js'] }
53
- it { expect(subject.editor_html_urls).to eq ['http://runner.com/bb.html', 'http://runner.com/cc.html'] }
54
- it { expect(subject.editor_css_urls).to eq ['http://runner.com/stylesheets/dd.css'] }
55
- end
56
- end
@@ -1,90 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Lesson, organization_workspace: :test do
4
- let(:user) { create(:user) }
5
- describe '#friendly' do
6
- let!(:chapter) {
7
- create(:chapter, lessons: [
8
- create(:lesson),
9
- create(:lesson)
10
- ]) }
11
-
12
- let(:lesson) { chapter.lessons.second }
13
-
14
- before { reindex_current_organization! }
15
-
16
- it { expect(lesson.friendly).to eq "#{chapter.name}: #{lesson.name}" }
17
- end
18
-
19
- describe '#friendly_name' do
20
- let!(:chapter) {
21
- create(:chapter, name: 'Fundamentos De Programación', lessons: [
22
- create(:lesson),
23
- create(:lesson),
24
- create(:lesson, name: 'una guía')
25
- ]) }
26
- let(:lesson) { chapter.lessons.third }
27
-
28
- before { reindex_current_organization! }
29
-
30
- it { expect(lesson.friendly_name).to eq "#{lesson.id}-fundamentos-de-programacion-una-guia" }
31
- end
32
-
33
- describe '#navigable_name' do
34
- let!(:chapter) {
35
- create(:chapter, lessons: [
36
- create(:lesson),
37
- create(:lesson)
38
- ]) }
39
- let(:lesson) { chapter.lessons.second }
40
-
41
- before { reindex_current_organization! }
42
-
43
- it { expect(lesson.navigable_name).to eq "2. #{lesson.name}" }
44
- end
45
-
46
- describe '#next_for' do
47
- context 'when it is single' do
48
- let!(:chapter) { create(:chapter, lessons: [
49
- create(:lesson),
50
- create(:lesson)
51
- ]) }
52
- let(:lesson) { chapter.lessons.second }
53
-
54
- before { reindex_current_organization! }
55
-
56
- it { expect(lesson.next_for(user)).to be nil }
57
- end
58
-
59
- context 'when there is a next guide' do
60
- let!(:chapter) { create(:chapter, lessons: [
61
- create(:lesson),
62
- create(:lesson),
63
- create(:lesson)
64
- ]) }
65
- let(:lesson) { chapter.lessons.second }
66
- let(:other_lesson) { chapter.lessons.third }
67
-
68
- before { reindex_current_organization! }
69
-
70
- it { expect(lesson.next_for(user)).to eq other_lesson }
71
- end
72
- context 'when there are many next guides at same level' do
73
- let!(:chapter) {
74
- create(:chapter, lessons: [
75
- create(:lesson),
76
- create(:lesson),
77
- create(:lesson),
78
- create(:lesson),
79
- ]) }
80
-
81
- let(:lesson) { chapter.lessons.first }
82
- let!(:other_lesson_1) { chapter.lessons.second }
83
- let!(:other_lesson_2) { chapter.lessons.third }
84
-
85
- before { reindex_current_organization! }
86
-
87
- it { expect(lesson.next_for(user)).to eq other_lesson_1 }
88
- end
89
- end
90
- end
@@ -1,87 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Message, organization_workspace: :test do
4
- describe '#parse_json' do
5
- let(:data) {
6
- {'exercise_id' => 1,
7
- 'submission_id' => 'abcdef1',
8
- 'message' => {
9
- 'sender' => 'aguspina87@gmail.com',
10
- 'content' => 'a',
11
- 'created_at' => '1/1/1'}} }
12
-
13
- let(:expected_json) {
14
- {'submission_id' => 'abcdef1',
15
- 'content' => 'a',
16
- 'created_at' => '1/1/1',
17
- 'sender' => 'aguspina87@gmail.com'} }
18
-
19
- let(:parsed_comment) { Message.parse_json(data) }
20
-
21
- it { expect(parsed_comment).to eq(expected_json) }
22
- end
23
-
24
- describe '.import_from_resource_h!' do
25
- let(:user) { create(:user) }
26
- let(:problem) { create(:problem) }
27
-
28
- context 'when last submission' do
29
- let!(:assignment) { problem.submit_solution! user, content: '' }
30
- let(:final_assignment) { Assignment.first }
31
- let(:message) { Message.first }
32
-
33
- let!(:data) {
34
- {'exercise_id' => problem.id,
35
- 'submission_id' => assignment.submission_id,
36
- 'organization' => Organization.current.name,
37
- 'message' => {
38
- 'sender' => 'teacher@mumuki.org',
39
- 'content' => 'a',
40
- 'created_at' => '1/1/1'}} }
41
-
42
- before { Message.import_from_resource_h! data }
43
- before do
44
- assignment = problem.submit_solution! user, content: ''
45
- Message.import_from_resource_h! 'exercise_id' => problem.id,
46
- 'submission_id' => assignment.submission_id,
47
- 'organization' => Organization.current.name,
48
- 'message' => {
49
- 'sender' => 'teacher@mumuki.org',
50
- 'content' => 'a',
51
- 'created_at' => '1/1/1'}
52
- end
53
-
54
- it { expect(Message.count).to eq 1 }
55
- it { expect(message.assignment).to_not be_nil }
56
- it { expect(message.assignment).to eq final_assignment }
57
- it { expect(message.to_resource_h.except 'created_at', 'updated_at', 'date')
58
- .to json_like submission_id: message.submission_id,
59
- content: 'a',
60
- sender: 'teacher@mumuki.org',
61
- read: false,
62
- exercise: {bibliotheca_id: problem.bibliotheca_id},
63
- organization: 'test' }
64
- it { expect(final_assignment.has_messages?).to be true }
65
- end
66
-
67
- context 'when not last submission' do
68
- let!(:assignment) { problem.submit_solution! user, content: '' }
69
- let!(:data) {
70
- {'exercise_id' => problem.id,
71
- 'submission_id' => assignment.submission_id,
72
- 'organization' => Organization.current.name,
73
- 'message' => {
74
- 'sender' => 'teacher@mumuki.org',
75
- 'content' => 'a',
76
- 'type' => 'success',
77
- 'created_at' => '1/1/1'}} }
78
-
79
- before { problem.submit_solution! user, content: 'other solution' }
80
- before { Message.import_from_resource_h! data }
81
-
82
- it { expect(Message.count).to eq 0 }
83
- it { expect(Assignment.first.has_messages?).to be false }
84
- end
85
-
86
- end
87
- end
@@ -1,70 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Navigation', organization_workspace: :test do
4
- let(:organization_1) { create(:organization, name: 'org1', book: book_1) }
5
- let(:organization_2) { create(:organization, name: 'org2', book: book_2) }
6
-
7
- let(:book_1) do
8
- create(:book,
9
- complements: [create(:complement)],
10
- chapters: [
11
- create(:chapter, lessons: [
12
- create(:lesson, exercises: [
13
- create(:exercise)
14
- ]),
15
- create(:lesson)
16
- ])
17
- ])
18
- end
19
-
20
- let(:book_2) do
21
- create(:book,
22
- complements: [create(:complement)],
23
- chapters: [
24
- create(:chapter, lessons: [
25
- create(:lesson, exercises: [
26
- create(:exercise)
27
- ]),
28
- create(:lesson)
29
- ])
30
- ])
31
- end
32
-
33
- let(:chapter_1) { book_1.chapters.first }
34
- let(:chapter_2) { book_2.chapters.first }
35
-
36
- let(:lesson_1) { chapter_1.lessons.first }
37
- let(:lesson_2) { chapter_2.lessons.first }
38
-
39
- let(:exercise_1) { lesson_1.exercises.first }
40
- let(:exercise_2) { lesson_2.exercises.first }
41
-
42
- before { reindex_organization! organization_1 }
43
- before { reindex_organization! organization_2 }
44
-
45
- it { expect(book_1.complements.first.used_in? Organization.current).to be false }
46
- it { expect(book_1.complements.first.used_in? organization_1).to be true }
47
- it { expect(book_1.complements.first.used_in? organization_2).to be false }
48
-
49
- it { expect(book_2.complements.first.used_in? Organization.current).to be false }
50
- it { expect(book_2.complements.first.used_in? organization_1).to be false }
51
- it { expect(book_2.complements.first.used_in? organization_2).to be true }
52
-
53
- it { expect(chapter_1.used_in? organization_1).to be true }
54
- it { expect(chapter_1.used_in? organization_2).to be false }
55
-
56
- it { expect(chapter_2.used_in? organization_1).to be false }
57
- it { expect(chapter_2.used_in? organization_2).to be true }
58
-
59
- it { expect(lesson_1.used_in? organization_1).to be true }
60
- it { expect(lesson_1.used_in? organization_2).to be false }
61
-
62
- it { expect(lesson_2.used_in? organization_1).to be false }
63
- it { expect(lesson_2.used_in? organization_2).to be true }
64
-
65
- it { expect(exercise_1.used_in? organization_1).to be true }
66
- it { expect(exercise_1.used_in? organization_2).to be false }
67
-
68
- it { expect(exercise_2.used_in? organization_1).to be false }
69
- it { expect(exercise_2.used_in? organization_2).to be true }
70
- end
@@ -1,124 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Organization, organization_workspace: :test do
4
- let(:user) { create(:user) }
5
- let(:central) { create(:organization, name: 'central') }
6
-
7
- describe '.import_from_resource_h!' do
8
- let(:book) { create(:book) }
9
- let(:resource_h) { {
10
- name: 'zulema',
11
- book: book.slug,
12
- profile: { locale: 'es', contact_email: 'contact@email.com' }
13
- } }
14
- let!(:imported) { Organization.import_from_resource_h! resource_h }
15
- let(:found) { Organization.find_by(name: 'zulema').to_resource_h }
16
-
17
- it { expect(imported).to_not be nil }
18
- it { expect(found).to json_eq resource_h, except: [:theme, :settings] }
19
- end
20
-
21
- describe '.current' do
22
- let(:organization) { Organization.find_by(name: 'test') }
23
- it { expect(organization).to_not be nil }
24
- it { expect(organization).to eq Organization.current }
25
- end
26
-
27
- describe 'defaults' do
28
- let(:fresh_organization) { create(:organization, name: 'bar') }
29
-
30
- context 'no base organization' do
31
- it { expect(fresh_organization.settings.customized_login_methods?).to be true }
32
- it { expect(fresh_organization.theme_stylesheet).to eq nil }
33
- end
34
-
35
- context 'with base organization' do
36
- before { create(:base, theme_stylesheet: '.foo { width: 100%; }') }
37
-
38
- it { expect(fresh_organization.settings.customized_login_methods?).to be true }
39
- it { expect(fresh_organization.theme_stylesheet).to eq '.foo { width: 100%; }' }
40
- end
41
- end
42
-
43
- describe '#notify_recent_assignments!' do
44
- it { expect { Organization.current.notify_recent_assignments! 1.minute.ago }.to_not raise_error }
45
- end
46
-
47
- describe 'restricter_login_methods?' do
48
- let(:private_organization) { create(:private_organization, name: 'digitaldojo') }
49
- let(:public_organization) { create(:public_organization, name: 'guolok') }
50
-
51
- it { expect(private_organization.settings.customized_login_methods?).to be true }
52
- it { expect(private_organization.private?).to be true }
53
-
54
- it { expect { private_organization.update! public: true }.to raise_error('Validation failed: A public organization can not restrict login methods') }
55
-
56
- it { expect(public_organization.settings.customized_login_methods?).to be false }
57
- it { expect(public_organization.private?).to be false }
58
- end
59
-
60
- describe '#notify_assignments_by!' do
61
- it { expect { Organization.current.notify_assignments_by! user }.to_not raise_error }
62
- end
63
-
64
- describe '#in_path?' do
65
- let(:organization) { Organization.current }
66
- let!(:chapter_in_path) { create(:chapter, lessons: [
67
- create(:lesson, exercises: [
68
- create(:exercise),
69
- create(:exercise)
70
- ]),
71
- create(:lesson)
72
- ]) }
73
- let(:topic_in_path) { chapter_in_path.lessons.first }
74
- let(:topic_in_path) { chapter_in_path.topic }
75
- let(:lesson_in_path) { chapter_in_path.lessons.first }
76
- let(:guide_in_path) { lesson_in_path.guide }
77
- let(:exercise_in_path) { lesson_in_path.exercises.first }
78
-
79
- let!(:orphan_exercise) { create(:exercise) }
80
- let!(:orphan_guide) { orphan_exercise.guide }
81
-
82
- before { reindex_current_organization! }
83
-
84
- it { expect(organization.in_path? orphan_guide).to be false }
85
- it { expect(organization.in_path? orphan_exercise).to be false }
86
-
87
- it { expect(organization.in_path? chapter_in_path).to be true }
88
- it { expect(organization.in_path? topic_in_path).to be true }
89
- it { expect(organization.in_path? lesson_in_path).to be true }
90
- it { expect(organization.in_path? guide_in_path).to be true }
91
- end
92
-
93
-
94
- describe 'login_settings' do
95
- let(:fresh_organization) { create(:organization, name: 'foo') }
96
- it { expect(fresh_organization.login_settings.login_methods).to eq Mumukit::Login::Settings.default_methods }
97
- it { expect(fresh_organization.login_settings.social_login_methods).to eq [] }
98
- end
99
-
100
- describe 'validations' do
101
- let(:book) { create :book }
102
-
103
- context 'is valid when all is ok' do
104
- let(:organization) { build :public_organization }
105
- it { expect(organization.valid?).to be true }
106
- end
107
-
108
- context 'is invalid when there are no books' do
109
- let(:organization) { build :public_organization, book: nil }
110
- it { expect(organization.valid?).to be false }
111
- end
112
-
113
- context 'is invalid when the locale isnt known' do
114
- let(:organization) { build :public_organization, locale: 'uk-DA' }
115
- it { expect(organization.valid?).to be false }
116
- end
117
-
118
- context 'has login method' do
119
- let(:organization) { build :public_organization, login_methods: ['github'] }
120
- it { expect(organization.has_login_method? 'github').to be true }
121
- it { expect(organization.has_login_method? 'google').to be false }
122
- end
123
- end
124
- end
@@ -1,23 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Playground do
4
- let(:user) { create(:user) }
5
-
6
- describe '#create' do
7
- context 'when language is queriable and exercise is playable' do
8
- let(:language) { create(:language, queriable: true) }
9
- let(:guide) { create(:guide) }
10
- let(:exercise) { build(:playground, language: language, layout: :input_bottom, guide: guide, number: 1) }
11
-
12
- it { expect(exercise.save).to be true }
13
- end
14
-
15
- context 'when language is not queriable and exercise is playable' do
16
- let(:language) { create(:language, queriable: false) }
17
- let(:exercise) { build(:playground, language: language, layout: :input_bottom) }
18
-
19
- it { expect(exercise.save).to be false }
20
- end
21
- end
22
-
23
- end