mumuki-laboratory 8.1.1 → 8.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/mumuki_laboratory/application/bridge.js +1 -1
  3. data/app/assets/javascripts/mumuki_laboratory/application/button.js +2 -2
  4. data/app/assets/javascripts/mumuki_laboratory/application/codemirror-builder.js +2 -2
  5. data/app/assets/javascripts/mumuki_laboratory/application/codemirror.js +5 -5
  6. data/app/assets/javascripts/mumuki_laboratory/application/console.js +2 -2
  7. data/app/assets/javascripts/mumuki_laboratory/application/discussions.js +7 -7
  8. data/app/assets/javascripts/mumuki_laboratory/application/editors.js +1 -1
  9. data/app/assets/javascripts/mumuki_laboratory/application/elipsis.js +1 -1
  10. data/app/assets/javascripts/mumuki_laboratory/application/events.js +2 -2
  11. data/app/assets/javascripts/mumuki_laboratory/application/exercise.js +2 -2
  12. data/app/assets/javascripts/mumuki_laboratory/application/gamification.js +13 -3
  13. data/app/assets/javascripts/mumuki_laboratory/application/inputs.js +1 -1
  14. data/app/assets/javascripts/mumuki_laboratory/application/kids.js +4 -4
  15. data/app/assets/javascripts/mumuki_laboratory/application/kindergarten.js +7 -7
  16. data/app/assets/javascripts/mumuki_laboratory/application/messages.js +6 -6
  17. data/app/assets/javascripts/mumuki_laboratory/application/mu-modal-carrousel.js +1 -1
  18. data/app/assets/javascripts/mumuki_laboratory/application/multiple-choice.js +1 -1
  19. data/app/assets/javascripts/mumuki_laboratory/application/multiple-files.js +3 -3
  20. data/app/assets/javascripts/mumuki_laboratory/application/multiple-scenarios.js +1 -1
  21. data/app/assets/javascripts/mumuki_laboratory/application/pin.js +1 -1
  22. data/app/assets/javascripts/mumuki_laboratory/application/primary.js +1 -1
  23. data/app/assets/javascripts/mumuki_laboratory/application/progress.js +1 -1
  24. data/app/assets/javascripts/mumuki_laboratory/application/results-renderer.js +1 -1
  25. data/app/assets/javascripts/mumuki_laboratory/application/speech-bubble-renderer.js +4 -4
  26. data/app/assets/javascripts/mumuki_laboratory/application/submission.js +2 -2
  27. data/app/assets/javascripts/mumuki_laboratory/application/submissions-store.js +3 -3
  28. data/app/assets/javascripts/mumuki_laboratory/application/sync-mode.js +2 -2
  29. data/app/assets/javascripts/mumuki_laboratory/application/timer.js +1 -1
  30. data/app/assets/stylesheets/mumuki_laboratory/application/_layout.scss +7 -7
  31. data/app/controllers/concerns/with_user_discussion_validation.rb +6 -0
  32. data/app/controllers/discussions_controller.rb +0 -6
  33. data/app/helpers/links_helper.rb +2 -2
  34. data/app/views/layouts/_copyright.html.erb +1 -1
  35. data/app/views/layouts/application.html.erb +16 -14
  36. data/app/views/layouts/embedded.html.erb +14 -11
  37. data/lib/mumuki/laboratory/locales/es-CL.yml +1 -1
  38. data/lib/mumuki/laboratory/locales/es.yml +2 -2
  39. data/lib/mumuki/laboratory/locales/pt.yml +1 -1
  40. data/lib/mumuki/laboratory/version.rb +1 -1
  41. data/spec/controllers/discussions_controller_spec.rb +19 -0
  42. data/spec/dummy/db/schema.rb +2 -1
  43. metadata +102 -102
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5feda4ed95a66abdfc68c218f1d2b5752fe6fdd8d8da0a18cc7c968d90550bbd
4
- data.tar.gz: '080a983c6f384a8568ba2c8e7f092fcab9afe2a82b728bdfcc1e66fb8256377f'
3
+ metadata.gz: d366cf0d6d349759281213746e2c6a6f1a998db2d07efa9dc45b02480487108e
4
+ data.tar.gz: 0c890e15fa8b8f3164372b7c8f6844b17e85ded1686bb1c4d0947d9a08b7cd6a
5
5
  SHA512:
6
- metadata.gz: f95a1a2057a7946e2f26589a50076ec7e3c0e3d538a3feeb75da6a7cd1e030598a048dbb2e8918f1dcf39aa6565bc22fec237c66c88ee6842503c4d0bf94947c
7
- data.tar.gz: 006504d33b8cb9ea871cff01be16fbc9f4b9f89e8cab63f11e1bfcc41cb4384cf1aff2e6e501e053d9279a1dd3a2009ae0b6a5c242012ab311b0a1e1ed9702a5
6
+ metadata.gz: 4ff7d88d695024cbd9feac650c31b77055291f280791b262ddf6c6477f54a2e7ef0d858bbe4668594e88b755dd5ab1934ac7b8acc045acf02360ddae9dca8d7f
7
+ data.tar.gz: 555cfdee07fa9e97d62507360fda991dfd6bf16668093d6af44ab6f6ee79dcf22ab57aaf08d49a2e434767bd3a7dadfb8316321b22d3efa0e0b0f19f5ad7c1e0
@@ -113,7 +113,7 @@ mumuki.bridge = (() => {
113
113
  * @returns {SubmissionResult}
114
114
  */
115
115
  _preRenderResult(result) {
116
- result.class_for_progress_list_item = mumuki.renderers.progressListItemClassForStatus(result.status, true)
116
+ result.class_for_progress_list_item = mumuki.renderers.progressListItemClassForStatus(result.status, true);
117
117
  return result;
118
118
  }
119
119
  }
@@ -36,7 +36,7 @@ mumuki.Button = class {
36
36
  e.preventDefault();
37
37
  main();
38
38
  };
39
- this.$button.on('click', this.main)
39
+ this.$button.on('click', this.main);
40
40
  }
