mumuki-laboratory 9.14.0 → 9.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/mumuki_laboratory/application/codemirror-builder.js +6 -2
  3. data/app/assets/javascripts/mumuki_laboratory/application/codemirror.js +3 -2
  4. data/app/assets/javascripts/mumuki_laboratory/application/console.js +7 -1
  5. data/app/assets/javascripts/mumuki_laboratory/application/csrf-token.js +5 -5
  6. data/app/assets/javascripts/mumuki_laboratory/application/discussions.js +8 -13
  7. data/app/assets/javascripts/mumuki_laboratory/application/exercise.js +35 -0
  8. data/app/assets/javascripts/mumuki_laboratory/application/i18n.js +4 -0
  9. data/app/controllers/ajax_controller.rb +5 -0
  10. data/app/controllers/application_controller.rb +2 -2
  11. data/app/helpers/discussions_helper.rb +4 -1
  12. data/app/helpers/editor_helper.rb +2 -2
  13. data/app/helpers/exams_helper.rb +23 -0
  14. data/app/helpers/exercise_input_helper.rb +0 -4
  15. data/app/helpers/menu_bar_helper.rb +5 -4
  16. data/app/helpers/notifications_helper.rb +1 -1
  17. data/app/helpers/time_helper.rb +12 -0
  18. data/app/helpers/time_zone_helper.rb +5 -1
  19. data/app/helpers/user_discussions_helper.rb +7 -7
  20. data/app/views/book/show.html.erb +4 -2
  21. data/app/views/discussions/_actions.html.erb +1 -0
  22. data/app/views/discussions/_basic_actions.html.erb +20 -0
  23. data/app/views/discussions/_description_message.html.erb +1 -1
  24. data/app/views/discussions/_message.html.erb +2 -2
  25. data/app/views/discussions/new.html.erb +7 -1
  26. data/app/views/discussions/show.html.erb +1 -18
  27. data/app/views/exercises/_read_only.html.erb +56 -70
  28. data/app/views/exercises/show.html.erb +1 -0
  29. data/app/views/layouts/_discussions_list.html.erb +1 -1
  30. data/app/views/layouts/_messages.html.erb +1 -1
  31. data/app/views/users/_user_form.html.erb +1 -1
  32. data/app/views/users/messages.html.erb +1 -1
  33. data/app/views/users/notifications.html.erb +1 -1
  34. data/lib/mumuki/laboratory/locales/en.yml +5 -0
  35. data/lib/mumuki/laboratory/locales/es-CL.yml +5 -0
  36. data/lib/mumuki/laboratory/locales/es.yml +5 -0
  37. data/lib/mumuki/laboratory/locales/pt.yml +5 -0
  38. data/lib/mumuki/laboratory/version.rb +1 -1
  39. data/spec/features/not_found_private_flow_spec.rb +1 -1
  40. metadata +113 -109
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ad2aade204189333166666c1e645465a61863e7157e88a3cb7f7c70fbc56531
4
- data.tar.gz: 3ba1bd40a4cce76c17a0c33ce377939f67c959ac17d09f324157d8b902a07dc7
3
+ metadata.gz: d420aa36a1219b0a8984fa03062704f55b6227b0f8009ec7fa08b8c67d0780d6
4
+ data.tar.gz: 0e0d9d6aab2633b8081464b447a90db3be572ab5ec3f9dad92d77e3824c71ade
5
5
  SHA512:
6
- metadata.gz: 404d077ba985d112f9a213b2cf548fe0c57dffe9b09d94472bf32a4505fb8cd90c3d5572d74eb2d03babe20644cdd9c7e7626bc2e3c9865fe665cbee80c95b1d
7
- data.tar.gz: c1250fb109892e4646adf02f6ddc7b86fc867377a194b0846ff0e38722e116b51357e4d4adf2a66eea06b146f18bf3134d0e35e9ef8519d8adf79d563788610d
6
+ metadata.gz: '084ffe85c17ed01338fa6ad45bfb6a24b92ec85c838432626436b216c9486b49babac048883ce1a40dd20336ebdb745bf3182d82c681c2d29b7306f6b9a9e783'
7
+ data.tar.gz: bfb035582b7227797d88fc2f66dd9912d6366f32d5b4428cee0e90a9d2c698f3b2989d2c60cf75d51570e3709f10bafb47fcc32db4cc819fd891c29a0a37167c
@@ -27,7 +27,11 @@
27
27
  this.$textarea = $(textarea);
28
28
  }
29
29
 
