mumuki-laboratory 5.0.12 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +339 -0
  3. data/app/assets/javascripts/application/bridge.js +36 -7
  4. data/app/assets/javascripts/application/kids.js +92 -7
  5. data/app/assets/javascripts/application/submission.js +2 -1
  6. data/app/assets/stylesheets/application/modules/_highlight.scss +8 -0
  7. data/app/assets/stylesheets/application/modules/_kids.scss +92 -27
  8. data/app/controllers/api/base_controller.rb +23 -0
  9. data/app/controllers/api/courses_controller.rb +26 -0
  10. data/app/controllers/api/organizations_controller.rb +28 -0
  11. data/app/controllers/api/roles_controller.rb +47 -0
  12. data/app/controllers/api/students_controller.rb +9 -0
  13. data/app/controllers/api/teachers_controller.rb +9 -0
  14. data/app/controllers/api/users_controller.rb +18 -0
  15. data/app/controllers/assets_controller.rb +2 -1
  16. data/app/controllers/concerns/on_base_organization_only.rb +11 -0
  17. data/app/controllers/concerns/organizations_controller_template.rb +34 -0
  18. data/app/controllers/concerns/users_controller_template.rb +28 -0
  19. data/app/controllers/concerns/with_api_errors.rb +37 -0
  20. data/app/controllers/concerns/with_authorization.rb +19 -0
  21. data/app/controllers/concerns/with_errors_filter.rb +32 -0
  22. data/app/helpers/reset_button_helper.rb +1 -1
  23. data/app/models/api_client.rb +27 -0
  24. data/app/models/api_client_spec.rb +6 -0
  25. data/app/models/concerns/with_assignments.rb +4 -1
  26. data/app/models/course.rb +4 -6
  27. data/app/models/exercise/challenge.rb +5 -6
  28. data/app/models/language.rb +1 -1
  29. data/app/models/organization.rb +4 -0
  30. data/app/models/user.rb +22 -1
  31. data/app/views/exercise_solutions/_kids_results_button.html.erb +11 -0
  32. data/app/views/exercise_solutions/_results.html.erb +1 -7
  33. data/app/views/exercise_solutions/_results_button.html.erb +7 -0
  34. data/app/views/layouts/_kids.html.erb +5 -2
  35. data/app/views/layouts/exercise_inputs/editors/_custom.html.erb +1 -0
  36. data/app/views/layouts/exercise_inputs/forms/_kids_form.html.erb +3 -0
  37. data/app/views/layouts/exercise_inputs/layouts/_input_kids.html.erb +3 -3
  38. data/app/views/layouts/modals/_kids_context.html.erb +0 -3
  39. data/app/views/layouts/modals/_kids_results.html.erb +2 -0
  40. data/config/routes.rb +23 -0
  41. data/db/migrate/20180129142749_add_api_client.rb +11 -0
  42. data/lib/mumuki/laboratory/controllers/results_rendering.rb +7 -1
  43. data/lib/mumuki/laboratory/extensions/string.rb +8 -0
  44. data/lib/mumuki/laboratory/locales/en.yml +4 -0
  45. data/lib/mumuki/laboratory/locales/es.yml +4 -0
  46. data/lib/mumuki/laboratory/locales/pt.yml +4 -0
  47. data/lib/mumuki/laboratory/mumukit/auth.rb +7 -0
  48. data/lib/mumuki/laboratory/version.rb +1 -1
  49. data/public/amarillo_exito.svg +11 -0
  50. data/public/amarillo_fracaso.svg +5 -0
  51. data/public/compass_rose.svg +1417 -0
  52. data/spec/controllers/api_clients_controller.rb +26 -0
  53. data/spec/controllers/confirmations_controller_spec.rb +1 -1
  54. data/spec/controllers/courses_api_controller_spec.rb +28 -0
  55. data/spec/controllers/exercise_solutions_controller_spec.rb +1 -1
  56. data/spec/controllers/messages_controller_spec.rb +1 -1
  57. data/spec/controllers/organizations_api_controller_spec.rb +235 -0
  58. data/spec/controllers/students_api_controller_spec.rb +101 -0
  59. data/spec/controllers/users_api_controller_spec.rb +56 -0
  60. data/spec/dummy/db/schema.rb +9 -0
  61. data/spec/factories/api_client_factory.rb +18 -0
  62. data/spec/factories/course_factory.rb +9 -0
  63. data/spec/features/chapter_spec.rb +1 -1
  64. data/spec/features/complements_flow_spec.rb +1 -1
  65. data/spec/features/exams_flow_spec.rb +1 -1
  66. data/spec/features/exercise_flow_spec.rb +1 -1
  67. data/spec/features/guide_reset_spec.rb +1 -1
  68. data/spec/features/guides_flow_spec.rb +1 -1
  69. data/spec/features/home_public_flow_spec.rb +1 -1
  70. data/spec/features/lessons_flow_spec.rb +1 -1
  71. data/spec/features/links_flow_spec.rb +1 -1
  72. data/spec/features/login_flow_spec.rb +1 -1
  73. data/spec/features/profile_flow_spec.rb +1 -1
  74. data/spec/features/standard_flow_spec.rb +1 -1
  75. data/spec/helpers/application_helper_spec.rb +1 -1
  76. data/spec/helpers/email_helper_spec.rb +1 -1
  77. data/spec/helpers/exercise_input_helper_spec.rb +1 -1
  78. data/spec/helpers/with_breadcrumbs_spec.rb +1 -1
  79. data/spec/helpers/with_navigation_spec.rb +1 -1
  80. data/spec/models/assignment_spec.rb +1 -1
  81. data/spec/models/book_import_spec.rb +1 -1
  82. data/spec/models/book_spec.rb +1 -1
  83. data/spec/models/course_spec.rb +1 -1
  84. data/spec/models/event_generation_spec.rb +1 -1
  85. data/spec/models/exam_spec.rb +1 -1
  86. data/spec/models/exercise_spec.rb +11 -3
  87. data/spec/models/guide_spec.rb +1 -1
  88. data/spec/models/interactive_spec.rb +1 -1
  89. data/spec/models/lesson_spec.rb +1 -1
  90. data/spec/models/message_spec.rb +1 -1
  91. data/spec/models/navigation_spec.rb +1 -1
  92. data/spec/models/organization_spec.rb +1 -1
  93. data/spec/models/problem_spec.rb +1 -1
  94. data/spec/models/question_spec.rb +1 -1
  95. data/spec/models/reading_spec.rb +1 -1
  96. data/spec/models/solution_spec.rb +1 -1
  97. data/spec/models/usage_spec.rb +1 -1
  98. data/spec/models/user_changed_spec.rb +1 -1
  99. data/spec/models/user_spec.rb +5 -5
  100. data/spec/spec_helper.rb +19 -3
  101. metadata +37 -2