41
41
 
42
42
  // ==============
@@ -80,7 +80,7 @@ mumuki.Button = class {
80
80
 
81
81
  this.enable();
82
82
 
83
- this.$button.on('click', this.main)
83
+ this.$button.on('click', this.main);
84
84
  }
85
85
 
86
86
  // =============
@@ -38,7 +38,7 @@
38
38
  mumuki.editor.toggleFullscreen();
39
39
  },
40
40
  'Tab': function (cm) {
41
- mumuki.editor.indentWithSpaces(cm)
41
+ mumuki.editor.indentWithSpaces(cm);
42
42
  }
43
43
  }
44
44
  });
@@ -53,7 +53,7 @@
53
53
  'Cmd-Enter': submitMessage,
54
54
  'Ctrl-Enter': submitMessage,
55
55
  'Tab': function (cm) {
56
- mumuki.editor.indentWithSpaces(cm)
56
+ mumuki.editor.indentWithSpaces(cm);
57
57
  }
58
58
  }
59
59
  });
@@ -23,14 +23,14 @@ mumuki.page.editors = [];
23
23
  function resetEditor() {
24
24
  mumuki.page.dynamicEditors.forEach(function (e) {
25
25
  setDefaultContent(e, $('#default_content').val());
26
- })
26
+ });
27
27
  }
28
28
 
29
29
  function formatContent() {
30
30
  mumuki.page.editors.each(function (_, editor) {
31
- editor.setSelection({line: 0, ch: 0}, {line: editor.lineCount()})
32
- editor.indentSelection("smart")
33
- editor.setSelection({line: 0})
31
+ editor.setSelection({line: 0, ch: 0}, {line: editor.lineCount()});
32
+ editor.indentSelection("smart");
33
+ editor.setSelection({line: 0});
34
34
  });
35
35
  }
36
36
 
@@ -56,7 +56,7 @@ mumuki.page.editors = [];
56
56
  if (language !== undefined) {
57
57
  mumuki.page.dynamicEditors.forEach(function (e) {
58
58
  setEditorLanguage(e, language);
59
- })
59
+ });
60
60
  }
61
61
  }
62
62
 
@@ -32,7 +32,7 @@
32
32
  function clearConsole() {
33
33
  $('.jquery-console-message-error').remove();
34
34
  $('.jquery-console-message-value').remove();
35
- $('.jquery-console-prompt-box:not(:last)').remove()
35
+ $('.jquery-console-prompt-box:not(:last)').remove();
36
36
  }
37
37
 
38
38
  class QueryConsole {
@@ -134,7 +134,7 @@
134
134
  url: self._requestUrl,
135
135
  type: 'POST',
136
136
  data: self._requestData
137
- })
137
+ });
138
138
  }
139
139
  get _requestUrl() {
140
140
  return this.console.endpoint;
@@ -34,33 +34,33 @@ mumuki.load(() => {
34
34
  },
35
35
  token: new mumuki.CsrfToken(),
36
36
  tokenRequest: function (data) {
37
- return $.ajax(Forum.token.newRequest(data))
37
+ return $.ajax(Forum.token.newRequest(data));
38
38
  },
39
39
  discussionPost: function (url) {
40
40
  return Forum.tokenRequest({
41
41
  url: url,
42
42
  method: 'POST',
43
43
  xhrFields: {withCredentials: true}
44
- })
44
+ });
45
45
  },
46
46
  discussionSubscription: function (url) {
47
- Forum.discussionPostAndToggle(url, $subscriptionSpans)
47
+ Forum.discussionPostAndToggle(url, $subscriptionSpans);
48
48
  },
49
49
  discussionUpvote: function (url) {
50
- Forum.discussionPostAndToggle(url, $upvoteSpans)
50
+ Forum.discussionPostAndToggle(url, $upvoteSpans);
51
51
  },
52
52
  discussionPostAndToggle: function (url, elem) {
53
- Forum.discussionPost(url).done(Forum.toggleButton(elem))
53
+ Forum.discussionPost(url).done(Forum.toggleButton(elem));
54
54
  },
55
55
  discussionMessageToggleApprove: function (url, elem) {
56
56
  Forum.discussionPost(url).done(function () {
57
57
  elem.toggleClass("selected");
58
- })
58
+ });
59
59
  },
60
60
  discussionMessageToggleNotActuallyAQuestion: function (url, elem) {
61
61
  Forum.discussionPost(url).done(function () {
62
62
  elem.toggleClass("selected");
63
- })
63
+ });
64
64
  },
65
65
  discussionsToggleCheckbox: function (elem) {
66
66
  const key = elem.attr('name');
@@ -99,6 +99,6 @@ mumuki.editors = {
99
99
  * @param {CustomEditorSource} source
100
100
  */
101
101
  addCustomSource(source) {
102
- mumuki.CustomEditor.addSource(source)
102
+ mumuki.CustomEditor.addSource(source);
103
103
  }
104
104
  };
@@ -21,7 +21,7 @@ mumuki.elipsis = (() => {
21
21
  $elipsis.each((it, e) => {
22
22
  let $e = $(e);
23
23
  $e.html(mumuki.elipsis($e.html()));
24
- })
24
+ });
25
25
  };
26
26
 
27
27
  mumuki.load(() => {
@@ -34,7 +34,7 @@ mumuki.events = {
34
34
  */
35
35
  fire(eventName, value = null) {
36
36
  if (this._handlers[eventName]) {
37
- this._handlers[eventName].forEach(it => it(value))
37
+ this._handlers[eventName].forEach(it => it(value));
38
38
  }
39
39
  },
40
40
 
@@ -48,4 +48,4 @@ mumuki.events = {
48
48
  this._handlers[eventName] = [];
49
49
  }
50
50
  }
51
- }
51
+ };
@@ -63,6 +63,6 @@ mumuki.exercise = {
63
63
  this._current = null;
64
64
  }
65
65
  }
66
- }
66
+ };
67
67
 
