mumuki-laboratory 8.4.0 → 9.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/mumuki_laboratory/application/upload.js +69 -14
  3. data/app/assets/stylesheets/mumuki_laboratory/application/_layout.scss +3 -0
  4. data/app/assets/stylesheets/mumuki_laboratory/application/_modules.scss +1 -0
  5. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_content_show.scss +15 -2
  6. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_discussion.scss +31 -8
  7. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_medal.scss +1 -1
  8. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_menu.scss +35 -0
  9. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_profile.scss +11 -0
  10. data/app/controllers/api/base_controller.rb +0 -1
  11. data/app/controllers/api/courses_controller.rb +1 -1
  12. data/app/controllers/api/organizations_controller.rb +5 -2
  13. data/app/controllers/api/roles_controller.rb +4 -0
  14. data/app/controllers/api/users_controller.rb +6 -1
  15. data/app/controllers/application_controller.rb +1 -1
  16. data/app/controllers/concerns/with_authorization.rb +1 -16
  17. data/app/controllers/concerns/with_user_params.rb +4 -0
  18. data/app/controllers/discussions_messages_controller.rb +0 -1
  19. data/app/controllers/exam_authorization_requests_controller.rb +26 -0
  20. data/app/controllers/exam_registrations_controller.rb +6 -0
  21. data/app/controllers/users_controller.rb +8 -5
  22. data/app/helpers/application_helper.rb +4 -0
  23. data/app/helpers/breadcrumbs_helper.rb +4 -0
  24. data/app/helpers/content_view_helper.rb +19 -0
  25. data/app/helpers/exercise_input_helper.rb +8 -17
  26. data/app/helpers/icons_helper.rb +3 -11
  27. data/app/helpers/links_helper.rb +3 -3
  28. data/app/helpers/menu_bar_helper.rb +3 -3
  29. data/app/helpers/progress_bar_helper.rb +2 -2
  30. data/app/helpers/user_menu_helper.rb +18 -0
  31. data/app/views/chapters/show.html.erb +17 -16
  32. data/app/views/complements/show.html.erb +1 -1
  33. data/app/views/discussions/_message.html.erb +7 -7
  34. data/app/views/exam_authorization_requests/show.html.erb +17 -0
  35. data/app/views/exam_registrations/show.html.erb +37 -0
  36. data/app/views/exams/show.html.erb +1 -1
  37. data/app/views/{layouts → exercises}/_exercise_skipped.html.erb +0 -0
  38. data/app/views/exercises/_exercise_title_icons.html.erb +4 -0
  39. data/app/views/exercises/show.html.erb +5 -8
  40. data/app/views/{layouts → guides}/_guide.html.erb +3 -3
  41. data/app/views/guides/_guide_container.html.erb +24 -0
  42. data/app/views/{layouts → guides}/_guide_title_icons.html.erb +1 -3
  43. data/app/views/layouts/_progress_bar.html.erb +9 -7
  44. data/app/views/layouts/_progress_listing.html.erb +5 -5
  45. data/app/views/layouts/_user_menu.html.erb +21 -0
  46. data/app/views/layouts/application.html.erb +1 -6
  47. data/app/views/layouts/exercise_inputs/editors/_upload.html.erb +11 -2
  48. data/app/views/lessons/show.html.erb +1 -1
  49. data/app/views/notifications/_discussion.html.erb +1 -0
  50. data/app/views/notifications/_dropdown.html.erb +13 -0
  51. data/app/views/notifications/_exam_authorization_request.html.erb +1 -0
  52. data/app/views/notifications/_exam_registration.html.erb +1 -0
  53. data/app/views/notifications/_message.html.erb +1 -0
  54. data/app/views/users/_user_form.html.erb +10 -8
  55. data/app/views/users/discussions.html.erb +28 -0
  56. data/app/views/users/edit.html.erb +1 -1
  57. data/app/views/users/messages.html.erb +27 -0
  58. data/app/views/users/show.html.erb +4 -51
  59. data/app/views/users/terms.html.erb +2 -2
  60. data/config/routes.rb +6 -0
  61. data/lib/mumuki/laboratory/controllers/notifications.rb +3 -22
  62. data/lib/mumuki/laboratory/locales/en.yml +34 -17
  63. data/lib/mumuki/laboratory/locales/es-CL.yml +25 -8
  64. data/lib/mumuki/laboratory/locales/es.yml +30 -14
  65. data/lib/mumuki/laboratory/locales/pt.yml +27 -10
  66. data/lib/mumuki/laboratory/version.rb +1 -1
  67. data/spec/controllers/exam_authorization_requests_controller_spec.rb +40 -0
  68. data/spec/controllers/exam_registrations_controller_spec.rb +19 -0
  69. data/spec/controllers/organizations_api_controller_spec.rb +16 -9
  70. data/spec/dummy/db/schema.rb +23 -0
  71. data/spec/features/exercise_flow_spec.rb +3 -3
  72. data/spec/features/login_flow_spec.rb +1 -1
  73. data/spec/features/menu_bar_spec.rb +24 -24
  74. data/spec/features/notifications_flow_spec.rb +46 -0
  75. data/spec/features/profile_flow_spec.rb +6 -9
  76. data/spec/features/terms_flow_spec.rb +30 -0
  77. data/spec/helpers/application_helper_spec.rb +10 -0
  78. data/spec/javascripts/bridge-spec.js +2 -2
  79. data/spec/javascripts/csrf-token-spec.js +2 -2
  80. data/spec/javascripts/editors-spec.js +7 -9
  81. data/spec/javascripts/elipsis-spec.js +4 -4
  82. data/spec/javascripts/events-spec.js +7 -7
  83. data/spec/javascripts/exercise-spec.js +7 -8
  84. data/spec/javascripts/global-spec.js +3 -3
  85. data/spec/javascripts/i18n-spec.js +23 -20
  86. data/spec/javascripts/kids-button-spec.js +6 -8
  87. data/spec/javascripts/results-renderers-spec.js +5 -5
  88. data/spec/javascripts/speech-bubble-renderer-spec.js +2 -3
  89. data/spec/javascripts/submissions-store-spec.js +14 -14
  90. data/spec/javascripts/sync-mode-spec.js +3 -3
  91. data/spec/javascripts/timeout-spec.js +2 -2
  92. data/spec/javascripts/timer-spec.js +2 -2
  93. data/spec/javascripts/upload-spec.js +80 -0
  94. metadata +132 -108
  95. data/app/views/layouts/_guide_container.html.erb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5768156d24f254cf945c99755c091bc65af815819018e30c862ca29c3c5f853