@@ -59,7 +59,8 @@ var mumuki = mumuki || {};
59
59
 
60
60
  var bridge = new mumuki.bridge.Laboratory;
61
61
 
62
- $('.btn-submit').on('click', function () {
62
+ $('.btn-submit').on('click', function (e) {
63
+ e.preventDefault();
63
64
  submitButton.disable();
64
65
  resultsBox.waiting();
65
66
 
@@ -134,3 +134,11 @@ $mu-color-highlight-prolog-atoms: $mu-color-primary;
134
134
  color: $mu-color-highlight-prolog-atoms !important;
135
135
  font-weight: normal !important;
136
136
  }
137
+
138
+ $mu-color-highlight-css-literal: #b96dba;
139
+
140
+ .css .m { color: $mu-color-highlight-literal !important; }
141
+ .css .nc { color: $mu-color-highlight-identifier !important; font-weight: bold !important; }
142
+ .css .nl { color: $mu-color-highlight-keyword !important; }
143
+ .css .n { color: $mu-color-highlight-css-literal !important; }
144
+ .css .nb { color: $mu-color-highlight-css-literal !important; }
@@ -1,4 +1,5 @@
1
- $kids-height: calc(100vh - 80px - 30px);
1
+ $kids-height: calc(100vh - 80px - 30px) !default;
2
+
2
3
  $kids-characters-height: 120px;
3
4
  $kids-speech-arrow-size: 10px;
4
5
  $kids-speech-border-color: lighten($mu-color-disabled, 20%);
@@ -24,22 +25,21 @@ $kids-speech-tabs-width: 40px;
24
25
  .mu-kids-exercise-description {
25
26
  padding-right: 15px;
26
27
  }
27
- .mu-kids-exercise-board {
28
- hr {
29
- border-top: $kids-speech-border;
30
- }
31
- }
32
28
 
33
- .mu-kids-character,
34
- .mu-kids-state {
29
+ .mu-kids-states {
30
+ margin-bottom: 15px;
31
+ }
32
+ .mu-kids-character {
35
33
  padding: 15px;
36
34
  }
37
- .mu-kids-blocks,
38
- .mu-state-final {
35
+ .mu-kids-state {
36
+ padding: 0;
37
+ }
38
+ .mu-kids-blocks {
39
39
  margin-top: 15px;
40
40
  }
41
41
  .mu-kids-state {
42
- height: calc(#{$kids-height} / 2 - 15px);
42
+ height: calc(#{$kids-height} / 2);
43
43
  }
44
44
  .mu-kids-character {
45
45
  height: $kids-characters-height;
@@ -49,19 +49,47 @@ $kids-speech-tabs-width: 40px;
49
49
  margin-left: 0;
50
50
  margin-right: 0;
51
51
  position: relative;
52
+ .mu-kids-overlay {
53
+ border-radius: 10px;
54
+ position: absolute;
55
+ z-index: 80;
56
+ background-color: white;
57
+ opacity: 0.50;
58
+ top: 0;
59
+ right: 0;
60
+ left: 0;
61
+ bottom: 0;
62
+ cursor: not-allowed;
63
+ }
64
+ .mu-kids-reset-button,
65
+ .mu-kids-compass-rose,
52
66
  .mu-kids-submit-button {
53
67
  position: absolute;
54
- bottom: 15px;
55
68
  right: 15px;
56
- width: 54px;
57
- height: 54px;
58
- z-index: 2;
69
+ width: 56px;
70
+ height: 56px;
71
+ z-index: 70; //Value defined by blockly
72
+ }
73
+ .mu-kids-compass-rose {
74
+ top: 15px;
75
+ opacity: 0.75;
76
+ }
77
+ .mu-kids-submit-button {
78
+ z-index: 90;
79
+ bottom: 15px;
59
80
  button {
60
81
  border-radius: 50%;
61
82
  width: 100%;
62
83
  height: 100%;
63
84
  }
64
85
  }
86
+ .mu-kids-reset-button {
87
+ bottom: 80px;
88
+ transform: scale(0.9);
89
+ paper-fab {
90
+ background-color: $mu-color-disabled;
91
+ }
92
+ }
65
93
 
66
94
  }
67
95
 
@@ -147,7 +175,7 @@ $kids-speech-tabs-width: 40px;
147
175
  border-radius: 10px;
148
176
  background: $kids-speech-background-color;
149
177
  border: $kids-speech-border;
150
- height: 80px;
178
+ height: 90px;
151
179
  width: 100%;
152
180
  p {
153
181
  margin-bottom: 0;
@@ -173,6 +201,28 @@ $kids-speech-tabs-width: 40px;
173
201
  content: '';
174
202
  border-style: solid;
175
203
  }
204
+
205
+ $classes: (
206
+ failed: $mu-color-danger,
207
+ passed: $mu-color-success,
208
+ aborted: $mu-color-broken,
209
+ errored: $mu-color-broken,
210
+ passed_with_warnings: $mu-color-warning
211
+ );
212
+ @each $status, $class in $classes {
213
+ $lighten-class: lighten($class, 35%);
214
+ &.#{$status} {
215
+ border: none;
216
+ background: $lighten-class;
217
+ &:before {
218
+ border: none;
219
+ }
220
+ &:after {
221
+ border-color: transparent $lighten-class;
222
+ }
223
+ }
224
+ }
225
+
176
226
  }
177
227
 
178
228
  }
@@ -181,6 +231,12 @@ $kids-speech-tabs-width: 40px;
181
231
  display: flex;
182
232
  flex-direction: column;
183
233
  align-items: center;
234
+ strong {
235
+ margin-top: 7.5px;
236
+ }
237
+ #mu-actual-state-text {
238
+ display: none;
239
+ }
184
240
  .mu-kids-state-image {
185
241
  display: flex;
186
242
  flex-direction: column;
@@ -196,7 +252,6 @@ $kids-speech-tabs-width: 40px;
196
252
  border-radius: 12px;
197
253
  }
198
254
  display: flex;
199
- margin-top: 15px;
200
255
  flex-direction: column;
201
256
  align-items: center;
202
257
  justify-content: center;
@@ -217,9 +272,6 @@ $kids-speech-tabs-width: 40px;
217
272
  background: rgba(221, 221, 136, 0.7) !important;
218
273
  outline: 3px solid $kids-speech-border-color !important;
219
274
  }
220
- span {
221
- vertical-align: middle;
222
- }
223
275
  }
224
276
  }