68
- mumuki.load(() => mumuki.exercise.load())
68
+ mumuki.load(() => mumuki.exercise.load());
@@ -108,12 +108,22 @@ mumuki.gamification = (() => {
108
108
  }
109
109
 
110
110
  updateLevel() {
111
- const $muLevelProgress = $('#mu-level-progress');
112
-
113
111
  $('#mu-solve-more-exercises span').text(this.exercisesToNextLevel());
114
112
  $('.mu-level-number').html(this.currentLevel());
115
- $('.mu-level-tooltip').attr("title", (_, value) => `${value} ${this.currentLevel()}`);
116
113
 
114
+ this.updateTooltip();
115
+ this.animateProgressIfAny();
116
+ }
117
+
118
+ updateTooltip() {
119
+ const $muLevelTooltip = $('.mu-level-tooltip');
120
+
121
+ $muLevelTooltip.attr("data-original-title", `${$muLevelTooltip.attr("level")} ${this.currentLevel()}`);
122
+ $muLevelTooltip.attr("title", "");
123
+ }
124
+
125
+ animateProgressIfAny() {
126
+ const $muLevelProgress = $('#mu-level-progress');
117
127
  if (this.currentLevelProgress() === 0) {
118
128
  $muLevelProgress.attr("display", "none");
119
129
  }
@@ -7,7 +7,7 @@ mumuki.onInputsReady = (() => {
7
7
  if ($(inputsSelector).length === 0) return;
8
8
 
9
9
  callback(event);
10
- })
10
+ });
11
11
  }
12
12
 
13
13
  return onInputsReady;
@@ -61,11 +61,11 @@ mumuki.Kids = class {
61
61
  // ==================
62
62
 
63
63
  _showSuccessPopup() {
64
- this._mustImplementThisMethod()
64
+ this._mustImplementThisMethod();
65
65
  }
66
66
 
67
67
  _showFailurePopup() {
68
- this._mustImplementThisMethod()
68
+ this._mustImplementThisMethod();
69
69
  }
70
70
 
71
71
  // ====================
@@ -141,7 +141,7 @@ mumuki.Kids = class {
141
141
  // ============
142
142
 
143
143
  _mustImplementThisMethod() {
144
- throw new Error('TODO: implement method')
144
+ throw new Error('TODO: implement method');
145
145
  }
146
146
 
147
147
  // ============
@@ -214,4 +214,4 @@ mumuki.Kids = class {
214
214
  $blockSvg.height($blocks.height());
215
215
  }
216
216
 
217
- }
217
+ };
@@ -103,27 +103,27 @@ mumuki.load(() => {
103
103
  this._action('play', 'stop', true, (speech) => {
104
104
  mumuki.presenterCharacter.playAnimation('talk', mumuki.kids.$bubbleCharacterAnimation);
105
105
  speech.speak(msg);
106
- })
106
+ });
107
107
  },
108
108
  stop() {
109
- this._action('stop', 'play', false, (speech) => speech.cancel())
109
+ this._action('stop', 'play', false, (speech) => speech.cancel());
110
110
  },
111
111
  _action(add, remove, isPlaying, callback) {
112
112
  callback(window.speechSynthesis);
113
- const $button = $('.mu-kindergarten-play-description')
113
+ const $button = $('.mu-kindergarten-play-description');
114
114
  $button.find(`.mu-kindergarten-${add}`).addClass('hidden');
115
115
  $button.find(`.mu-kindergarten-${remove}`).removeClass('hidden');
116
116
  this._isPlaying = isPlaying;
117
117
  },
118
118
  verifyBrowserSupport() {
119
119
  if (!window.speechSynthesis) {
120
- const $button = $('.mu-kindergarten-play-description')
120
+ const $button = $('.mu-kindergarten-play-description');
121
121
  $button.prop('disabled', true);
122
122
  $button.css('cursor', 'not-allowed');
123
- this._action('play', 'stop', false)
123
+ this._action('play', 'stop', false);
124
124
  }
125
125
  }
126
- }
126
+ };
127
127
 
128
128
  }
129
129
 
@@ -143,7 +143,7 @@ mumuki.load(() => {
143
143
  const $hintMedia = $('.mu-kindergarten-hint-media');
144
144
  if (!$hintMedia.get(0)) $button.addClass('hidden');
145
145
  },
146
- }
146
+ };
147
147
  }
148
148
 