30
- setupEditor() {
30
+ setupEditor(readonly = false) {
31
+ return readonly ? this._setupReadOnlyEditor() : this._setupCommonEditor();
32
+ }
33
+
34
+ _setupCommonEditor() {
31
35
  this.editor = this.createEditor({
32
36
  lineNumbers: true,
33
37
  extraKeys: {
@@ -61,7 +65,7 @@
61
65
  return this;
62
66
  }
63
67
 
64
- setupReadOnlyEditor() {
68
+ _setupReadOnlyEditor() {
65
69
  this.editor = this.createEditor({
66
70
  readOnly: true,
67
71
  cursorBlinkRate: -1, //Hides the cursor
@@ -6,10 +6,11 @@ mumuki.page.editors = [];
6
6
  (() => {
7
7
  function createCodeMirrors() {
8
8
  return $(".editor").map(function (index, textarea) {
9
- var $textarea = $("#solution_content");
9
+ const $textarea = $("#solution_content");
10
+ const readonly = $textarea.data('readonly');
10
11
 
11
12
  return new mumuki.editor.CodeMirrorBuilder(textarea)
12
- .setupEditor()
13
+ .setupEditor(readonly)
13
14
  .setupMinLines($textarea.data('lines'))
14
15
  .setupLanguage()
15
16
  .build();
@@ -87,7 +87,7 @@
87
87
  }
88
88
  get content() {
89
89
  var firstEditor = mumuki.page.editors[0];
90
- if (firstEditor && $("#include_solution").prop("checked"))
90
+ if (firstEditor && this.includeSolution())
91
91
  return firstEditor.getValue();
92
92
  else
93
93
  return '';
@@ -142,6 +142,12 @@
142
142
  get _requestData() {
143
143
  return {content: this.content, query: this.line, cookie: this.cookie};
144
144
  }
145
+ includeSolution() {
146
+ return !this._includeSolutionCheckbox || this._includeSolutionCheckbox.checked;
147
+ }
148
+ get _includeSolutionCheckbox() {
149
+ return $("#include_solution")[0];
150
+ }
145
151
  }
146
152
 
147
153
 
@@ -1,12 +1,12 @@
1
1
  mumuki.CsrfToken = (() => {
2
2
  class CsrfToken {
3
- constructor() {
4
- this.value = $('meta[name="csrf-token"]').attr('content');
3
+ get token() {
4
+ return $('meta[name="csrf-token"]').attr('content');
5
5
  }
6
+
6
7
  newRequest(data) {
7
- var self = this;
8
- data.beforeSend = function (xhr) {
9
- xhr.setRequestHeader('X-CSRF-Token', self.value);
8
+ data.beforeSend = (xhr) => {
9
+ xhr.setRequestHeader('X-CSRF-Token', this.token);
10
10
  };
11
11
  return data;
12
12
  }
@@ -19,25 +19,18 @@ mumuki.load(() => {
19
19
  .build();
20
20
  }
21
21
 
22
- function createReadOnlyEditors() {
23
- return $(".read-only-editor").map(function (index, textarea) {
24
- var $textarea = $("#solution_content");
25
-
26
- return new mumuki.editor.CodeMirrorBuilder(textarea)
27
- .setupReadOnlyEditor()
28
- .setupMinLines($textarea.data('lines'))
29
- .setupLanguage()
30
- .build();
31
- });
32
- }
33
-
34
- createReadOnlyEditors();
35
22
  let editor = createNewMessageEditor();
36
23
 
37
24
  var Forum = {
38
25
  toggleButton: function (elements) {
39
26
  elements.toggleClass('d-none');
40
27
  },
28
+ disableButton: function (elements) {
29
+ elements.attr('disabled', true);
30
+ },
31
+ reenableButton: function (elements) {
32
+ elements.attr('disabled', false);
33
+ },
41
34
  token: new mumuki.CsrfToken(),
42
35
  tokenRequest: function (data) {
43
36
  return $.ajax(Forum.token.newRequest(data));
@@ -56,6 +49,7 @@ mumuki.load(() => {
56
49
  Forum.discussionPostAndToggle(url, $upvoteButtons);
57
50
  },
58
51
  discussionResponsible: function (url) {
52
+ Forum.disableButton($responsibleButton);
59
53
  Forum.discussionPostToggleAndRenderToast(url, $responsibleButton);
60
54
  $('.responsible-moderator-badge').toggleClass('d-none');
61
55
  },
@@ -66,6 +60,7 @@ mumuki.load(() => {
66
60
  Forum.discussionPost(url)
67
61
  .done(function (response) {
68
62
  Forum.toggleButton(elem);
63
+ Forum.reenableButton(elem);
69
64
  mumuki.toast.addToast(response);
70
65
  })
71
66
  .fail(function (response) {
@@ -1,3 +1,31 @@
1
+ (() => {
2
+ function shouldSkipChangesCheck() {
3
+ return mumuki.isKidsExercise() || mumuki.exercise.isReadOnly;
4
+ }
5
+
6
+ function solutionChangedSinceLastSubmission() {
7
+ return mumuki.exercise.id &&
8
+ mumuki.SubmissionsStore.getLastSubmissionAndResult(mumuki.exercise.id) &&
9
+ !mumuki.SubmissionsStore.getSubmissionResultFor(mumuki.exercise.id, mumuki.editors.getSubmission());
10
+ }
11
+
12
+ function shouldWarnOfChanges() {
13
+ return !shouldSkipChangesCheck() && solutionChangedSinceLastSubmission();
14
+ }
15
+
16
+ window.addEventListener("beforeunload", (event) => {
17
+ if (shouldWarnOfChanges()) {
18
+ event.returnValue = 'unsaved_progress';
19
+ } else {
20
+ delete event['returnValue'];
21
+ }
22
+ });
23
+
24
+ window.addEventListener("turbolinks:before-visit", (event) => {
25
+ if (shouldWarnOfChanges() && !confirm(mumuki.I18n.t('unsaved_progress'))) event.preventDefault();
26
+ });
27
+ })();
28
+
1
29
  /**
2
30
  * @typedef {"input_right" | "input_bottom" | "input_primary" | "input_kindergarten"} Layout
3
31
  * @typedef {{id: number, layout: Layout, settings: any}} Exercise
@@ -46,6 +74,13 @@ mumuki.exercise = {
46
74
  return this._current;
47
75
  },
48
76
 
77
+ /**
78
+ * @type {Boolean?}
79
+ */
80
+ get isReadOnly() {
81
+ return $('#mu-exercise-read-only').val() === 'true';
82
+ },
83
+
49
84
  /**
50
85
  * Set global current exercise information
51
86
  */
@@ -9,6 +9,7 @@ mumuki.I18n = (() => {
9
9
  passed_with_warnings: () => "Tu solución funcionó, pero hay cosas que mejorar",
10
10
  pending: () => "Pendiente",
11
11
  skipped: () => "Venís aprendiendo muy bien, por lo que aprobaste este ejercicio",
12
+ unsaved_progress: () => "Tu solución tiene cambios sin guardar, ¿Querés salir de todos modos?",
12
13
  },
13
14
  'es-CL': {
14
15
  aborted: () => "Ups, no pudimos evaluar tu solución",
@@ -18,6 +19,7 @@ mumuki.I18n = (() => {
18
19
  passed_with_warnings: () => "Tu solución funcionó, pero hay cosas que mejorar",
19
20
  pending: () => "Pendiente",
20
21
  skipped: () => "Vienes aprendiendo muy bien, por lo que aprobaste este ejercicio",
22
+ unsaved_progress: () => "Tu solución tiene cambios sin guardar, ¿Quieres salir de todos modos?",
21
23
  },
22
24
  'en': {
23
25
  aborted: () => "Oops, we couldn't evaluate your solution",
@@ -27,6 +29,7 @@ mumuki.I18n = (() => {
27
29
  passed_with_warnings: () => "It worked, but you can do better",
28
30
  pending: () => "Pending",
29
31
  skipped: () => "You are doing very well, so you've passed this exercise",
32
+ unsaved_progress: () => "Your solution has unsaved changes, leave anyways?",
30
33
  },
31
34
  'pt': {
32
35
  aborted: () => "Opa, não pudemos avaliar sua solução",
@@ -36,6 +39,7 @@ mumuki.I18n = (() => {
36
39
  passed_with_warnings: () => "Sua solução funcionou, mas há coisas para melhorar",
37
40
  pending: () => "Pendente",
38
41
  skipped: () => "Você está aprendendo muito bem e passou neste exercício",
42
+ unsaved_progress: () => "Sua solução tem alterações não salvas. Deseja sair mesmo assim?",
39
43
  }
40
44
  }
41
45
 
@@ -1,9 +1,14 @@
1
1
  class AjaxController < ApplicationController
2
2
  before_action :authenticate!
3
+ before_action :validate_organization_enabled!, on: :create
3
4
 
4
5
  private
5
6
 
6
7
  def authenticate!
7
8
  head 403 unless current_user?
8
9
  end
10
+
11
+ def validate_organization_enabled!
12
+ Organization.current.validate_enabled! unless current_user&.teacher_here?
13
+ end
9
14
  end
@@ -19,11 +19,11 @@ class ApplicationController < ActionController::Base
19
19
  before_action :set_time_zone!
20
20
 
21
21
  before_action :ensure_user_enabled!, if: :current_user?
22
-
23
22
  before_action :redirect_to_proper_context!, if: :immersive_context_wrong?
24
- before_action :validate_active_organization!
25
23
 
26
24
  before_action :authorize_if_private!
25
+ before_action :validate_active_organization!
26
+
27
27
  before_action :validate_user_profile!, if: :current_user?
28
28
  before_action :validate_accepted_role_terms!, if: :current_user?
29
29
  before_action :ensure_restore_progress!, if: :current_user?
@@ -184,7 +184,10 @@ module DiscussionsHelper
184
184
  end
185
185
 
186
186
  def discussion_info(discussion)
187
- "#{t(:time_since, time: time_ago_in_words(discussion.created_at))} · #{t(:reply_count, count: discussion.visible_messages.size)}"
187
+ <<~HTML.html_safe
188
+ <span>#{friendly_time(discussion.created_at, :time_since)}</span>
189
+ <span> · #{t(:reply_count, count: discussion.visible_messages.size)}</span>
190
+ HTML
188
191
  end
189
192
 
190
193
  def discussion_filter_params_without_page
@@ -7,8 +7,8 @@ module EditorHelper
7
7
  end
8
8
 
9
9
  def read_only_editor(content, language, options = {})
10
- editor_options = editor_defaults(language, options, 'read-only-editor')
11
- text_area_tag :solution_content, content, editor_options
10
+ editor_options = editor_defaults(language, options.deep_merge(data: { readonly: true }), 'editor')
11
+ text_area_tag 'solution[content]', content, editor_options
12
12
  end
13
13
 
14
14
  def spell_checked_editor(name, options = {})
@@ -0,0 +1,23 @@
1
+ module ExamsHelper
2
+ def exam_information_for(user, exam)
3
+ %Q{
4
+ #{course_information_for(user, exam)}
5
+ #{fa_icon('calendar-alt', class: 'fa-fw',
6
+ text: "<strong>#{t :date_and_time}:</strong> #{local_time_without_time_zone(exam.start_time)} - #{local_time(exam.end_time)}".html_safe)}
7
+ <br>
8
+ #{fa_icon(:stopwatch, class: 'fa-fw',
9
+ text: "<strong>#{t :available_time}:</strong> #{t :time_in_minutes, time: exam.duration}".html_safe)}
10
+ <br>
11
+ }.html_safe
12
+ end
13
+
14
+ private
15
+
16
+ def course_information_for(user, exam)
17
+ if user.teacher_here?
18
+ "#{fa_icon('graduation-cap', class: 'fa-fw',
19
+ text: "<strong>#{t :course}:</strong> #{exam.course.canonical_code}".html_safe)}
20
+ <br>"
21
+ end
22
+ end
23
+ end
@@ -35,10 +35,6 @@ module ExerciseInputHelper
35
35
  should_render_exercise_tabs?(exercise) { exercise.has_messages_for? user }
36
36
  end
37
37
 
38
- def should_render_read_only_exercise_tabs?(discussion)
39
- should_render_exercise_tabs?(discussion.exercise) { discussion.has_submission? }
40
- end
41
-
42
38
  def should_render_message_input?(exercise, organization = Organization.current)
43
39
  exercise.is_a?(Problem) && !exercise.hidden? && organization.raise_hand_enabled?
44
40
  end
@@ -38,12 +38,13 @@ module MenuBarHelper
38
38
  li_tag menu_item('sign-out-alt', :sign_out, logout_path(origin: url_for, organization: Organization.current))
39
39
  end
40
40
 
41
- def menu_item(icon, name, url, css_class = nil, **translation_params)
42
- menu_text_item(icon, t(name, translation_params), url, css_class)
41
+ def menu_item(icon, name, url, css_class = nil, translation_params = {}, options = {})
42
+ menu_text_item(icon, t(name, translation_params), url, css_class, **options)
43
43
  end
44
44
 
45
- def menu_text_item(icon, text, url, css_class = nil)
46
- link_to fixed_fa_icon(icon, text: text), url, role: 'menuitem', tabindex: '-1', class: "dropdown-item #{css_class}"
45
+ def menu_text_item(icon, text, url, css_class = nil, **options)
46
+ link_options = { role: 'menuitem', tabindex: '-1', class: "dropdown-item #{css_class}" }.merge(options)
47
+ link_to fixed_fa_icon(icon, text: text), url, link_options
47
48
  end
48
49
 
49
50
  def any_menu_bar_links?
@@ -4,7 +4,7 @@ module NotificationsHelper
4
4
  end
5
5
 
6
6
  def notification_preview_item(icon, name, url, **translation_params)
7
- menu_item icon, name, url, 'mu-notification-preview', **translation_params
7
+ menu_item icon, name, url, 'mu-notification-preview', translation_params
8
8
  end
9
9
 
10
10
  def notification_text_preview_item(icon, text, url)
@@ -0,0 +1,12 @@
1
+ module TimeHelper
2
+ def friendly_time(time, t_key = nil)
3
+ friendly_time = time_ago_in_words time
4
+ friendly_time_t = t_key ? t(t_key, time: friendly_time) : friendly_time
5
+
6
+ <<~HTML.html_safe
7
+ <time title="#{time}">
8
+ #{friendly_time_t}
9
+ </time>
10
+ HTML
11
+ end
12
+ end
@@ -1,5 +1,9 @@
1
1
  module TimeZoneHelper
2
2
  def local_time(time, time_zone = Time.zone.name)
3
- "#{l(time.in_time_zone(time_zone), format: :long)} (#{time_zone})"
3
+ "#{local_time_without_time_zone(time, time_zone)} (#{time_zone})"
4
+ end
5
+
6
+ def local_time_without_time_zone(time, time_zone = Time.zone.name)
7
+ l(time.in_time_zone(time_zone), format: :long)
4
8
  end
5
9
  end
@@ -1,6 +1,6 @@
1
1
  module UserDiscussionsHelper
2
2
  def user_discussions_table_title(discussion, user, last_read)
3
- %Q{
3
+ <<~HTML.html_safe
4
4
  <tr></tr>
5
5
  <thead>
6
6
  <tr>
@@ -9,30 +9,30 @@ module UserDiscussionsHelper
9
9
  </td>
10
10
  </tr>
11
11
  </thead>
12
- }.html_safe
12
+ HTML
13
13
  end
14
14
 
15
15
  def user_discussions_table_header
16
- %Q{
16
+ <<~HTML.html_safe
17
17
  <tr class="fw-bold">
18
18
  <td></td>
19
19
  <td>#{t(:exercise)}</td>
20
20
  <td>#{t(:discussion_created_by)}</td>
21
21
  <td>#{t(:last_message)}</td>
22
22
  </tr>
23
- }.html_safe
23
+ HTML
24
24
  end
25
25
 
26
26
  def user_discussions_table_item(discussion, user)
27
- %Q{
27
+ <<~HTML.html_safe
28
28
  <tr>
29
29
  <td class="text-center">
30
30
  #{icon_for_read(discussion.read_by?(user))}
31
31
  </td>
32
32
  <td>#{link_to discussion.item.name, item_discussion_path(discussion)}</td>
33
33
  <td>#{discussion_user_name discussion.initiator}</td>
34
- <td>#{t(:time_since, time: time_ago_in_words(discussion.last_message_date))}</td>
34
+ <td>#{friendly_time(discussion.last_message_date, :time_since)}</td>
35
35
  </tr>
36
- }.html_safe
36
+ HTML
37
37
  end
38
38
  end
@@ -45,8 +45,10 @@
45
45
  <h2><%= t(:exams) %></h2>
46
46
  <% @exams.each_with_index do |it, index| %>
47
47
  <div class="chapter">
48
- <h3> <%= index + 1 %>. <%= link_to_path_element it, mode: :plain %></h3>
49
-
48
+ <h3><%= link_to_path_element it, mode: :plain %></h3>
49
+ <div class="fs-7">
50
+ <%= exam_information_for(current_user, it) %>
51
+ </div>
50
52
  <div class="text-box">
51
53
  <%= it.guide.description_teaser_html %>
52
54
  </div>
@@ -0,0 +1 @@
1
+ <%= render partial: 'discussions/basic_actions' %>
@@ -0,0 +1,20 @@
1
+ <% if @discussion.can_toggle_responsible?(current_user) %>
2
+ <div class="discussion-responsible me-1">
3
+ <%= btn_toggle responsible_icon, not_responsible_icon, @discussion.any_responsible?, class: 'btn-sm',
4
+ onclick: "mumuki.Forum.discussionResponsible('#{responsible_discussion_url(@discussion)}')" %>
5
+ </div>
6
+ <% end %>
7
+
8
+ <% if @discussion.subscribable? %>
9
+ <div class="discussion-subscription me-1">
10
+ <%= btn_toggle subscription_icon, unsubscription_icon, current_user.subscribed_to?(@discussion), class: 'btn-sm',
11
+ onclick: "mumuki.Forum.discussionSubscription('#{subscription_discussion_url(@discussion)}')" %>
12
+ </div>
13
+ <% end %>
14
+
15
+ <% if @discussion.solved? %>
16
+ <div class="discussion-upvote">
17
+ <%= btn_toggle upvote_icon, undo_upvote_icon, current_user.upvoted?(@discussion), class: 'btn-sm',
18
+ onclick: "mumuki.Forum.discussionUpvote('#{upvote_discussion_url(@discussion)}')" %>
19
+ </div>
20
+ <% end %>
@@ -4,7 +4,7 @@
4
4
  <div class="discussion-message-bubble-title">
5
5
  <%= linked_discussion_user_name(discussion.initiator) %>
6
6
  <span class="message-date">
7
- <%= t(:time_since, time: time_ago_in_words(discussion.created_at)) %>
7
+ <%= friendly_time(discussion.created_at, :time_since) %>
8
8
  </span>
9
9
  </div>
10
10
  </div>
@@ -7,7 +7,7 @@
7
7
  <span class="moderator-badge"><%= t(:moderation) %></span>
8
8
  <% end %>
9
9
  <span class="message-date">
10
- <%= t(:time_since, time: time_ago_in_words(message.created_at)) %>
10
+ <%= friendly_time(message.created_at, :time_since) %>
11
11
  </span>
12
12
  <span class="actions">
13
13
  <% if message.authorized?(current_user) && !message.deleted? %>
@@ -47,7 +47,7 @@
47
47
  <% if current_user&.moderator_here? %>
48
48
  <hr>
49
49
  <%= t :deleted_by, deleter: message.deleted_by.name %>
50
- <%= t(:time_since, time: time_ago_in_words(message.deleted_at)) %>.
50
+ <%= friendly_time(message.deleted_at, :time_since) %>
51
51
  <a href='<%= "#deletedMessage#{message.id}" %>' data-bs-toggle="collapse">
52
52
  <%= t :show_message %>
53
53
  </a>
@@ -22,12 +22,18 @@
22
22
  <div class="container-fluid">
23
23
  <div class="row">
24
24
  <div class="discussion-new-message-content">
25
- <%= f.editor :description, '', {id: 'discussion-new-message', class: 'form-control', placeholder: t(:discussion_description_placeholder)} %>
25
+ <%= spell_checked_editor 'discussion[description]',
26
+ { id: 'discussion-new-message', placeholder: t(:discussion_description_placeholder) } %>
26
27
  </div>
27
28
  </div>
28
29
  </div>
29
30
  </div>
30
31
  </div>
32
+ <% if faqs_enabled_here? %>
33
+ <div class="fs-7">
34
+ <%= fa_icon('exclamation-triangle', text: t(:only_forum_questions_on_forum, link: link_to_faqs).html_safe) %>
35
+ </div>
36
+ <% end %>
31
37
  <%= f.submit t(:publish_discussion), class: 'btn btn-complementary w-100 discussion-new-message-button' %>
32
38
  <% end %>
33
39
  <% end %>
@@ -15,24 +15,7 @@
15
15
  <h3 class="flex-grow-1 me-3"><%= t :messages %></h3>
16
16
  <% if current_user && @discussion.persisted? && current_access_mode.show_discussion_element? %>
17
17
  <span class="d-flex">
18
- <% if @discussion.can_toggle_responsible?(current_user) %>
19
- <div class="discussion-responsible me-1">
20
- <%= btn_toggle responsible_icon, not_responsible_icon, @discussion.any_responsible?, class: 'btn-sm',
21
- onclick: "mumuki.Forum.discussionResponsible('#{responsible_discussion_url(@discussion)}')" %>
22
- </div>
23
- <% end %>
24
- <% if @discussion.subscribable? %>
25
- <div class="discussion-subscription me-1">
26
- <%= btn_toggle subscription_icon, unsubscription_icon, current_user.subscribed_to?(@discussion), class: 'btn-sm',
27
- onclick: "mumuki.Forum.discussionSubscription('#{subscription_discussion_url(@discussion)}')" %>
28
- </div>
29
- <% end %>
30
- <% if @discussion.solved? %>
31
- <div class="discussion-upvote">
32
- <%= btn_toggle upvote_icon, undo_upvote_icon, current_user.upvoted?(@discussion), class: 'btn-sm',
33
- onclick: "mumuki.Forum.discussionUpvote('#{upvote_discussion_url(@discussion)}')" %>
34
- </div>
35
- <% end %>
18
+ <%= render partial: 'discussions/actions' %>
36
19
  </span>
37
20
  <% end %>
38
21
  </div>
@@ -45,90 +45,76 @@
45
45
  <div class="accordion-body accordion-collapse collapse show" id="mu-discussion-accordion-body"
46
46
  aria-labelledby="#mu-discussion-accordion-header" data-bs-parent="#mu-discussion-accordion">
47
47
 
48
- <% if should_render_read_only_exercise_tabs?(@discussion) %>
49
- <ul class="nav nav-tabs discussion-tabs" role="tablist">
48
+ <ul class="nav nav-tabs discussion-tabs" role="tablist">
49
+ <li role="presentation">
50
+ <a class="editor-tab nav-link active" data-bs-target="#solution" aria-controls="solution" role="tab" data-bs-toggle="tab">
51
+ <%= t :solution %>
52
+ </a>
53
+ </li>
54
+ <li role="presentation">
55
+ <a class="editor-tab nav-link" data-bs-target="#results" aria-controls="results" role="tab" data-bs-toggle="tab">
56
+ <%= t :results %>
57
+ </a>
58
+ </li>
59
+ <li role="presentation">
60
+ <a class="editor-tab nav-link" data-bs-target="#content" aria-controls="content" role="tab" data-bs-toggle="tab">
61
+ <%= t :description %>
62
+ </a>
63
+ </li>
50
64
 
51
- <% if @discussion.has_submission? %>
52
- <li role="presentation">
53
- <a class="editor-tab nav-link active" data-bs-target="#solution" aria-controls="solution" role="tab" data-bs-toggle="tab">
54
- <%= t :solution %>
55
- </a>
56
- </li>
57
- <li role="presentation">
58
- <a class="editor-tab nav-link" data-bs-target="#results" aria-controls="results" role="tab" data-bs-toggle="tab">
59
- <%= t :results %>
60
- </a>
61
- </li>
62
- <% end %>
63
-
64
- <li role="presentation">
65
- <a class="editor-tab nav-link <%= "active" unless @discussion.has_submission? %>" data-bs-target="#content" aria-controls="content" role="tab" data-bs-toggle="tab">
66
- <%= t :description %>
67
- </a>
68
- </li>
69
-
70
- <% if exercise.extra_visible? %>
71
- <%= extra_code_tab %>
72
- <% end %>
65
+ <% if exercise.extra_visible? %>
66
+ <%= extra_code_tab %>
67
+ <% end %>
73
68
 
74
- <% if exercise.queriable? %>
75
- <%= console_tab %>
76
- <% end %>
77
- </ul>
69
+ <% if exercise.queriable? %>
70
+ <%= console_tab %>
71
+ <% end %>
72
+ </ul>
78
73
 
79
- <div class="tab-content">
80
- <% if @discussion.has_submission? %>
81
- <div role="tabpanel" class="tab-pane active" id="solution">
82
- <div class="mu-tab-body">
83
- <div role="tabpanel" class="tab-pane mu-input-panel fade show active" id="editor">
84
- <div class="mu-read-only-editor">
85
- <%= render_exercise_read_only_editor exercise, @discussion.solution %>
86
- </div>
87
- </div>
88
- </div>
74
+ <div class="tab-content">
75
+ <div role="tabpanel" class="tab-pane mu-input-panel fade show active" id="solution">
76
+ <div class="mu-tab-body">
77
+ <div class="mu-read-only-editor">
78
+ <%= render_exercise_read_only_editor exercise, @discussion.solution %>
89
79
  </div>
80
+ </div>
81
+ </div>
90
82
 
91
- <div role="tabpanel" class="tab-pane" id="results">
92
- <div class="mu-tab-body">
93
- <%= render layout: 'exercise_solutions/contextualization_results_container', locals: { contextualization: @discussion } do %>
94
- <div class="row">
95
- <div class="col-md-12 submission-results">
96
- <%= render partial: 'exercise_solutions/contextualization_results_body',
97
- locals: { contextualization: @discussion, guide_finished_by_solution: false } %>
98
- </div>
99
- </div>
100
- <% end %>
101
- </div>
102
- </div>
103
- <% end %>
104
-
105
- <div role="tabpanel" class="tab-pane <%= 'active' unless @discussion.has_submission? %>" id="content">
106
- <div class="mu-tab-body">
107
- <div class="exercise-assignment">
108
- <%= render partial: 'exercises/exercise_assignment', locals: { exercise: exercise } %>
83
+ <div role="tabpanel" class="tab-pane fade" id="results">
84
+ <div class="mu-tab-body">
85
+ <%= render layout: 'exercise_solutions/contextualization_results_container', locals: { contextualization: @discussion } do %>
86
+ <div class="row">
87
+ <div class="col-md-12 submission-results">
88
+ <%= render partial: 'exercise_solutions/contextualization_results_body',
89
+ locals: { contextualization: @discussion, guide_finished_by_solution: false } %>
90
+ </div>
109
91
  </div>
110
- </div>
92
+ <% end %>
111
93
  </div>
94
+ </div>
112
95
 
113
- <div role="tabpanel" class="tab-pane mu-input-panel fade" id="console">
114
- <div class="mu-overlapped-container">
115
- <div class="console">
116
- </div>
117
- <div class="mu-overlapped">
118
- <%= restart_icon %>
119
- </div>
96
+ <div role="tabpanel" class="tab-pane fade" id="content">
97
+ <div class="mu-tab-body">
98
+ <div class="exercise-assignment">
99
+ <%= render partial: 'exercises/exercise_assignment', locals: { exercise: exercise } %>
120
100
  </div>
121
101
  </div>
102
+ </div>
122
103
 
123
- <div role="tabpanel" class="tab-pane mu-input-panel fade mu-elipsis" id="visible-extra">
124
- <%= @discussion.extra_preview_html %>
104
+ <div role="tabpanel" class="tab-pane mu-input-panel fade" id="console">
105
+ <div class="mu-overlapped-container">
106
+ <div class="console">
107
+ </div>
108
+ <div class="mu-overlapped">
109
+ <%= restart_icon %>
110
+ </div>
125
111
  </div>
126
112
  </div>
127
- <% else %>
128
- <div class="exercise-assignment">
129
- <%= render partial: 'exercises/exercise_assignment', locals: { exercise: exercise } %>
113
+
114
+ <div role="tabpanel" class="tab-pane mu-input-panel fade mu-elipsis" id="visible-extra">
115
+ <%= @discussion.extra_preview_html %>
130
116
  </div>
131
- <% end %>
117
+ </div>
132
118
  </div>
133
119
  </div>
134
120
  </div>
@@ -45,6 +45,7 @@
45
45
  <%= hidden_field_tag "mu-exercise-id", @exercise.id %>
46
46
  <%= hidden_field_tag "mu-exercise-layout", @exercise.layout %>
47
47
  <%= hidden_field_tag "mu-exercise-settings", @exercise.settings.to_json %>
48
+ <%= hidden_field_tag "mu-exercise-read-only", current_access_mode.read_only? %>
48
49
 
49
50
  <div class="d-none" id="processing-template">
50
51
  <div class="bs-callout bs-callout-info">
@@ -26,7 +26,7 @@
26
26
  </span>
27
27
  <span class="discussion-initiator">
28
28
  <strong><%= discussion_user_name discussion.initiator %></strong>
29
- <%= t(:asked_time_since, time: time_ago_in_words(discussion.created_at)) %>
29
+ <%= friendly_time(discussion.created_at, :asked_time_since) %>
30
30
  <span class="discussion-status-icon">
31
31
  <%= discussion_status_fa_icon(discussion) %>
32
32
  </span>
@@ -6,7 +6,7 @@
6
6
  <div class="message">
7
7
  <p> <%= message.content_html %></p>
8
8
  <div class="sender"><%= message.sender unless message.sender == current_user_uid %></div>
9
- <time><%= time_ago_in_words message.created_at %></time>
9
+ <%= friendly_time(message.created_at) %>
10
10
  </div>
11
11
  </li>
12
12
  <% end %>
@@ -31,7 +31,7 @@
31
31
  <span> <strong><%= t :email %>:</strong> <%= @user.email %> </span>
32
32
  </div>
33
33
  <div>
34
- <span> <strong><%= t :programming_since %>:</strong> <%= t(:time_since, time: time_ago_in_words(@user.created_at)) %> </span>
34
+ <span> <strong><%= t :programming_since %>:</strong> <%= friendly_time(@user.created_at, :time_since) %> </span>
35
35
  </div>
36
36
  </div>
37
37
  </div>
@@ -20,7 +20,7 @@
20
20
  <td><%= icon_for_read(message.read?) %></td>
21
21
  <td><%= link_to message.exercise.name, exercise_path(message.exercise.id) %></td>
22
22
  <td><%= mail_to message.sender %></td>
23
- <td><%= time_ago_in_words message.created_at %></td>
23
+ <td><%= friendly_time(message.created_at) %></td>
24
24
  </tr>
25
25
  <% end %>
26
26
  </table>
@@ -38,7 +38,7 @@
38
38
  <%= render partial: "notifications/#{notification.subject}", locals: { notification: notification } %>
39
39
  </td>
40
40
  <td class="col-md-3">
41
- <%= t(:time_since, time: time_ago_in_words(notification.created_at)) %>
41
+ <%= friendly_time(notification.created_at, :time_since) %>
42
42
  </td>
43
43
  </tr>
44
44
  <% end %>
@@ -30,6 +30,7 @@ en:
30
30
  authoring: Authoring
31
31
  authoring_note_html: This guide's content was developed by %{authors} under the terms of <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">Creative Commons License Share-Alike, 4.0</a>
32
32
  authoring_note_with_collaborators_html: This guide's content was developed by %{authors} and <a href="%{collaborators}" target="_blank">many others</a>, under the terms of <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">Creative Commons License Share-Alike, 4.0</a>
33
+ available_time: Available time
33
34
  back_to_mumuki: Back to Mumuki!
34
35
  bibliotheca_ui: Bibliotheca
35
36
  birthdate: Birthdate
@@ -67,9 +68,11 @@ en:
67
68
  continue_practicing: Continue practicing!
68
69
  corollary: To think about
69
70
  correct_answer: The answer is correct!
71
+ course: Course
70
72
  create_submission: Submit
71
73
  created_at: Created at
72
74
  date: Date
75
+ date_and_time: Date and time
73
76
  deleted_by: Deleted by %{deleter}
74
77
  deleted_message_warning: If you repeateadly violate these or other rules, you may be prohibited from accessing the forum or you may suffer more severe consequences, such as being expulsed from the course.
75
78
  deletion_motive:
@@ -272,6 +275,7 @@ en:
272
275
  notifications_will_be_here: Notifications will be here
273
276
  notify_problem_with_exercise: Report a bug
274
277
  office: Office
278
+ only_forum_questions_on_forum: Remember that only exercise-related questions are answered on the forum. For any other kind of inquiries, please check the %{link}.
275
279
  only_landscape_support: Please, rotate your tablet or cellphone to continue practicing
276
280
  opened: Open
277
281
  opened_count: '%{count} opened'
@@ -360,6 +364,7 @@ en:
360
364
  terms_and_conditions_continue_disclaimer: By continuing you agree to %{terms_link}
361
365
  terms_and_conditions_must_be_accepted: You must accept the terms and conditions
362
366
  test_results: Test results
367
+ time_in_minutes: "%{time} minutes"
363
368
  time_since: "%{time} ago"
364
369
  time_left: You have
365
370
  title: Title
@@ -29,6 +29,7 @@ es-CL:
29
29
  authoring: Autores
30
30
  authoring_note_html: Esta guía fue desarrollada por %{authors} bajo los términos de la <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">Licencia Creative Commons Compartir-Igual, 4.0</a>.
31
31
  authoring_note_with_collaborators_html: Esta guía fue desarrollada por %{authors} y <a href="%{collaborators}" target="_blank">muchas personas más</a>, bajo los términos de la <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">Licencia Creative Commons Compartir-Igual, 4.0</a>.
32
+ available_time: Tiempo disponible
32
33
  back_to_mumuki: ¡Vuelve a Mumuki!
33
34
  bibliotheca_ui: Biblioteca
34
35
  birthdate: Fecha de nacimiento
@@ -65,11 +66,13 @@ es-CL:
65
66
  continue_lesson: ¡Continúa esta lección!
66
67
  continue_practicing: ¡Sigue aprendiendo!
67
68
  correct_answer: ¡La respuesta es correcta!
69
+ course: Curso
68
70
  create_submission: Enviar
69
71
  created_at: Creado
70
72
  created_exercises: Ejercicios Creados
71
73
  created_guides: Lecciones Creadas
72
74
  date: Fecha
75
+ date_and_time: Fecha y hora
73
76
  deleted_by: Eliminado por %{deleter}
74
77
  deleted_message_warning: Si infringes reiteradamente estas u otras reglas del Espacio de Consultas, se te puede prohibir el acceso al mismo o podrás sufrir consecuencias más severas, como la expulsión del curso.
75
78
  deletion_motive:
@@ -280,6 +283,7 @@ es-CL:
280
283
  notifications_will_be_here: Tus notificaciones aparecerán aquí
281
284
  notify_problem_with_exercise: Reporta un bug
282
285
  office: Secretaría
286
+ only_forum_questions_on_forum: Recuerda que en el espacio de consultas se responden únicamente dudas relacionadas a los ejercicios. Para cualquier otro tipo de consulta, revisa la %{link}.
283
287
  only_landscape_support: Por favor, rota tu tablet o celular para realizar ejercicios
284
288
  opened: Abierta
285
289
  opened_count:
@@ -374,6 +378,7 @@ es-CL:
374
378
  terms_and_conditions_continue_disclaimer: Al continuar aceptas los %{terms_link}
375
379
  terms_and_conditions_must_be_accepted: Tienes que aceptar los términos y condiciones
376
380
  test_results: Resultados de las pruebas
381
+ time_in_minutes: "%{time} minutos"
377
382
  time_since: "hace %{time}"
378
383
  time_left: Te quedan
379
384
  title: Título
@@ -32,6 +32,7 @@ es:
32
32
  authoring: Autores
33
33
  authoring_note_html: Esta guía fue desarrollada por %{authors} bajo los términos de la <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">Licencia Creative Commons Compartir-Igual, 4.0</a>.
34
34
  authoring_note_with_collaborators_html: Esta guía fue desarrollada por %{authors} y <a href="%{collaborators}" target="_blank">muchas personas más</a>, bajo los términos de la <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank">Licencia Creative Commons Compartir-Igual, 4.0</a>.
35
+ available_time: Tiempo disponible
35
36
  back_to_mumuki: ¡Volvé a Mumuki!
36
37
  bibliotheca_ui: Biblioteca
37
38
  birthdate: Fecha de nacimiento
@@ -68,6 +69,7 @@ es:
68
69
  continue_lesson: ¡Continuá esta lección!
69
70
  continue_practicing: ¡Seguí aprendiendo!
70
71
  correct_answer: ¡La respuesta es correcta!
72
+ course: Curso
71
73
  create_submission: Enviar
72
74
  created_at: Creado
73
75
  created_at_asc: Antiguas
@@ -75,6 +77,7 @@ es:
75
77
  created_exercises: Ejercicios Creados
76
78
  created_guides: Lecciones Creadas
77
79
  date: Fecha
80
+ date_and_time: Fecha y hora
78
81
  deleted_by: Eliminado por %{deleter}
79
82
  deleted_message_warning: Si infringís reiteradamente estas u otras reglas del Espacio de Consultas, se te puede prohibir el acceso al mismo o podrás sufrir consecuencias más severas, como la expulsión del curso.
80
83
  deletion_motive:
@@ -289,6 +292,7 @@ es:
289
292
  notifications_will_be_here: Tus notificaciones aparecerán aquí
290
293
  notify_problem_with_exercise: Reportá un bug
291
294
  office: Secretaría
295
+ only_forum_questions_on_forum: Recordá que en el espacio de consultas se responden únicamente dudas relacionadas a los ejercicios. Para cualquier otro tipo de consulta, revisá la %{link}.
292
296
  only_landscape_support: Por favor, rotá tu tablet o celular para realizar ejercicios
293
297
  opened: Abierta
294
298
  opened_count:
@@ -388,6 +392,7 @@ es:
388
392
  terms_and_conditions_continue_disclaimer: Al continuar estás aceptando los %{terms_link}
389
393
  terms_and_conditions_must_be_accepted: Tenés que aceptar los términos y condiciones
390
394
  test_results: Resultados de las pruebas
395
+ time_in_minutes: "%{time} minutos"
391
396
  time_since: "hace %{time}"
392
397
  time_left: Te quedan
393
398
  title: Título
@@ -31,6 +31,7 @@ pt:
31
31
  authoring: Autores
32
32
  authoring_note_html: 'Este guia foi desenvolvido por %{authors} nos termos do <a href = "https://creativecommons.org/licenses/by-sa/4.0/" target="_blank"> Creative Commons License Share-Equal, 4.0 </a>.'
33
33
  authoring_note_with_collaborators_html: 'Este guia foi desenvolvido por %{authors} e <a href="%{collaborators}" target="_blank">muitas outras pessoas </a>, nos termos do <a href = "https://creativecommons.org/licenses/by-sa/4.0/" target="_blank"> Creative Commons License Share-Equal, 4.0 </a>.'
34
+ available_time: Tempo disponível
34
35
  back_to_mumuki: Voltei para Mumuki!
35
36
  bibliotheca_ui: Biblioteca
36
37
  birthdate: Fecha de nacimiento
@@ -64,6 +65,7 @@ pt:
64
65
  continue_lesson: Continue esta lição!
65
66
  continue_practicing: Continue aprendendo!
66
67
  correct_answer: A resposta está correta!
68
+ course: Curso
67
69
  create_submission: Enviar
68
70
  created_at: Criado
69
71
  created_at_asc: Antigo
@@ -71,6 +73,7 @@ pt:
71
73
  created_exercises: Exercícios criados
72
74
  created_guides: Lições criadas
73
75
  date: Data
76
+ date_and_time: Data e hora
74
77
  deleted_by: Removido pelo
75
78
  deleted_message_warning: Se você violar repetidamente essas ou outras regras da Área de Consulta, seu acesso a ela pode ser proibido ou você pode sofrer consequências mais graves, como a expulsão do curso.
76
79
  deletion_motive:
@@ -280,6 +283,7 @@ pt:
280
283
  notifications_will_be_here: Suas notificações aparecerão aqui
281
284
  notify_problem_with_exercise: Relatar um erro
282
285
  office: Secretariado
286
+ only_forum_questions_on_forum: Lembre-se que apenas as dúvidas relacionadas aos exercícios são respondidas no espaço de consulta. Para qualquer outro tipo de consulta, reveja a %{link}.
283
287
  only_landscape_support: Por favor, gire seu tablet ou celular para realizar exercícios
284
288
  opened: Aberto
285
289
  opened_count: '%{count} aberto'
@@ -373,6 +377,7 @@ pt:
373
377
  terms_and_conditions_continue_disclaimer: Ao continuar, você concorda %{terms_link}
374
378
  terms_and_conditions_must_be_accepted: Você deve aceitar os Termos e Condições
375
379
  test_results: Resultados do teste
380
+ time_in_minutes: "%{time} minutos"
376
381
  time_since: "há %{time}"
377
382
  time_left: Te deixam
378
383
  title: Título
@@ -1,5 +1,5 @@
1
1
  module Mumuki
2
2
  module Laboratory
3
- VERSION = '9.14.0'
3
+ VERSION = '9.17.0'
4
4
  end
5
5
  end
@@ -30,7 +30,7 @@ feature 'not found private on app', organization_workspace: :base do
30
30
  expect(page.text).to json_eq errors: [
31
31
  'The operation on organization base' +
32
32
  ' was forbidden to user foo+1@bar.com' +
33
- ' with permissions !student:central/*;teacher:;headmaster:;janitor:;admin:;owner:;ex_student:']
33
+ ' with permissions !student:central/*;teacher:;headmaster:;janitor:;admin:;owner:']
34
34
  end
35
35
 
36
36
  scenario 'api with authentication', :json_eq_error do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mumuki-laboratory
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.14.0
4
+ version: 9.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Franco Bulgarelli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-02 00:00:00.000000000 Z
11
+ date: 2021-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 9.14.0
33
+ version: 9.17.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 9.14.0
40
+ version: 9.17.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mumukit-bridge
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -548,6 +548,7 @@ files:
548
548
  - app/helpers/editor_tabs_helper.rb
549
549
  - app/helpers/email_helper.rb
550
550
  - app/helpers/exam_registration_helper.rb
551
+ - app/helpers/exams_helper.rb
551
552
  - app/helpers/exercise_input_helper.rb
552
553
  - app/helpers/gamification_helper.rb
553
554
  - app/helpers/globals_helper.rb
@@ -567,6 +568,7 @@ files:
567
568
  - app/helpers/progress_bar_helper.rb
568
569
  - app/helpers/progress_helper.rb
569
570
  - app/helpers/runner_assets_helper.rb
571
+ - app/helpers/time_helper.rb
570
572
  - app/helpers/time_zone_helper.rb
571
573
  - app/helpers/toast_helper.rb
572
574
  - app/helpers/user_activity_helper.rb
@@ -583,6 +585,8 @@ files:
583
585
  - app/views/certificates/verify.html.erb
584
586
  - app/views/chapters/show.html.erb
585
587
  - app/views/complements/show.html.erb
588
+ - app/views/discussions/_actions.html.erb
589
+ - app/views/discussions/_basic_actions.html.erb
586
590
  - app/views/discussions/_description_message.html.erb
587
591
  - app/views/discussions/_message.html.erb
588
592
  - app/views/discussions/_message_container.html.erb
@@ -980,135 +984,135 @@ signing_key:
980
984
  specification_version: 4
981
985
  summary: Code assement web application for the Mumuki Platform.
982
986
  test_files:
983
- - spec/evaluation_helper.rb
984
- - spec/api_helper.rb
985
- - spec/features/exams_flow_spec.rb
986
- - spec/features/standard_flow_spec.rb
987
- - spec/features/guides_flow_spec.rb
988
- - spec/features/dynamic_exam_spec.rb
989
- - spec/features/disabled_organization_flow_spec.rb
990
- - spec/features/user_activity_flow_spec.rb
987
+ - spec/features/disable_user_flow_spec.rb
988
+ - spec/features/exercise_flow_spec.rb
989
+ - spec/features/certificate_programs_flow_spec.rb
990
+ - spec/features/progressive_tips_spec.rb
991
+ - spec/features/runner_assets_spec.rb
992
+ - spec/features/guide_reset_spec.rb
991
993
  - spec/features/home_public_flow_spec.rb
994
+ - spec/features/links_flow_spec.rb
995
+ - spec/features/not_found_private_flow_spec.rb
996
+ - spec/features/dynamic_exam_spec.rb
997
+ - spec/features/chapters_flow_spec.rb
992
998
  - spec/features/read_only_flow_spec.rb
999
+ - spec/features/discussion_flow_spec.rb
1000
+ - spec/features/complements_flow_spec.rb
1001
+ - spec/features/standard_flow_spec.rb
1002
+ - spec/features/user_activity_flow_spec.rb
1003
+ - spec/features/invitations_flow_spec.rb
993
1004
  - spec/features/home_private_flow_spec.rb
994
- - spec/features/immersive_redirection_spec.rb
995
- - spec/features/progressive_tips_spec.rb
1005
+ - spec/features/exams_flow_spec.rb
1006
+ - spec/features/topic_flow_spec.rb
996
1007
  - spec/features/login_flow_spec.rb
997
- - spec/features/exercise_flow_spec.rb
998
- - spec/features/disable_user_flow_spec.rb
999
- - spec/features/menu_bar_spec.rb
1000
- - spec/features/not_found_private_flow_spec.rb
1001
- - spec/features/guide_reset_spec.rb
1002
- - spec/features/notifications_flow_spec.rb
1008
+ - spec/features/not_found_public_flow_spec.rb
1009
+ - spec/features/immersive_redirection_spec.rb
1010
+ - spec/features/disabled_organization_flow_spec.rb
1003
1011
  - spec/features/lessons_flow_spec.rb
1004
- - spec/features/chapters_flow_spec.rb
1012
+ - spec/features/guides_flow_spec.rb
1013
+ - spec/features/notifications_flow_spec.rb
1014
+ - spec/features/menu_bar_spec.rb
1005
1015
  - spec/features/profile_flow_spec.rb
1006
- - spec/features/complements_flow_spec.rb
1007
- - spec/features/not_found_public_flow_spec.rb
1008
- - spec/features/certificate_programs_flow_spec.rb
1009
- - spec/features/topic_flow_spec.rb
1010
- - spec/features/links_flow_spec.rb
1011
- - spec/features/runner_assets_spec.rb
1012
- - spec/features/invitations_flow_spec.rb
1013
- - spec/features/discussion_flow_spec.rb
1014
1016
  - spec/features/terms_flow_spec.rb
1015
- - spec/capybara_helper.rb
1017
+ - spec/javascripts/results-renderers-spec.js
1018
+ - spec/javascripts/i18n-spec.js
1016
1019
  - spec/javascripts/gamification-spec.js
1017
- - spec/javascripts/upload-spec.js
1020
+ - spec/javascripts/global-spec.js
1021
+ - spec/javascripts/elipsis-spec.js
1022
+ - spec/javascripts/kids-button-spec.js
1023
+ - spec/javascripts/sync-mode-spec.js
1024
+ - spec/javascripts/spec-helper.js
1018
1025
  - spec/javascripts/timer-spec.js
1026
+ - spec/javascripts/csrf-token-spec.js
1027
+ - spec/javascripts/submissions-store-spec.js
1019
1028
  - spec/javascripts/timeout-spec.js
1020
- - spec/javascripts/elipsis-spec.js
1021
1029
  - spec/javascripts/editors-spec.js
1022
1030
  - spec/javascripts/speech-bubble-renderer-spec.js
1023
- - spec/javascripts/results-renderers-spec.js
1024
- - spec/javascripts/sync-mode-spec.js
1025
- - spec/javascripts/i18n-spec.js
1026
- - spec/javascripts/submissions-store-spec.js
1027
- - spec/javascripts/kids-button-spec.js
1031
+ - spec/javascripts/upload-spec.js
1028
1032
  - spec/javascripts/exercise-spec.js
1029
- - spec/javascripts/global-spec.js
1030
- - spec/javascripts/bridge-spec.js
1031
1033
  - spec/javascripts/events-spec.js
1032
- - spec/javascripts/spec-helper.js
1033
- - spec/javascripts/csrf-token-spec.js
1034
- - spec/login_helper.rb
1034
+ - spec/javascripts/bridge-spec.js
1035
1035
  - spec/spec_helper.rb
1036
- - spec/controllers/exam_authorization_requests_controller_spec.rb
1037
- - spec/controllers/api_clients_controller.rb
1038
- - spec/controllers/exercise_solutions_controller_spec.rb
1039
- - spec/controllers/discussions_controller_spec.rb
1040
- - spec/controllers/exam_registrations_controller_spec.rb
1041
- - spec/controllers/organizations_api_controller_spec.rb
1042
- - spec/controllers/certificates_controller_spec.rb
1043
- - spec/controllers/discussions_messages_controller_spec.rb
1044
- - spec/controllers/users_controller_spec.rb
1045
- - spec/controllers/invitations_controller_spec.rb
1046
- - spec/controllers/guide_progress_controller_spec.rb
1047
- - spec/controllers/users_api_controller_spec.rb
1048
- - spec/controllers/students_api_controller_spec.rb
1049
- - spec/controllers/confirmations_controller_spec.rb
1050
- - spec/controllers/messages_controller_spec.rb
1051
- - spec/controllers/chapters_controller_spec.rb
1052
- - spec/controllers/courses_api_controller_spec.rb
1053
- - spec/mailers/user_mailer_spec.rb
1054
- - spec/mailers/previews/user_mailer_preview.rb
1055
1036
  - spec/teaspoon_env.rb
1056
- - spec/dummy/bin/update
1057
- - spec/dummy/bin/yarn
1058
- - spec/dummy/bin/rake
1059
- - spec/dummy/bin/bundle
1060
- - spec/dummy/bin/setup
1061
- - spec/dummy/bin/rails
1062
- - spec/dummy/config/cable.yml
1063
- - spec/dummy/config/boot.rb
1064
- - spec/dummy/config/secrets.yml
1037
+ - spec/evaluation_helper.rb
1038
+ - spec/dummy/public/medal/outline.svg
1039
+ - spec/dummy/public/error/404.svg
1040
+ - spec/dummy/public/error/500.svg
1041
+ - spec/dummy/public/error/timeout_3.svg
1042
+ - spec/dummy/public/error/timeout_1.svg
1043
+ - spec/dummy/public/error/timeout_2.svg
1044
+ - spec/dummy/public/error/401.svg
1045
+ - spec/dummy/public/error/403.svg
1046
+ - spec/dummy/public/error/410.svg
1047
+ - spec/dummy/public/character/animations.json
1048
+ - spec/dummy/public/character/magnifying_glass/apparition.svg
1049
+ - spec/dummy/public/character/magnifying_glass/loop.svg
1050
+ - spec/dummy/public/character/kibi/failure.svg
1051
+ - spec/dummy/public/character/kibi/context.svg
1052
+ - spec/dummy/public/character/kibi/passed_with_warnings.svg
1053
+ - spec/dummy/public/character/kibi/jump.svg
1054
+ - spec/dummy/public/character/kibi/success_l.svg
1055
+ - spec/dummy/public/character/kibi/success2_l.svg
1056
+ - spec/dummy/Rakefile
1057
+ - spec/dummy/config/application.rb
1058
+ - spec/dummy/config/puma.rb
1059
+ - spec/dummy/config/spring.rb
1065
1060
  - spec/dummy/config/routes.rb
1066
1061
  - spec/dummy/config/environments/test.rb
1067
1062
  - spec/dummy/config/environments/development.rb
1068
- - spec/dummy/config/locales/en.yml
1069
- - spec/dummy/config/initializers/cookies_serializer.rb
1070
- - spec/dummy/config/initializers/wrap_parameters.rb
1063
+ - spec/dummy/config/database.yml
1071
1064
  - spec/dummy/config/initializers/assets.rb
1065
+ - spec/dummy/config/initializers/wrap_parameters.rb
1072
1066
  - spec/dummy/config/initializers/filter_parameter_logging.rb
1073
- - spec/dummy/config/application.rb
1074
- - spec/dummy/config/spring.rb
1075
- - spec/dummy/config/database.yml
1076
- - spec/dummy/config/environment.rb
1067
+ - spec/dummy/config/initializers/cookies_serializer.rb
1077
1068
  - spec/dummy/config/rabbit.yml
1078
- - spec/dummy/config/puma.rb
1079
- - spec/dummy/Rakefile
1080
- - spec/dummy/db/schema.rb
1081
- - spec/dummy/db/seeds.rb
1082
- - spec/dummy/public/character/kibi/success_l.svg
1083
- - spec/dummy/public/character/kibi/failure.svg
1084
- - spec/dummy/public/character/kibi/context.svg
1085
- - spec/dummy/public/character/kibi/jump.svg
1086
- - spec/dummy/public/character/kibi/success2_l.svg
1087
- - spec/dummy/public/character/kibi/passed_with_warnings.svg
1088
- - spec/dummy/public/character/animations.json
1089
- - spec/dummy/public/character/magnifying_glass/loop.svg
1090
- - spec/dummy/public/character/magnifying_glass/apparition.svg
1091
- - spec/dummy/public/medal/outline.svg
1092
- - spec/dummy/public/error/timeout_2.svg
1093
- - spec/dummy/public/error/410.svg
1094
- - spec/dummy/public/error/timeout_3.svg
1095
- - spec/dummy/public/error/500.svg
1096
- - spec/dummy/public/error/403.svg
1097
- - spec/dummy/public/error/timeout_1.svg
1098
- - spec/dummy/public/error/404.svg
1099
- - spec/dummy/public/error/401.svg
1100
- - spec/dummy/config.ru
1069
+ - spec/dummy/config/locales/en.yml
1070
+ - spec/dummy/config/cable.yml
1071
+ - spec/dummy/config/environment.rb
1072
+ - spec/dummy/config/secrets.yml
1073
+ - spec/dummy/config/boot.rb
1101
1074
  - spec/dummy/package.json
1102
- - spec/helpers/with_choices_spec.rb
1103
- - spec/helpers/email_helper_spec.rb
1075
+ - spec/dummy/config.ru
1076
+ - spec/dummy/db/seeds.rb
1077
+ - spec/dummy/db/schema.rb
1078
+ - spec/dummy/bin/yarn
1079
+ - spec/dummy/bin/rails
1080
+ - spec/dummy/bin/rake
1081
+ - spec/dummy/bin/bundle
1082
+ - spec/dummy/bin/setup
1083
+ - spec/dummy/bin/update
1084
+ - spec/controllers/certificates_controller_spec.rb
1085
+ - spec/controllers/students_api_controller_spec.rb
1086
+ - spec/controllers/api_clients_controller.rb
1087
+ - spec/controllers/organizations_api_controller_spec.rb
1088
+ - spec/controllers/exam_authorization_requests_controller_spec.rb
1089
+ - spec/controllers/confirmations_controller_spec.rb
1090
+ - spec/controllers/exam_registrations_controller_spec.rb
1091
+ - spec/controllers/users_controller_spec.rb
1092
+ - spec/controllers/exercise_solutions_controller_spec.rb
1093
+ - spec/controllers/discussions_controller_spec.rb
1094
+ - spec/controllers/courses_api_controller_spec.rb
1095
+ - spec/controllers/discussions_messages_controller_spec.rb
1096
+ - spec/controllers/users_api_controller_spec.rb
1097
+ - spec/controllers/messages_controller_spec.rb
1098
+ - spec/controllers/invitations_controller_spec.rb
1099
+ - spec/controllers/guide_progress_controller_spec.rb
1100
+ - spec/controllers/chapters_controller_spec.rb
1101
+ - spec/login_helper.rb
1102
+ - spec/mailers/previews/user_mailer_preview.rb
1103
+ - spec/mailers/user_mailer_spec.rb
1104
+ - spec/capybara_helper.rb
1105
+ - spec/helpers/icons_helper_spec.rb
1106
+ - spec/helpers/certificate_helper_spec.rb
1104
1107
  - spec/helpers/test_results_rendering_spec.rb
1105
- - spec/helpers/authors_helper_spec.rb
1108
+ - spec/helpers/avatar_helper_spec.rb
1109
+ - spec/helpers/exercise_input_helper_spec.rb
1106
1110
  - spec/helpers/with_navigation_spec.rb
1107
- - spec/helpers/certificate_helper_spec.rb
1108
- - spec/helpers/page_title_helper_spec.rb
1111
+ - spec/helpers/email_helper_spec.rb
1109
1112
  - spec/helpers/user_activity_helper_spec.rb
1110
- - spec/helpers/application_helper_spec.rb
1113
+ - spec/helpers/with_choices_spec.rb
1111
1114
  - spec/helpers/breadcrumbs_helper_spec.rb
1112
- - spec/helpers/icons_helper_spec.rb
1113
- - spec/helpers/exercise_input_helper_spec.rb
1114
- - spec/helpers/avatar_helper_spec.rb
1115
+ - spec/helpers/page_title_helper_spec.rb
1116
+ - spec/helpers/application_helper_spec.rb
1117
+ - spec/helpers/authors_helper_spec.rb
1118
+ - spec/api_helper.rb