225
277
  }
@@ -245,18 +297,14 @@ $kids-speech-tabs-width: 40px;
245
297
  ry: 10px !important;
246
298
  }
247
299
  .blocklyScrollbarHandle {
300
+ display: none;
248
301
  fill: $kids-speech-background-color !important;
249
302
  stroke: $kids-speech-border-color !important;
250
303
  stroke-width: 1px !important;
251
304
  }
252
- .blocklyScrollbarVertical {
253
- right: 0 !important;
254
- transform: unset !important;
255
- }
305
+ .blocklyScrollbarVertical,
256
306
  .blocklyScrollbarHorizontal {
257
- right: 15px !important;
258
- transform: translateY(0) !important;
259
- bottom: 0 !important;
307
+ display: none;
260
308
  }
261
309
  .blocklyToolboxDiv {
262
310
  background-color: $kids-speech-background-color !important;
@@ -290,6 +338,7 @@ $kids-speech-tabs-width: 40px;
290
338
  .mu-kids-exercise {
291
339
  visibility: unset;
292
340
  }
341
+ .mu-kids-reset-button,
293
342
  .mu-kids-submit-button {
294
343
  display: block;
295
344
  }
@@ -302,7 +351,23 @@ $kids-speech-tabs-width: 40px;
302
351
  .mu-kids-exercise {
303
352
  visibility: hidden;
304
353
  }
354
+ .mu-kids-reset-button,
305
355
  .mu-kids-submit-button {
306
356
  display: none;
307
357
  }
308
358
  }