149
149
  get context() {
@@ -1,7 +1,7 @@
1
1
  mumuki.load(() => {
2
2
  var Chat = {
3
3
  $body: function () {
4
- return $('body')
4
+ return $('body');
5
5
  },
6
6
  $newMessageModal: function () {
7
7
  return $('.new-message-modal');
@@ -18,7 +18,7 @@ mumuki.load(() => {
18
18
  $('.notifications-box').toggleClass('notifications-box-empty', !data.has_messages);
19
19
  $('.pending-messages-filter').removeClass('pending-messages-filter');
20
20
  $('button.btn-submit').removeClass('disabled');
21
- $('.pending-messages-text').remove()
21
+ $('.pending-messages-text').remove();
22
22
  },
23
23
  readMessages: function (url) {
24
24
  Chat.tokenRequest({
@@ -26,10 +26,10 @@ mumuki.load(() => {
26
26
  method: 'POST',
27
27
  success: Chat.setMessages,
28
28
  xhrFields: {withCredentials: true}
29
- })
29
+ });
30
30
  },
31
31
  tokenRequest: function (data) {
32
- $.ajax(Chat.token.newRequest(data))
32
+ $.ajax(Chat.token.newRequest(data));
33
33
  },
34
34
  getMessages: function () {
35
35
  if ($('.badge-messages').length == 0) {
@@ -74,7 +74,7 @@ mumuki.load(() => {
74
74
  success: success,
75
75
  error: error,
76
76
  xhrFields: {withCredentials: true}
77
- })
77
+ });
78
78
  },
79
79
  openNewMessageModal: function () {
80
80
  Chat.$newMessageModal().modal({backdrop: false, keyboard: false});
@@ -89,5 +89,5 @@ mumuki.load(() => {
89
89
  Chat.setMessagesInterval();
90
90
  mumuki.Chat = Chat;
91
91
 
92
- })
92
+ });
93
93
 
@@ -41,7 +41,7 @@ mumuki.ModalCarrousel = (() => {
41
41
 
42
42
  _hidePreviousButtonIfFirstSlide() {
43
43
  const $prev = $('.mu-kids-modal-button.mu-previous');
44
- this._addClassIf($prev, 'hidden', () => this._activeSlide().is(':first-child'))
44
+ this._addClassIf($prev, 'hidden', () => this._activeSlide().is(':first-child'));
45
45
  }
46
46
 
47
47
  _showFirstSlide() {
@@ -1,7 +1,7 @@
1
1
  mumuki.load(() => {
2
2
  function dumpChoices(_evt) {
3
3
  var indexes = $('.solution-choice:checked').map(function () {
4
- return $(this).data('index')
4
+ return $(this).data('index');
5
5
  }).get().join(':');
6
6
  $('#solution_content').attr('value', indexes);
7
7
  }
@@ -103,11 +103,11 @@ mumuki.load(() => {
103
103
  }
104
104
 
105
105
  get highlightModes() {
106
- return this._getDataFromHiddenInput('#highlight-modes')
106
+ return this._getDataFromHiddenInput('#highlight-modes');
107
107
  }
108
108
 
109
109
  get locales() {
110
- return this._getDataFromHiddenInput('#multifile-locales')
110
+ return this._getDataFromHiddenInput('#multifile-locales');
111
111
  }
112
112
 
113
113
  setUpAddFile() {
@@ -131,7 +131,7 @@ mumuki.load(() => {
131
131
 
132
132
  this._setVisibility(this._addFileButton, filesCount < this.MAX_TABS);
133
133
  this.files.toArray().forEach(file => {
134
- this._setVisibility(file.deleteButton, file.name !== this.mainFile && filesCount > 1)
134
+ this._setVisibility(file.deleteButton, file.name !== this.mainFile && filesCount > 1);
135
135
  });
136
136
  }
137
137
 
@@ -73,7 +73,7 @@ mumuki.MultipleScenarios = (() => {
73
73
  if (this.validScenarioIndex(newScenarioIndex)) {
74
74
  this.setActiveIndex(newScenarioIndex);
75
75
  }
76
- })
76
+ });
77
77
  }
78
78
 
79
79
  createControls () {
@@ -11,5 +11,5 @@ mumuki.pin = (() => {
11
11
  smoothScrollToElement(scrollPin);
12
12
  }
13
13
  }
14
- }
14
+ };
15
15
  })();
@@ -83,7 +83,7 @@ mumuki.load(() => {
83
83
  this._$texts.hide();
84
84
  this.$characterSpeechBubbleNormal.children('.' + $tab.data('target')).show();
85
85
  this._updateSpeechParagraphs();
86
- })
86
+ });
87
87
  }
88
88
  });
89
89
 
@@ -17,7 +17,7 @@ mumuki.progress = (() => {
17
17
  function updateWholeProgressBar(f) {
18
18
  $('.progress-list-item').each((_, it) => {
19
19
  const $anchor = $(it);
20
- $anchor.attr('class', f($anchor))
20
+ $anchor.attr('class', f($anchor));
21
21
  });
22
22
  }
23
23
 
@@ -49,7 +49,7 @@ mumuki.renderers.results = (() => {
49
49
  classForStatus,
50
50
  iconForStatus,
51
51
  progressListItemClassForStatus
52
- }
52
+ };
53
53
  })();
54
54
 
55
55
  /** @deprecated use {@code mumuki.renderers.results.classForStatus} instead */
@@ -20,7 +20,7 @@ mumuki.renderers.speechBubble = (()=> {
20
20
 
21
21
  _chooseResultItem() {
22
22
  if (this._responseStatus() !== 'passed' && this._hasTips()) {
23
- this._appendFirstTip()
23
+ this._appendFirstTip();
24
24
  } else if (this._responseStatus() === 'failed') {
25
25
  this._appendFirstFailedTestResultSummary();
26
26
  } else if (this._responseStatus() === 'passed_with_warnings') {
@@ -29,7 +29,7 @@ mumuki.renderers.speechBubble = (()=> {
29
29
  }
30
30
 
31
31
  _appendFirstFailedTestResultSummary() {
32
- const failedTestResult = this._failedTestResults()[0]
32
+ const failedTestResult = this._failedTestResults()[0];
33
33
  if (failedTestResult && failedTestResult.summary) {
34
34
  this._appendResultItem(mumuki.renderers.renderSpeechBubbleResultItem(failedTestResult.summary));
35
35
  }
@@ -67,7 +67,7 @@ mumuki.renderers.speechBubble = (()=> {
67
67
  }
68
68
 
69
69
  _hasTips() {
70
- return this.responseData.tips && this.responseData.tips.length
70
+ return this.responseData.tips && this.responseData.tips.length;
71
71
  }
72
72
 
73
73
  _failedTestResults() {
@@ -97,7 +97,7 @@ mumuki.renderers.speechBubble = (()=> {
97
97
  return {
98
98
  SpeechBubbleRenderer,
99
99
  renderSpeechBubbleResultItem
100
- }
100
+ };
101
101
  })();
102
102
 
103
103
  /** @deprecated use {@code mumuki.renderers.speechBubble.SpeechBubbleRenderer} instead */
@@ -101,7 +101,7 @@ mumuki.submission = (() => {
101
101
  });
102
102
  mumuki.kids.showResult(data);
103
103
  });
104
- }
104
+ };
105
105
  }
106
106
 
107
107
  /** Processor for non-kids layouts */
@@ -118,7 +118,7 @@ mumuki.submission = (() => {
118
118
  $(document).renderMuComponents();
119
119
  resultsBox.done(data, submitButton);
120
120
  });
121
- }
121
+ };
122
122
  }
123
123
 
124
124
  /** Selects the most appropriate solution processor */
