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.
- checksums.yaml +4 -4
- data/README.md +339 -0
- data/app/assets/javascripts/application/bridge.js +36 -7
- data/app/assets/javascripts/application/kids.js +92 -7
- data/app/assets/javascripts/application/submission.js +2 -1
- data/app/assets/stylesheets/application/modules/_highlight.scss +8 -0
- data/app/assets/stylesheets/application/modules/_kids.scss +92 -27
- data/app/controllers/api/base_controller.rb +23 -0
- data/app/controllers/api/courses_controller.rb +26 -0
- data/app/controllers/api/organizations_controller.rb +28 -0
- data/app/controllers/api/roles_controller.rb +47 -0
- data/app/controllers/api/students_controller.rb +9 -0
- data/app/controllers/api/teachers_controller.rb +9 -0
- data/app/controllers/api/users_controller.rb +18 -0
- data/app/controllers/assets_controller.rb +2 -1
- data/app/controllers/concerns/on_base_organization_only.rb +11 -0
- data/app/controllers/concerns/organizations_controller_template.rb +34 -0
- data/app/controllers/concerns/users_controller_template.rb +28 -0
- data/app/controllers/concerns/with_api_errors.rb +37 -0
- data/app/controllers/concerns/with_authorization.rb +19 -0
- data/app/controllers/concerns/with_errors_filter.rb +32 -0
- data/app/helpers/reset_button_helper.rb +1 -1
- data/app/models/api_client.rb +27 -0
- data/app/models/api_client_spec.rb +6 -0
- data/app/models/concerns/with_assignments.rb +4 -1
- data/app/models/course.rb +4 -6
- data/app/models/exercise/challenge.rb +5 -6
- data/app/models/language.rb +1 -1
- data/app/models/organization.rb +4 -0
- data/app/models/user.rb +22 -1
- data/app/views/exercise_solutions/_kids_results_button.html.erb +11 -0
- data/app/views/exercise_solutions/_results.html.erb +1 -7
- data/app/views/exercise_solutions/_results_button.html.erb +7 -0
- data/app/views/layouts/_kids.html.erb +5 -2
- data/app/views/layouts/exercise_inputs/editors/_custom.html.erb +1 -0
- data/app/views/layouts/exercise_inputs/forms/_kids_form.html.erb +3 -0
- data/app/views/layouts/exercise_inputs/layouts/_input_kids.html.erb +3 -3
- data/app/views/layouts/modals/_kids_context.html.erb +0 -3
- data/app/views/layouts/modals/_kids_results.html.erb +2 -0
- data/config/routes.rb +23 -0
- data/db/migrate/20180129142749_add_api_client.rb +11 -0
- data/lib/mumuki/laboratory/controllers/results_rendering.rb +7 -1
- data/lib/mumuki/laboratory/extensions/string.rb +8 -0
- data/lib/mumuki/laboratory/locales/en.yml +4 -0
- data/lib/mumuki/laboratory/locales/es.yml +4 -0
- data/lib/mumuki/laboratory/locales/pt.yml +4 -0
- data/lib/mumuki/laboratory/mumukit/auth.rb +7 -0
- data/lib/mumuki/laboratory/version.rb +1 -1
- data/public/amarillo_exito.svg +11 -0
- data/public/amarillo_fracaso.svg +5 -0
- data/public/compass_rose.svg +1417 -0
- data/spec/controllers/api_clients_controller.rb +26 -0
- data/spec/controllers/confirmations_controller_spec.rb +1 -1
- data/spec/controllers/courses_api_controller_spec.rb +28 -0
- data/spec/controllers/exercise_solutions_controller_spec.rb +1 -1
- data/spec/controllers/messages_controller_spec.rb +1 -1
- data/spec/controllers/organizations_api_controller_spec.rb +235 -0
- data/spec/controllers/students_api_controller_spec.rb +101 -0
- data/spec/controllers/users_api_controller_spec.rb +56 -0
- data/spec/dummy/db/schema.rb +9 -0
- data/spec/factories/api_client_factory.rb +18 -0
- data/spec/factories/course_factory.rb +9 -0
- data/spec/features/chapter_spec.rb +1 -1
- data/spec/features/complements_flow_spec.rb +1 -1
- data/spec/features/exams_flow_spec.rb +1 -1
- data/spec/features/exercise_flow_spec.rb +1 -1
- data/spec/features/guide_reset_spec.rb +1 -1
- data/spec/features/guides_flow_spec.rb +1 -1
- data/spec/features/home_public_flow_spec.rb +1 -1
- data/spec/features/lessons_flow_spec.rb +1 -1
- data/spec/features/links_flow_spec.rb +1 -1
- data/spec/features/login_flow_spec.rb +1 -1
- data/spec/features/profile_flow_spec.rb +1 -1
- data/spec/features/standard_flow_spec.rb +1 -1
- data/spec/helpers/application_helper_spec.rb +1 -1
- data/spec/helpers/email_helper_spec.rb +1 -1
- data/spec/helpers/exercise_input_helper_spec.rb +1 -1
- data/spec/helpers/with_breadcrumbs_spec.rb +1 -1
- data/spec/helpers/with_navigation_spec.rb +1 -1
- data/spec/models/assignment_spec.rb +1 -1
- data/spec/models/book_import_spec.rb +1 -1
- data/spec/models/book_spec.rb +1 -1
- data/spec/models/course_spec.rb +1 -1
- data/spec/models/event_generation_spec.rb +1 -1
- data/spec/models/exam_spec.rb +1 -1
- data/spec/models/exercise_spec.rb +11 -3
- data/spec/models/guide_spec.rb +1 -1
- data/spec/models/interactive_spec.rb +1 -1
- data/spec/models/lesson_spec.rb +1 -1
- data/spec/models/message_spec.rb +1 -1
- data/spec/models/navigation_spec.rb +1 -1
- data/spec/models/organization_spec.rb +1 -1
- data/spec/models/problem_spec.rb +1 -1
- data/spec/models/question_spec.rb +1 -1
- data/spec/models/reading_spec.rb +1 -1
- data/spec/models/solution_spec.rb +1 -1
- data/spec/models/usage_spec.rb +1 -1
- data/spec/models/user_changed_spec.rb +1 -1
- data/spec/models/user_spec.rb +5 -5
- data/spec/spec_helper.rb +19 -3
- metadata +37 -2
@@ -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-
|
34
|
-
|
29
|
+
.mu-kids-states {
|
30
|
+
margin-bottom: 15px;
|
31
|
+
}
|
32
|
+
.mu-kids-character {
|
35
33
|
padding: 15px;
|
36
34
|
}
|
37
|
-
.mu-kids-
|
38
|
-
|
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
|
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:
|
57
|
-
height:
|
58
|
-
z-index:
|
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:
|
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
|
-
|
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,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
|
-
|
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
|