359
+
360
+ @media screen and (max-height: $screen-xs-min) {
361
+ .mu-kids-exercise {
362
+ height: 100vh;
363
+ min-height: 100vh;
364
+ max-height: 100vh;
365
+
366
+ .mu-kids-state {
367
+ height: 50vh;
368
+ }
369
+ .mu-kids-blocks {
370
+ height: calc(100vh - #{$kids-characters-height} - 30px);
371
+ }
372
+ }
373
+ }
@@ -0,0 +1,23 @@
1
+ module Api
2
+ class BaseController < ActionController::Base
3
+ Mumukit::Login.configure_controller! self
4
+
5
+ protect_from_forgery with: :null_session
6
+
7
+ include WithApiErrors
8
+ include WithAuthorization
9
+ include Mumuki::Laboratory::Controllers::CurrentOrganization
10
+
11
+ before_action :set_current_organization!
12
+
13
+ include OnBaseOrganizationOnly
14
+
15
+ before_action :verify_api_client!
16
+
17
+ private
18
+
19
+ def verify_api_client!
20
+ ApiClient.verify_token! Mumukit::Auth::Token.extract_from_header(request.env['HTTP_AUTHORIZATION'])
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ module Api
2
+ class CoursesController < BaseController
3
+ before_action :set_new_course!, only: :create
4
+ before_action :authorize_janitor!, only: :create
5
+
6
+ def create
7
+ @course.save!
8
+ @course.notify!
9
+ render json: @course
10
+ end
11
+
12
+ private
13
+
14
+ def course_params
15
+ params.require(:course).permit(:slug, :code, :period, :description, shifts: [], days: [])
16
+ end
17
+
18
+ def set_new_course!
19
+ @course = Course.new course_params
20
+ end
21
+
22
+ def protection_slug
23
+ @course.slug
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ module Api
2
+ class OrganizationsController < BaseController
3
+ include OrganizationsControllerTemplate
4
+
5
+ before_action :authorize_janitor!, only: [:show, :index]
6
+ before_action :authorize_owner!, only: [:update, :create]
7
+
8
+ def index
9
+ render json: { organizations: Organization.accessible_as(current_user, :janitor) }
10
+ end
11
+
12
+ def show
13
+ render json: @organization.as_platform_json
14
+ end
15
+
16
+ def create
17
+ @organization.save_and_notify!
18
+ render json: @organization.as_platform_json
19
+ end
20
+
21
+ def update
22
+ @organization.update_and_notify! organization_params
23
+
24
+ render json: @organization.as_platform_json
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,47 @@
1
+ module Api
2
+ class RolesController < BaseController
3
+ before_action :set_slug!
4
+ before_action :set_course!
5
+ before_action :set_user!, except: :create
6
+ before_action :authorize_janitor!
7
+
8
+ def create
9
+ @user = User.create_if_necessary(user_params)
10
+ @user.attach! role, @course
11
+ render json: @user
12
+ end
13
+
14
+ def attach
15
+ @user.attach! role, @course
16
+ head :ok
17
+ end
18
+
19
+ def detach
20
+ @user.detach! role, @course
21
+ head :ok
22
+ end
23
+
24
+ private
25
+
26
+ def role
27
+ raise 'Not Implemented'
28
+ end
29
+
30
+ def user_params
31
+ params.require(role).permit(:first_name, :last_name, :email, :uid, :image_url)
32
+ end
33
+
34
+ def set_course!
35
+ @course = Course.find_by!(slug: @slug)
36
+ end
37
+
38
+ def set_user!
39
+ @user = User.find_by!(uid: params[:uid])
40
+ end
41
+
42
+ def set_slug!
43
+ @slug = Mumukit::Auth::Slug.join_s params.to_unsafe_h
44
+ end
45
+ end
46
+
47
+ end
@@ -0,0 +1,9 @@
1
+ module Api
2
+ class StudentsController < RolesController
3
+ private
4
+
5
+ def role
6
+ :student
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Api
2
+ class TeachersController < RolesController
3
+ private
4
+
5
+ def role
6
+ :teacher
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ module Api
2
+ class UsersController < BaseController
3
+ include UsersControllerTemplate
4
+ before_action :authorize_janitor!
5
+
6
+ def create
7
+ @user.save!
8
+ @user.notify!
9
+ render json: @user.as_platform_json
10
+ end
11
+
12
+ def update
13
+ @user.update! user_params.except([:email, :permissions, :uid])
14
+ @user.notify!
15
+ render json: @user.as_platform_json
16
+ end
17
+ end
18
+ end
@@ -1,6 +1,7 @@
1
1
  class AssetsController < ApplicationController
2
2
 
3
- skip_before_action :verify_authenticity_token, :authorize_if_private!
3
+ protect_from_forgery except: [:theme_stylesheet, :extension_javascript]
4
+ skip_before_action :authorize_if_private!
4
5
 
5
6
  def theme_stylesheet
6
7
  render inline: Organization.current.theme_stylesheet.to_s, content_type: 'text/css'
@@ -0,0 +1,11 @@
1
+ module OnBaseOrganizationOnly
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_action :ensure_base_organization!
6
+ end
7
+
8
+ def ensure_base_organization!
9
+ raise ActionController::RoutingError, 'API must be called from base organization' unless Organization.current.base?
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ module OrganizationsControllerTemplate
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_action :set_organization!, only: [:show, :update, :edit]
6
+ before_action :set_new_organization!, only: :create
7
+ end
8
+
9
+ private
10
+
11
+ def set_new_organization!
12
+ @organization = Organization.new organization_params
13
+ end
14
+
15
+ def set_organization!
16
+ @organization = Organization.find_by! name: params[:id]
17
+ end
18
+
19
+ def protection_slug
20
+ @organization&.slug
21
+ end
22
+
23
+ def organization_params
24
+ params
25
+ .require(:organization)
26
+ .permit(:book,
27
+ :contact_email, :name, :locale, :description,
28
+ :logo_url, :banner_url, :open_graph_image_url, :favicon_url, :breadcrumb_image_url,
29
+ :raise_hand_enabled, :feedback_suggestions_enabled, :public, :immersive,
30
+ :theme_stylesheet, :extension_javascript,
31
+ :terms_of_service, :community_link, login_methods: [])
32
+ .tap { |it| it.merge!(book: Book.find_by!(slug: it[:book])) if it[:book] }
33
+ end
34
+ end