@@ -96,7 +96,7 @@ mumuki.SubmissionsStore = (() => {
96
96
  _keyFor(exerciseId) {
97
97
  return `/exercise/${exerciseId}/submission`;
98
98
  }
99
- };
99
+ }();
100
100
 
101
101
  return SubmissionsStore;
102
102
  })();
@@ -106,5 +106,5 @@ mumuki.load(() => {
106
106
  if (e.detail[0]) {
107
107
  mumuki.SubmissionsStore.clear();
108
108
  }
109
- })
110
- })
109
+ });
110
+ });
@@ -65,11 +65,11 @@ mumuki.syncMode = (() => {
65
65
 
66
66
  /** @type {ClientSyncMode|ServerSyncMode}*/
67
67
  _current: null
68
- }
68
+ };
69
69
  })();
70
70
 
71
71
  mumuki.load(() => {
72
72
  mumuki.syncMode._selectSyncMode();
73
73
  mumuki.syncMode._current.syncProgress();
74
74
  mumuki.syncMode._current.syncEditorContent();
75
- })
75
+ });
@@ -16,5 +16,5 @@ mumuki.startTimer = (() => {
16
16
  }
17
17
  }, intervalDuration);
18
18
  }
19
- return startTimer
19
+ return startTimer;
20
20
  })();
@@ -25,13 +25,13 @@ body {
25
25
  margin-bottom: 110px;
26
26
  }
27
27
 