4
- data.tar.gz: d6e5afe45c48ff78d0fb091f50474c2c2b26ea1862eedf1c10989d6b931f73ea
3
+ metadata.gz: d4fc890303f1598f34b8258b73ca92a3beb1d594cbdb7f00d729401df4e44f89
4
+ data.tar.gz: 8ad9aba5c0b5d11251a972f2f5354f6f3ee6c6fcb3ef62d72b592e0d6e78b66f
5
5
  SHA512:
6
- metadata.gz: 8d8948197c3172881c4e633432bf60f87228085c7154c458c3169fe4762a789ec6a1c5ecac5def061059d545ed52d3f3a2f9d72415c9b2fce15e24b3c5cb3683
7
- data.tar.gz: 4da96aac20c1f2b16f87dbf87d117d3845c30b58f17c3e8a6b16bd6a7bd18a644ccce006a591b47a9e3c5fbb07f9013472bd3dab6171ab4d17f347bdff934eba
6
+ metadata.gz: 3f44cc0d2df94e3b613abea57d4ff8a1c48628a2d3fbc1797cb2a2fdca1d54c1c639c8da8e19ddfb65c581f874927758cb1fbf673cd9cf66ed8c1b9186a5d9ca
7
+ data.tar.gz: c5e6c4b580ec812c0ff84290558f6439fab546dc2be009da77c032b9059700230da3db4e1fc0765a4560d846d6409d4e6a17f79dbbff830a10199ad4ae25a6ec
@@ -1,17 +1,72 @@
1
+ mumuki.upload = (() => {
2
+ class FileUploader {
3
+ constructor(file) {
4
+ this.file = file;
5
+ }
6
+
7
+ uploadFileIfValid() {
8
+ if (!this.file) return;
9
+
10
+ let maxFileSize = $('#mu-upload-input').attr("mu-upload-file-limit");
11
+ if (this.file.size > maxFileSize) {
12
+ return mumuki.upload.ui.showFileExceedsMaxSize();
13
+ }
14
+
15
+ mumuki.upload.ui.allowSubmissionFor(this.file.name);
16
+
17
+ const reader = new FileReader();
18
+ reader.onload = function (e) {
19
+ const contents = e.target.result;
20
+ $('#solution_content').html(contents);
21
+ };
22
+ reader.readAsText(this.file);
23
+
24
+ return reader;
25
+ }
26
+ }
27
+
28
+ class UI {
29
+ constructor() {
30
+ this.$uploadFileLimitExceeded = $('#mu-upload-file-limit-exceeded');
31
+ this.$uploadLabel = $('#mu-upload-label span');
32
+ this.$uploadLabelText = this.$uploadLabel.text();
33
+ this.$uploadIcon = $('#mu-upload-icon');
34
+ this.$btnSubmit = $('.btn-submit');
35
+ }
36
+
37
+ showFileExceedsMaxSize() {
38
+ this.$uploadFileLimitExceeded.removeClass('hidden');
39
+ this.$uploadLabel.text(this.$uploadLabelText);
40
+ this.$uploadIcon.addClass('fa-upload').removeClass('fa-file-alt');
41
+ this.$btnSubmit.addClass('disabled');
42
+ }
43
+
44
+ allowSubmissionFor(filename) {
45
+ this.$uploadFileLimitExceeded.addClass('hidden');
46
+ this.$uploadLabel.text(filename);
47
+ this.$uploadIcon.removeClass('fa-upload').addClass('fa-file-alt');
48
+ this.$btnSubmit.removeClass('disabled');
49
+ }
50
+ }
51
+
52
+ function _setUI() {
53
+ mumuki.upload.ui = new UI();
54
+ }
55
+
56
+ return {
57
+ FileUploader,
58
+ UI,
59
+
60
+ _setUI,
61
+
62
+ /** @type {UI} */
63
+ ui: null
64
+ };
65
+ })();
66
+
1
67
  mumuki.load(() => {
2
- $('#upload-input').change(function (evt) {
3
- var file = evt.target.files[0];
4
- if (!file) return;
5
-
6
- var reader = new FileReader();
7
- reader.onload = function (e) {
8
- var contents = e.target.result;
9
- $('#solution_content').html(contents);
10
- $(evt.target).val("");
11
- $('form.new_solution').submit();
12
- };
13
- reader.readAsText(file);
14
- return false;
68
+ $('#mu-upload-input').change(function (evt) {
69
+ if (!mumuki.upload.ui) mumuki.upload._setUI();
70
+ return new mumuki.upload.FileUploader(evt.target.files[0]).uploadFileIfValid();
15
71
  });
16
72
  });
17
-
@@ -122,6 +122,9 @@ hr {
122
122
 
123
123
  /* TODO: move to mumuki-styles */
124
124
  .mu-inline-block-left {
125
+ display: flex;
126
+ align-items: center;
127
+
125
128
  margin-left: 15px;
126
129
  }
127
130
 
@@ -27,4 +27,5 @@
27
27
  @import "modules/terms";
28
28
  @import "modules/timer";
29
29
  @import "modules/upload";
30
+ @import "modules/user_menu";
30
31
  @import "modules/user_profile";
@@ -1,3 +1,16 @@
1
- .chapter-description p {
2
- display: inline-block;
1
+ .mu-chapter-description p {
2
+ display: inline-block
3
+ }
4
+
5
+ .mu-content-title-icons {
6
+ display: flex;
7
+ align-items: center;
8
+
9
+ font-size: 150%;
10
+ margin-left: 15px;
11
+ margin-right: 15px;
12
+
13
+ i {
14
+ margin-left: 5px;
15
+ }
3
16
  }
@@ -5,7 +5,7 @@ $discussion-toolbar-color: #f6f6fa;
5
5
  $message-divider-color: #ecf0f1;
6
6
  $discussion-button-color: #fafafa;
7
7
  $toolbar-filter-color: #808080;
8
- $moderator-star-color: #dd9900;
8
+ $moderator-badge-color: #dd9900;
9
9
 
10
10
  .discussions-list {
11
11
  margin: 30px 0;
@@ -177,8 +177,17 @@ $moderator-star-color: #dd9900;
177
177
  width: 100%;
178
178
  }
179
179
 
180
- .moderator-star {
181
- color: $moderator-star-color;
180
+ .moderator-badge {
181
+ position: relative;
182
+ top: -2px;
183
+ margin: 2px;
184
+ font-size: 12px;
185
+ text-transform: uppercase;
186
+ color: white;
187
+ background-color: $moderator-badge-color;
188
+ border: solid $moderator-badge-color 1px;
189
+ border-radius: 5px;
190
+ padding-inline: 5px;
182
191
  }
183
192
 
184
193
  .discussion-user-menu {
@@ -326,12 +335,15 @@ summary.discussion-summary {
326
335
  .actions {
327
336
  float: right;
328
337
  a {
329
- margin-left: 5px;
338
+ margin-left: 20px;
330
339
  cursor: pointer;
331
340
  }
332
341
  .discussion-message-approved {
333
342
  text-decoration: none;
334
- &.selected {
343
+ i {
344
+ transition: color 0.3s;
345
+ }
346
+ &:hover, &.selected {
335
347
  i {
336
348
  color: $brand-success;
337
349
  }
@@ -341,17 +353,20 @@ summary.discussion-summary {
341
353
  text-decoration: none;
342
354
  i {
343
355
  position: relative;
356
+ transition: color 0.3s;
344
357
  &:after {
345
358
  position: absolute;
346
- left: 6px;
359
+ left: 10px;
360
+ top: -6px;
347
361
  content: ' ';
348
- height: 19px;
362
+ height: 30px;
349
363
  width: 2px;
350
364
  transform: rotate(-45deg);
351
365
  background-color: #aaaaaa;
366
+ transition: background-color 0.3s;
352
367
  }
353
368
  }
354
- &.selected {
369
+ &:hover, &.selected {
355
370
  i {
356
371
  color: $brand-primary;
357
372
  &:after {
@@ -360,6 +375,14 @@ summary.discussion-summary {
360
375
  }
361
376
  }
362
377
  }
378
+ .discussion-delete-message {
379
+ i {
380
+ transition: color 0.3s;
381
+ &:hover {
382
+ color: black;
383
+ }
384
+ }
385
+ }
363
386
  i {
364
387
  color: #aaaaaa
365
388
  }
@@ -28,7 +28,7 @@
28
28
  left: 20px;
29
29
  top: 17px;
30
30
 
31
- margin-right: 30px;
31
+ margin-right: 40px;
32
32
  margin-bottom: 15px;
33
33
  }
34
34
 
@@ -0,0 +1,35 @@
1
+ .mu-user-menu {
2
+ display: flex;
3
+ }
4
+
5
+ .mu-user-menu-header {
6
+ font-size: 15px;
7
+ color: $mu-color-disabled;
8
+ text-transform: uppercase;
9
+ margin-bottom: 30px;
10
+ }
11
+
12
+ .mu-user-menu-item {
13
+ font-size: 17px;
14
+ margin-bottom: 5px;
15
+
16
+ a {
17
+ color: $brand-primary;
18
+ &.active {
19
+ font-weight: bold;
20
+ }
21
+ }
22
+ }
23
+
24
+ .mu-user-menu-divider {
25
+ &.vertical {
26
+ border-left: 2px solid $mu-color-separator;
27
+ }
28
+
29
+ &.horizontal {
30
+ border-top: 2px solid $mu-color-separator;
31
+
32
+ margin: 25px 0;
33
+ width: 100%
34
+ }
35
+ }
@@ -31,11 +31,19 @@
31
31
  }
32
32
  }
33
33
 
34
+ .mu-profile-info {
35
+ display: flex;
36
+ flex-wrap: wrap;
37
+
38
+ margin-top: 20px;
39
+ }
40
+
34
41
  .mu-profile-info-left {
35
42
  display: flex;
36
43
  flex-direction: column;
37
44
  align-items: center;
38
45
  text-align: center;
46
+ flex-grow: 1;
39
47
 
40
48
  .mu-level-progress {
41
49
  position: relative;
@@ -62,8 +70,11 @@
62
70
  }
63
71
 
64
72
  .mu-profile-info-right {
73
+ flex-grow: 2;
74
+
65
75
  font-size: 20px;
66
76
  margin-top: 5px;
77
+
67
78
  div {
68
79
  margin-bottom: 15px;
69
80
  .italic {
@@ -5,7 +5,6 @@ module Api
5
5
  protect_from_forgery with: :null_session
6
6
 
7
7
  include Mumuki::Laboratory::Controllers::DynamicErrors
8
- include WithAuthorization
9
8
  include Mumuki::Laboratory::Controllers::CurrentOrganization
10
9
 
11
10
  before_action :set_current_organization!
@@ -18,7 +18,7 @@ module Api
18
18
  @course = Course.new course_params
19
19
  end
20
20
 
21
- def protection_slug
21
+ def authorization_slug
22
22
  @course.slug
23
23
  end
24
24
  end
@@ -2,8 +2,7 @@ module Api
2
2
  class OrganizationsController < BaseController
3
3
  include OrganizationsControllerTemplate
4
4
 
5
- before_action :authorize_janitor!, only: [:show, :index]
6
- before_action :authorize_admin!, only: [:update, :create]
5
+ before_action :authorize_admin!
7
6
 
8
7
  def index
9
8
  render json: { organizations: Organization.accessible_as(current_user, :janitor) }
@@ -22,6 +21,10 @@ module Api
22
21
  @organization.update! organization_params
23
22
  render json: @organization.to_resource_h
24
23
  end
24
+
25
+ def authorization_slug
26
+ '_/_'
27
+ end
25
28
  end
26
29
 
27
30
  end
@@ -48,6 +48,10 @@ module Api
48
48
  def set_slug!
49
49
  @slug = Mumukit::Auth::Slug.join_s params.to_unsafe_h
50
50
  end
51
+
52
+ def authorization_slug
53
+ @slug
54
+ end
51
55
  end
52
56
 
53
57
  end
@@ -9,8 +9,13 @@ module Api
9
9
  end
10
10
 
11
11
  def update
12
- @user.update_and_notify! user_params.except([:email, :permissions, :uid])
12
+ @user.assign_attributes user_name_params
13
+ @user.verify_name!
13
14
  render json: @user.to_resource_h
14
15
  end
16
+
17
+ def authorization_slug
18
+ '_/_'
19
+ end
15
20
  end
16
21
  end
@@ -34,8 +34,8 @@ class ApplicationController < ActionController::Base
34
34
  helper_method :current_workspace,
35
35
  :login_button,
36
36
  :notifications_count,
37
- :user_notifications_path,
38
37
  :has_notifications?,
38
+ :notifications,
39
39
  :subject,
40
40
  :should_choose_organization?,
41
41
  :current_immersive_organizations,
@@ -1,27 +1,12 @@
1
1
  module WithAuthorization
2
2
  extend ActiveSupport::Concern
3
3
 
4
- def authorize_janitor!
5
- authorize! :janitor
6
- end
7
-
8
- def authorize_admin!
9
- authorize! :admin
10
- end
11
-
12
- def authorize_owner!
13
- authorize! :owner
14
- end
15
-
16
- def authorize_moderator!
17
- authorize! :moderator
18
- end
19
-
20
4
  def authorization_slug
21
5
  protection_slug || '_/_'
22
6
  end
23
7
 
24
8
  def protection_slug
9
+ warn "protection_slug is nil, which is not probably what you want" unless @slug
25
10
  @slug
26
11
  end
27
12
  end
@@ -5,6 +5,10 @@ module WithUserParams
5
5
  params.require(:user).permit(*permissible_params).to_h
6
6
  end
7
7
 
8
+ def user_name_params
9
+ params.require(:user).permit(:first_name, :last_name).to_h
10
+ end
11
+
8
12
  def permissible_params
9
13
  User.profile_fields
10
14
  end
@@ -1,5 +1,4 @@
1
1
  class DiscussionsMessagesController < AjaxController
2
- include WithAuthorization
3
2
  include WithUserDiscussionValidation
4
3
 
5
4
  before_action :set_discussion!, only: [:create, :destroy]
@@ -0,0 +1,26 @@
1
+ class ExamAuthorizationRequestsController < ApplicationController
2
+ def show
3
+ @authorization_request = ExamAuthorizationRequest.find(params[:id])
4
+ current_user.read_notification! @authorization_request
5
+ end
6
+
7
+ def create
8
+ authorization_request = ExamAuthorizationRequest.create! authorization_request_params
9
+ current_user.read_notification! authorization_request.exam_registration
10
+ flash.notice = I18n.t :exam_authorization_request_created
11
+ end
12
+
13
+ def update
14
+ ExamAuthorizationRequest.update params[:id], authorization_request_params
15
+ flash.notice = I18n.t :exam_authorization_request_saved
16
+ redirect_to root_path
17
+ end
18
+
19
+ private
20
+
21
+ def authorization_request_params
22
+ params
23
+ .require(:exam_authorization_request).permit(:exam_id, :exam_registration_id)
24
+ .merge(user: current_user, organization: Organization.current)
25
+ end
26
+ end