28
- .footer {
29
- position: absolute;
30
- bottom: 0;
31
- width: 100%;
32
- height: 110px;
33
- .container {
34
- margin-top: 33px;
28
+ .mu-footer {
29
+ &.container {
30
+ margin-top: 45px;
31
+ }
32
+ .mu-footer-terms {
33
+ font-size: 15px;
34
+ text-align: center;
35
35
  }
36
36
  }
37
37
 
@@ -2,12 +2,18 @@ module WithUserDiscussionValidation
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
+ # users are not allowed to access discussions during exams
6
+ before_action :validate_not_blocked_in_forum!
5
7
  # discussions are not enabled for all organizations nor all users
6
8
  before_action :validate_user_can_discuss!
7
9
  end
8
10
 
9
11
  private
10
12
 
13
+ def validate_not_blocked_in_forum!
14
+ raise Mumuki::Domain::BlockedForumError if current_user&.currently_in_exam?
15
+ end
16
+
11
17
  def validate_user_can_discuss!
12
18
  raise Mumuki::Domain::NotFoundError unless current_user&.can_discuss_here?
13
19
  end
@@ -1,8 +1,6 @@
1
1
  class DiscussionsController < ApplicationController
2
2
  include Mumuki::Laboratory::Controllers::Content
3
3
  include WithUserDiscussionValidation
4
- # users are not allowed to access discussions during exams
5
- before_action :validate_not_in_exam!
6
4
 
7
5
  before_action :set_debatable, except: [:subscription]
8
6
  before_action :authenticate!, only: [:update, :create]
@@ -74,8 +72,4 @@ class DiscussionsController < ApplicationController
74
72
  def discussion_filter_params
75
73
  @filter_params ||= params.permit(Discussion.permitted_query_params)
76
74
  end
77
-
78
- def validate_not_in_exam!
79
- raise Mumuki::Domain::BlockedForumError if current_user&.currently_in_exam?
80
- end
81
75
  end
@@ -52,11 +52,11 @@ module LinksHelper
52
52
  end
53
53
 
54
54
  def link_to_profile_terms
55
- link_to t(:terms_and_conditions).downcase, terms_user_path, target: '_blank'
55
+ link_to t(:terms_and_conditions), terms_user_path, target: '_blank'
56
56
  end
57
57
 
58
58
  def link_to_forum_terms
59
- link_to t(:forum_terms).downcase, discussions_terms_path, target: '_blank'
59
+ link_to t(:forum_terms), discussions_terms_path, target: '_blank'
60
60
  end
61
61
 
62
62
  def turbolinks_enable_for(exercise)
@@ -1,2 +1,2 @@
1
- &copy; Copyright 2015-<%= DateTime.now.year %>
1
+ &copy; 2015-<%= DateTime.now.year %>
2
2
  <a href="http://mumuki.org/" class="mu-org-link"><span class="da da-mumuki-circle"></span> Mumuki</a>
@@ -20,7 +20,7 @@
20
20
  <div class="mu-navbar-avatar">
21
21
  <% if current_logged_user? %>
22
22
  <% if in_gamified_context? %>
23
- <i class="fa fa-star fa-fw fa-2x navbar-icon mu-level-tooltip" data-toggle="tooltip" data-placement="bottom" title="<%= t(:level) %>"></i>
23
+ <i class="fa fa-star fa-fw fa-2x navbar-icon mu-level-tooltip" data-toggle="tooltip" data-placement="bottom" level="<%= t(:level) %>"></i>
24
24
  <span class="mu-level-number"></span>
25
25
  <% end %>
26
26
  <div class="dropdown">
@@ -52,30 +52,32 @@
52
52
 
53
53
  <% content_for :footer do %>
54
54
  <footer class="footer">
55
- <div class="<%= exercise_container_type %>">
56
- <hr>
57
-
58
- <div class="row">
59
- <div class="col-md-12">
55
+ <div class="mu-footer <%= exercise_container_type %>">
56
+ <div class="mu-footer-row">
57
+ <div class="mu-footer-authoring">
60
58
  <%= yield :authoring %>
61
59
  </div>
62
60
  </div>
63
61
 
64
- <div id="footer-copyright" class="row">
65
- <div class="col-md-4 text-left">
66
- <p>
67
- <%= render partial: 'layouts/copyright' %>
68
- </p>
62
+ <div class="mu-footer-row">
63
+ <div class="mu-footer-copyright">
64
+ <%= render partial: 'layouts/copyright' %>
69
65
  </div>
70
66
 
71
- <div class="col-md-4 text-center">
72
- <%= login_form.footer_html %>
67
+ <div class="mu-footer-terms">
68
+ <div><%= link_to_profile_terms %></div>
69
+ <% if current_user&.can_discuss_here? %>
70
+ <div><%= link_to_forum_terms %></div>
71
+ <% end %>
73
72
  </div>
74
73
 
75
- <div id="footer-social" class="col-md-4 text-right" lang="en">
74
+ <%= login_form.footer_html %>
75
+
76
+ <div id="footer-social" class="mu-footer-social" lang="en">
76
77
  <%= render partial: 'layouts/social_media' %>
77
78
  </div>
78
79
  </div>
80
+
79
81
  </div>
80
82
  </footer>
81
83
  <% end %>
@@ -1,22 +1,25 @@
1
1
  <% content_for :footer do %>
2
2
  <footer class="footer">
3
- <div class="<%= exercise_container_type %>">
4
- <hr>
5
-
6
- <div class="row">
7
- <div class="col-md-12">
3
+ <div class="mu-footer <%= exercise_container_type %>">
4
+ <div class="mu-footer-row">
5
+ <div class="mu-footer-authoring">
8
6
  <%= yield :authoring %>
9
7
  </div>
10
8
  </div>
11
9
 
12
- <div id="footer-copyright" class="row hidden-xs hidden-sm">
13
- <div class="col-sm-8 text-left">
14
- <p>
15
- <%= render partial: 'layouts/copyright' %>
16
- </p>
10
+ <div class="mu-footer-row">
11
+ <div class="mu-footer-copyright">
12
+ <%= render partial: 'layouts/copyright' %>
13
+ </div>
14
+
15
+ <div class="mu-footer-terms">
16
+ <div><%= link_to_profile_terms %></div>
17
+ <% if current_user&.can_discuss_here? %>
18
+ <div><%= link_to_forum_terms %></div>
19
+ <% end %>
17
20
  </div>
18
21
 
19
- <div id="footer-social" class="col-sm-4 text-right" lang="en">
22
+ <div id="footer-social" class="mu-footer-social" lang="en">
20
23
  <%= render partial: 'layouts/social_media' %>
21
24
  </div>
22
25
  </div>
@@ -104,7 +104,7 @@ es-CL:
104
104
  first_name: Nombre
105
105
  forbidden_explanation: ¿Puede que hayas ingresado con una cuenta incorrecta?
106
106
  format: Dar formato
107
- forum_terms_link: Si tienes alguna duda, consulta las %{terms_link}
107
+ forum_terms_link: Si tienes alguna duda, accede a las %{terms_link}
108
108
  fullscreen: "Pantalla completa"
109
109
  gender: Género
110
110
  get_messages: "Ver mensajes"
@@ -112,8 +112,8 @@ es:
112
112
  first_name: Nombre
113
113
  forbidden_explanation: ¿Puede que hayas ingresado con una cuenta incorrecta?
114
114
  format: Dar formato
115
- forum_terms: Reglas del foro
116
- forum_terms_link: Si tenés alguna duda, consultá las %{terms_link}
115
+ forum_terms: Reglas del espacio de consultas
116
+ forum_terms_link: Si tenés alguna duda, accedé a las %{terms_link}
117
117
  fullscreen: "Pantalla completa"
118
118
  gender: Género
119
119
  get_messages: "Ver mensajes"
@@ -108,7 +108,7 @@ pt:
108
108
  first_name: Nome
109
109
  forbidden_explanation: Você poderia ter entrado com uma conta incorreta?
110
110
  format: Formato
111
- forum_terms: Regras do fórum
111
+ forum_terms: Regras do espaço de consulta
112
112
  forum_terms_link: Se você tiver alguma dúvida, consulte as %{terms_link}
113
113
  fullscreen: Tela completa
114
114
  gender: Gênero
@@ -1,5 +1,5 @@
1
1
  module Mumuki
2
2
  module Laboratory
3
- VERSION = '8.1.1'
3
+ VERSION = '8.1.2'
4
4
  end
5
5
  end
@@ -26,6 +26,25 @@ describe DiscussionsController, organization_workspace: :test do
26
26
  end
27
27
  end
28
28
 
29
+ describe 'index' do
30
+ context 'when user is banned from forum' do
31
+ before { user.update! banned_from_forum: true }
32
+ before { get :index, params: exercise_params }
33
+
34
+ it { expect(response.status).to eq 404 }
35
+ end
36
+
37
+ context 'when user has exam in progress' do
38
+ let!(:exam) { create(:exam) }
39
+ before { exam.authorize! user }
40
+ before { exam.start! user }
41
+
42
+ before { get :index, params: exercise_params }
43
+
44
+ it { expect(response.status).to eq 403 }
45
+ end
46
+ end
47
+
29
48
  describe 'post' do
30
49
  before { allow_any_instance_of(DiscussionsController).to receive(:discussion_params).and_return title: 'A title' }
31
50
  before { post :create, params: exercise_params }
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 20201027152806) do
13
+ ActiveRecord::Schema.define(version: 20201130163114) do
14
14
 
15
15
  # These are extensions that must be enabled in order to support this database
16
16
  enable_extension "plpgsql"
@@ -433,6 +433,7 @@ ActiveRecord::Schema.define(version: 20201027152806) do
433
433
  t.datetime "privacy_terms_accepted_at"
434
434
  t.datetime "legal_terms_accepted_at"
435
435
  t.datetime "forum_terms_accepted_at"
436
+ t.boolean "banned_from_forum"
436
437
  t.index ["avatar_type", "avatar_id"], name: "index_users_on_avatar_type_and_avatar_id"
437
438
  t.index ["disabled_at"], name: "index_users_on_disabled_at"
438
439
  t.index ["last_organization_id"], name: "index_users_on_last_organization_id"
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: 8.1.1
4
+ version: 8.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Franco Bulgarelli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-06 00:00:00.000000000 Z
11
+ date: 2020-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '1.23'
117
+ version: '1.24'
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '1.23'
124
+ version: '1.24'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: muvment
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -849,121 +849,121 @@ required_rubygems_version: !ruby/object:Gem::Requirement
849
849
  - !ruby/object:Gem::Version
850
850
  version: '0'
851
851
  requirements: []
852
- rubygems_version: 3.1.2
852
+ rubygems_version: 3.0.3
853
853
  signing_key:
854
854
  specification_version: 4
855
855
  summary: Code assement web application for the Mumuki Platform.
856
856
  test_files:
857
- - spec/javascripts/gamification-spec.js
857
+ - spec/controllers/guide_progress_controller_spec.rb
858
+ - spec/controllers/discussions_controller_spec.rb
859
+ - spec/controllers/organizations_api_controller_spec.rb
860
+ - spec/controllers/chapters_controller_spec.rb
861
+ - spec/controllers/invitations_controller_spec.rb
862
+ - spec/controllers/messages_controller_spec.rb
863
+ - spec/controllers/courses_api_controller_spec.rb
864
+ - spec/controllers/confirmations_controller_spec.rb
865
+ - spec/controllers/students_api_controller_spec.rb
866
+ - spec/controllers/api_clients_controller.rb
867
+ - spec/controllers/exercise_solutions_controller_spec.rb
868
+ - spec/controllers/discussions_messages_controller_spec.rb
869
+ - spec/controllers/users_api_controller_spec.rb
870
+ - spec/controllers/users_controller_spec.rb
871
+ - spec/spec_helper.rb
872
+ - spec/api_helper.rb
873
+ - spec/mailers/user_mailer_spec.rb
874
+ - spec/mailers/previews/user_mailer_preview.rb
875
+ - spec/javascripts/elipsis-spec.js
858
876
  - spec/javascripts/csrf-token-spec.js
859
- - spec/javascripts/results-renderers-spec.js
860
- - spec/javascripts/bridge-spec.js
877
+ - spec/javascripts/global-spec.js
878
+ - spec/javascripts/events-spec.js
879
+ - spec/javascripts/gamification-spec.js
880
+ - spec/javascripts/sync-mode-spec.js
881
+ - spec/javascripts/exercise-spec.js
882
+ - spec/javascripts/timer-spec.js
861
883
  - spec/javascripts/editors-spec.js
862
884
  - spec/javascripts/spec-helper.js
885
+ - spec/javascripts/speech-bubble-renderer-spec.js
863
886
  - spec/javascripts/submissions-store-spec.js
887
+ - spec/javascripts/results-renderers-spec.js
888
+ - spec/javascripts/bridge-spec.js
864
889
  - spec/javascripts/timeout-spec.js
865
- - spec/javascripts/timer-spec.js
866
- - spec/javascripts/events-spec.js
867
- - spec/javascripts/exercise-spec.js
868
- - spec/javascripts/speech-bubble-renderer-spec.js
869
- - spec/javascripts/elipsis-spec.js
870
- - spec/javascripts/sync-mode-spec.js
871
- - spec/javascripts/global-spec.js
872
- - spec/spec_helper.rb
873
- - spec/dummy/config/locales/en.yml
874
- - spec/dummy/config/spring.rb
875
- - spec/dummy/config/database.travis.yml
876
- - spec/dummy/config/secrets.yml
877
- - spec/dummy/config/puma.rb
878
- - spec/dummy/config/environment.rb
879
- - spec/dummy/config/application.rb
880
- - spec/dummy/config/database.yml
881
- - spec/dummy/config/rabbit.yml
882
- - spec/dummy/config/boot.rb
883
- - spec/dummy/config/routes.rb
884
- - spec/dummy/config/cable.yml
885
- - spec/dummy/config/environments/test.rb
886
- - spec/dummy/config/environments/development.rb
887
- - spec/dummy/config/initializers/wrap_parameters.rb
888
- - spec/dummy/config/initializers/assets.rb
889
- - spec/dummy/config/initializers/cookies_serializer.rb
890
- - spec/dummy/config/initializers/filter_parameter_logging.rb
891
- - spec/dummy/config.ru
892
- - spec/dummy/public/medal/outline.svg
893
- - spec/dummy/public/character/animations.json
894
- - spec/dummy/public/error/403.svg
895
- - spec/dummy/public/error/410.svg
896
- - spec/dummy/public/error/timeout_3.svg
897
- - spec/dummy/public/error/401.svg
898
- - spec/dummy/public/error/500.svg
899
- - spec/dummy/public/error/404.svg
900
- - spec/dummy/public/error/timeout_2.svg
901
- - spec/dummy/public/error/timeout_1.svg
902
- - spec/dummy/bin/yarn
903
- - spec/dummy/bin/rails
904
- - spec/dummy/bin/setup
905
- - spec/dummy/bin/update
906
- - spec/dummy/bin/rake
907
- - spec/dummy/bin/bundle
908
- - spec/dummy/db/seeds.rb
909
- - spec/dummy/db/schema.rb
910
- - spec/dummy/package.json
911
- - spec/dummy/Rakefile
912
- - spec/evaluation_helper.rb
913
- - spec/helpers/page_title_helper_spec.rb
914
- - spec/helpers/test_results_rendering_spec.rb
915
- - spec/helpers/with_choices_spec.rb
916
- - spec/helpers/authors_helper_spec.rb
917
890
  - spec/helpers/avatar_helper_spec.rb
918
- - spec/helpers/icons_helper_spec.rb
919
- - spec/helpers/email_helper_spec.rb
920
- - spec/helpers/application_helper_spec.rb
921
- - spec/helpers/breadcrumbs_helper_spec.rb
922
891
  - spec/helpers/with_navigation_spec.rb
923
892
  - spec/helpers/exercise_input_helper_spec.rb
924
- - spec/login_helper.rb
925
- - spec/mailers/previews/user_mailer_preview.rb
926
- - spec/mailers/user_mailer_spec.rb
927
- - spec/controllers/guide_progress_controller_spec.rb
928
- - spec/controllers/students_api_controller_spec.rb
929
- - spec/controllers/messages_controller_spec.rb
930
- - spec/controllers/users_api_controller_spec.rb
931
- - spec/controllers/chapters_controller_spec.rb
932
- - spec/controllers/users_controller_spec.rb
933
- - spec/controllers/discussions_messages_controller_spec.rb
934
- - spec/controllers/courses_api_controller_spec.rb
935
- - spec/controllers/organizations_api_controller_spec.rb
936
- - spec/controllers/api_clients_controller.rb
937
- - spec/controllers/discussions_controller_spec.rb
938
- - spec/controllers/exercise_solutions_controller_spec.rb
939
- - spec/controllers/confirmations_controller_spec.rb
940
- - spec/controllers/invitations_controller_spec.rb
941
- - spec/capybara_helper.rb
942
- - spec/teaspoon_env.rb
893
+ - spec/helpers/authors_helper_spec.rb
894
+ - spec/helpers/with_choices_spec.rb
895
+ - spec/helpers/application_helper_spec.rb
896
+ - spec/helpers/breadcrumbs_helper_spec.rb
897
+ - spec/helpers/email_helper_spec.rb
898
+ - spec/helpers/page_title_helper_spec.rb
899
+ - spec/helpers/test_results_rendering_spec.rb
900
+ - spec/helpers/icons_helper_spec.rb
901
+ - spec/features/complements_flow_spec.rb
902
+ - spec/features/progressive_tips_spec.rb
903
+ - spec/features/runner_assets_spec.rb
943
904
  - spec/features/disable_user_flow_spec.rb
944
- - spec/features/invitations_flow_spec.rb
945
- - spec/features/topic_flow_spec.rb
946
- - spec/features/guide_reset_spec.rb
947
- - spec/features/discussion_flow_spec.rb
948
905
  - spec/features/links_flow_spec.rb
949
- - spec/features/not_found_private_flow_spec.rb
950
906
  - spec/features/not_found_public_flow_spec.rb
951
- - spec/features/exercise_flow_spec.rb
952
907
  - spec/features/standard_flow_spec.rb
953
- - spec/features/menu_bar_spec.rb
954
- - spec/features/dynamic_exam_spec.rb
908
+ - spec/features/exercise_flow_spec.rb
909
+ - spec/features/disabled_organization_flow_spec.rb
955
910
  - spec/features/immersive_redirection_spec.rb
956
- - spec/features/runner_assets_spec.rb
957
- - spec/features/progressive_tips_spec.rb
958
- - spec/features/chapter_spec.rb
959
- - spec/features/terms_flow_spec.rb
960
- - spec/features/login_flow_spec.rb
961
- - spec/features/home_public_flow_spec.rb
911
+ - spec/features/topic_flow_spec.rb
912
+ - spec/features/home_private_flow_spec.rb
962
913
  - spec/features/profile_flow_spec.rb
963
- - spec/features/lessons_flow_spec.rb
964
- - spec/features/disabled_organization_flow_spec.rb
965
- - spec/features/complements_flow_spec.rb
914
+ - spec/features/home_public_flow_spec.rb
915
+ - spec/features/menu_bar_spec.rb
916
+ - spec/features/not_found_private_flow_spec.rb
917
+ - spec/features/chapter_spec.rb
918
+ - spec/features/discussion_flow_spec.rb
919
+ - spec/features/invitations_flow_spec.rb
966
920
  - spec/features/exams_flow_spec.rb
967
921
  - spec/features/guides_flow_spec.rb
968
- - spec/features/home_private_flow_spec.rb
969
- - spec/api_helper.rb
922
+ - spec/features/dynamic_exam_spec.rb
923
+ - spec/features/terms_flow_spec.rb
924
+ - spec/features/lessons_flow_spec.rb
925
+ - spec/features/login_flow_spec.rb
926
+ - spec/features/guide_reset_spec.rb
927
+ - spec/evaluation_helper.rb
928
+ - spec/login_helper.rb
929
+ - spec/dummy/db/seeds.rb
930
+ - spec/dummy/db/schema.rb
931
+ - spec/dummy/public/character/animations.json
932
+ - spec/dummy/public/error/500.svg
933
+ - spec/dummy/public/error/timeout_2.svg
934
+ - spec/dummy/public/error/401.svg
935
+ - spec/dummy/public/error/timeout_3.svg
936
+ - spec/dummy/public/error/410.svg
937
+ - spec/dummy/public/error/404.svg
938
+ - spec/dummy/public/error/timeout_1.svg
939
+ - spec/dummy/public/error/403.svg
940
+ - spec/dummy/public/medal/outline.svg
941
+ - spec/dummy/package.json
942
+ - spec/dummy/config/initializers/filter_parameter_logging.rb
943
+ - spec/dummy/config/initializers/wrap_parameters.rb
944
+ - spec/dummy/config/initializers/cookies_serializer.rb
945
+ - spec/dummy/config/initializers/assets.rb
946
+ - spec/dummy/config/database.yml
947
+ - spec/dummy/config/routes.rb
948
+ - spec/dummy/config/cable.yml
949
+ - spec/dummy/config/spring.rb
950
+ - spec/dummy/config/boot.rb
951
+ - spec/dummy/config/puma.rb
952
+ - spec/dummy/config/environments/development.rb
953
+ - spec/dummy/config/environments/test.rb
954
+ - spec/dummy/config/database.travis.yml
955
+ - spec/dummy/config/rabbit.yml
956
+ - spec/dummy/config/secrets.yml
957
+ - spec/dummy/config/locales/en.yml
958
+ - spec/dummy/config/application.rb
959
+ - spec/dummy/config/environment.rb
960
+ - spec/dummy/Rakefile
961
+ - spec/dummy/bin/setup
962
+ - spec/dummy/bin/rake
963
+ - spec/dummy/bin/bundle
964
+ - spec/dummy/bin/update
965
+ - spec/dummy/bin/yarn
966
+ - spec/dummy/bin/rails
967
+ - spec/dummy/config.ru
968
+ - spec/teaspoon_env.rb
969
+ - spec/capybara_helper.rb