mumuki-laboratory 8.6.0 → 8.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/mumuki_laboratory/application/upload.js +69 -14
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_content_show.scss +1 -1
- data/app/helpers/exercise_input_helper.rb +8 -17
- data/app/views/layouts/exercise_inputs/editors/_upload.html.erb +11 -2
- data/app/views/users/terms.html.erb +1 -1
- data/lib/mumuki/laboratory/locales/en.yml +3 -2
- data/lib/mumuki/laboratory/locales/es-CL.yml +3 -2
- data/lib/mumuki/laboratory/locales/es.yml +2 -1
- data/lib/mumuki/laboratory/locales/pt.yml +2 -1
- data/lib/mumuki/laboratory/version.rb +1 -1
- data/spec/features/profile_flow_spec.rb +1 -2
- data/spec/features/terms_flow_spec.rb +30 -0
- data/spec/javascripts/upload-spec.js +80 -0
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 824e346e9d3113f3b3d48c8ed7e23c846e26a54fb5ed7e4c4bb5a9307323b4d7
|
4
|
+
data.tar.gz: e28b9bdf65007abda370a36b760adeaf7989ab9e4c94c52ebaa09bcd3f14fb79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46a32c31bb80eca3fa50fc45c37875a36894cf3fbc2192f339c138763afeac44a811ab336650460a7e7f150323601d92cab90c91e967668916462d21026eb72a
|
7
|
+
data.tar.gz: c9ecc5bd9523a72129d3914317fa29c596038b99f3733de72fc71c27b5c1be3295d9f79ddff39d3cf39c8cfb22bd873581442c4c9121680cdd68901990a11b54
|
@@ -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
|
-
|
4
|
-
|
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
|
-
|
@@ -53,12 +53,11 @@ module ExerciseInputHelper
|
|
53
53
|
waiting_text = t(options.waiting_t) if options.waiting_t.present?
|
54
54
|
%Q{
|
55
55
|
<div class="btn-submit-container">
|
56
|
-
|
57
|
-
class="btn btn-success btn-block btn-submit #{options.classes}"
|
56
|
+
<button class="btn btn-success btn-block btn-submit #{options.classes}"
|
58
57
|
data-waiting="#{waiting_text}">
|
59
|
-
#{fa_icon
|
58
|
+
#{fa_icon 'play'}
|
60
59
|
#{text} #{remaining_attempts_text(assignment)}
|
61
|
-
|
60
|
+
</button>
|
62
61
|
</div>
|
63
62
|
}.html_safe
|
64
63
|
end
|
@@ -92,26 +91,18 @@ module ExerciseInputHelper
|
|
92
91
|
|
93
92
|
def submit_button_options(exercise)
|
94
93
|
if exercise.upload?
|
95
|
-
struct
|
96
|
-
tag: :label,
|
94
|
+
struct classes: 'disabled',
|
97
95
|
waiting_t: :uploading_solution,
|
98
|
-
|
99
|
-
t: :upload_solution
|
96
|
+
t: :create_submission
|
100
97
|
elsif exercise.hidden?
|
101
|
-
struct
|
102
|
-
classes: 'submission_control',
|
98
|
+
struct classes: 'submission_control',
|
103
99
|
waiting_t: :working,
|
104
|
-
fa_icon: :play,
|
105
100
|
t: :continue_exercise
|
106
101
|
elsif exercise.input_kids?
|
107
|
-
struct
|
108
|
-
classes: 'submission_control',
|
109
|
-
fa_icon: :play
|
102
|
+
struct classes: 'submission_control'
|
110
103
|
else
|
111
|
-
struct
|
112
|
-
classes: 'submission_control',
|
104
|
+
struct classes: 'submission_control',
|
113
105
|
waiting_t: :sending_solution,
|
114
|
-
fa_icon: :play,
|
115
106
|
t: :create_submission
|
116
107
|
end
|
117
108
|
end
|
@@ -1,4 +1,13 @@
|
|
1
1
|
<div class="form-group">
|
2
|
-
|
3
|
-
|
2
|
+
<% @max_file_size = 256000 %>
|
3
|
+
|
4
|
+
<textarea id="solution_content" type="text" name="solution[content]" class="hidden"></textarea>
|
5
|
+
<input id="mu-upload-input" type="file" class="upload submission-control hidden" mu-upload-file-limit=<%= @max_file_size %> accept=".<%= @exercise.language.extension %>" />
|
6
|
+
<div>
|
7
|
+
<label id="mu-upload-label" for="mu-upload-input" class="btn btn-success">
|
8
|
+
<%= fa_icon(:upload, text: t(:select_file), id: "mu-upload-icon") %>
|
9
|
+
</label>
|
10
|
+
<div id="mu-upload-file-limit-exceeded" class="hidden">
|
11
|
+
<%= fa_icon("exclamation-triangle", text: t(:file_exceeds_max_size, size_kb: (@max_file_size / 1000))) %></div>
|
12
|
+
</div>
|
4
13
|
</div>
|
@@ -111,6 +111,7 @@ en:
|
|
111
111
|
failed: Oops, something went wrong
|
112
112
|
feedback: Feedback
|
113
113
|
female: Female
|
114
|
+
file_exceeds_max_size: "File size should not exceed %{size_kb}kb. Please select another file."
|
114
115
|
finish: Finish
|
115
116
|
first_name: First Name
|
116
117
|
forbidden_explanation: Please verify you have logged in with the right account
|
@@ -233,6 +234,7 @@ en:
|
|
233
234
|
running: running
|
234
235
|
save: Save
|
235
236
|
see_context: Watch exercise introduction animation
|
237
|
+
select_file: Select file
|
236
238
|
sending_solution: Sending solution
|
237
239
|
show: Show
|
238
240
|
sign_in: Sign in
|
@@ -289,13 +291,12 @@ en:
|
|
289
291
|
unprepared_organization_explanation: This path hasn't started yet.
|
290
292
|
unsubscribe: Unsubscribe
|
291
293
|
unsubscribed_successfully: You have successfully unsubscribed from reminders.
|
292
|
-
upload_solution: Upload Solution
|
293
294
|
uploading_solution: "Uploading solution"
|
294
295
|
upvote: Upvote
|
295
296
|
upvotes_count_desc: Most voted
|
296
297
|
upvotes_count_asc: Least voted
|
297
298
|
user: User
|
298
|
-
user_data_updated: Your data was updated
|
299
|
+
user_data_updated: Your data was updated successfully
|
299
300
|
username: Username
|
300
301
|
view_details: View details
|
301
302
|
want_permissions: The next user requires permissions
|
@@ -109,6 +109,7 @@ es-CL:
|
|
109
109
|
failed: Tu solución no pasó las pruebas
|
110
110
|
feedback: Problemas que encontramos
|
111
111
|
female: Mujer
|
112
|
+
file_exceeds_max_size: "El tamaño de archivo no debe exceder %{size_kb}kb. Por favor selecciona otro archivo."
|
112
113
|
finish: Terminar
|
113
114
|
first_name: Nombre
|
114
115
|
forbidden_explanation: ¿Puede que hayas ingresado con una cuenta incorrecta?
|
@@ -167,7 +168,7 @@ es-CL:
|
|
167
168
|
messages_error: Los mensajes anteriores no están disponibles en este momento. ¡Vuelve a intentar más tarde!
|
168
169
|
minute: minuto
|
169
170
|
minutes: minutos
|
170
|
-
moderation:
|
171
|
+
moderation: Mentoría
|
171
172
|
moderator: Mentor
|
172
173
|
more_messages: Ver mensajes anteriores
|
173
174
|
my_doubts: Mis consultas
|
@@ -236,6 +237,7 @@ es-CL:
|
|
236
237
|
running: procesando
|
237
238
|
save: Guardar
|
238
239
|
see_context: Mira la animación del principio
|
240
|
+
select_file: Seleccionar archivo
|
239
241
|
send: Enviar
|
240
242
|
sending_solution: Enviando solución
|
241
243
|
show: Mostrar
|
@@ -297,7 +299,6 @@ es-CL:
|
|
297
299
|
unprepared_organization_explanation: ¡Este recorrido aún no ha comenzado!
|
298
300
|
unsubscribe: Dejar de recibir notificaciones
|
299
301
|
unsubscribed_successfully: Te desuscribiste exitosamente de los recordatorios.
|
300
|
-
upload_solution: "Subir solución"
|
301
302
|
uploading_solution: "Subiendo solución"
|
302
303
|
upvote: Es útil
|
303
304
|
upvotes_count_desc: Más útiles
|
@@ -117,6 +117,7 @@ es:
|
|
117
117
|
failed: Tu solución no pasó las pruebas
|
118
118
|
feedback: Problemas que encontramos
|
119
119
|
female: Mujer
|
120
|
+
file_exceeds_max_size: "El tamaño de archivo no debe exceder %{size_kb}kb. Por favor seleccioná otro archivo."
|
120
121
|
finish: Terminar
|
121
122
|
first_name: Nombre
|
122
123
|
forbidden_explanation: ¿Puede que hayas ingresado con una cuenta incorrecta?
|
@@ -251,6 +252,7 @@ es:
|
|
251
252
|
running: procesando
|
252
253
|
save: Guardar
|
253
254
|
see_context: Mirá la animación del principio
|
255
|
+
select_file: Seleccionar archivo
|
254
256
|
send: Enviar
|
255
257
|
sending_solution: Enviando solución
|
256
258
|
show: Mostrar
|
@@ -313,7 +315,6 @@ es:
|
|
313
315
|
unprepared_organization_explanation: Este recorrido aún no ha comenzado
|
314
316
|
unsubscribe: Dejar de recibir notificaciones
|
315
317
|
unsubscribed_successfully: Te desuscribiste exitosamente de los recordatorios.
|
316
|
-
upload_solution: "Subir solución"
|
317
318
|
uploading_solution: "Subiendo solución"
|
318
319
|
upvote: Es útil
|
319
320
|
upvotes_count_desc: Más útiles
|
@@ -113,6 +113,7 @@ pt:
|
|
113
113
|
failed: Sua solução não passou as provas
|
114
114
|
feedback: Problemas que encontramos
|
115
115
|
female: Feminino
|
116
|
+
file_exceeds_max_size: "O tamanho do arquivo não deve exceder %{size_kb}kb. Selecione outro arquivo."
|
116
117
|
finish: Terminar
|
117
118
|
first_name: Nome
|
118
119
|
forbidden_explanation: Você poderia ter entrado com uma conta incorreta?
|
@@ -240,6 +241,7 @@ pt:
|
|
240
241
|
running: processamento
|
241
242
|
save: Salvar
|
242
243
|
see_context: Veja a animação desde o início
|
244
|
+
select_file: Selecione o arquivo
|
243
245
|
send: Enviar
|
244
246
|
sending_solution: Solução de envio
|
245
247
|
show: Mostrar
|
@@ -296,7 +298,6 @@ pt:
|
|
296
298
|
unmeet_expectations: Objetivos que não foram atendidos
|
297
299
|
unprepared_organization_explanation: Este curso ainda não começou
|
298
300
|
unsubscribe: Cancelar subscrição
|
299
|
-
upload_solution: Carregar solução
|
300
301
|
uploading_solution: Uploading solution
|
301
302
|
user: Usuário
|
302
303
|
user_data_updated: Os seus dados foram atualizados corretamente
|
@@ -95,9 +95,8 @@ feature 'Profile Flow', organization_workspace: :test do
|
|
95
95
|
visit "/user/edit"
|
96
96
|
fill_in('user_first_name', with: 'first_name')
|
97
97
|
|
98
|
-
# Match :first is used because there are two buttons: mobile and desktop.
|
99
98
|
click_on(button_options)
|
100
|
-
expect(page).to have_text('Your data was updated
|
99
|
+
expect(page).to have_text('Your data was updated successfully')
|
101
100
|
expect(page).to have_text('Profile')
|
102
101
|
end
|
103
102
|
end
|
@@ -153,5 +153,35 @@ feature 'Terms Flow', organization_workspace: :test do
|
|
153
153
|
end
|
154
154
|
end
|
155
155
|
|
156
|
+
context 'with incognito mode' do
|
157
|
+
before { test_organization.update! incognito_mode_enabled: true }
|
158
|
+
|
159
|
+
describe 'visit user terms path' do
|
160
|
+
let(:terms_path) { '/user/terms' }
|
161
|
+
let(:expected_terms) { general_terms_scopes }
|
162
|
+
|
163
|
+
it_behaves_like 'has expected terms'
|
164
|
+
end
|
165
|
+
|
166
|
+
scenario 'visit any other path' do
|
167
|
+
visit '/'
|
168
|
+
|
169
|
+
expect(page).to have_text('Start Practicing')
|
170
|
+
end
|
171
|
+
|
172
|
+
context 'visit forum' do
|
173
|
+
let(:terms_path) { '/discussions/terms' }
|
174
|
+
|
175
|
+
context 'with enabled forum' do
|
176
|
+
before { test_organization.update! forum_enabled: true }
|
177
|
+
|
178
|
+
scenario 'visit forum' do
|
179
|
+
visit '/discussions/terms'
|
180
|
+
expect(page).to have_text('You may have mistyped the address or the page may have moved')
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
156
186
|
end
|
157
187
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
describe('upload', () => {
|
2
|
+
const fileSizeLimit = 20;
|
3
|
+
|
4
|
+
fixture.set(`
|
5
|
+
<textarea id="solution_content" type="text" name="solution[content]" class="hidden"></textarea>
|
6
|
+
<input id="mu-upload-input" type="file" class="upload submission-control hidden" mu-upload-file-limit=${fileSizeLimit} accept=".txt" />
|
7
|
+
<label id="mu-upload-label" for="mu-upload-input" class="btn btn-success"></label>
|
8
|
+
<button class="btn btn-success btn-block btn-submit disabled"></button>
|
9
|
+
<div id="mu-upload-file-limit-exceeded" class="hidden"></div>
|
10
|
+
`);
|
11
|
+
|
12
|
+
beforeEach(() => {
|
13
|
+
mumuki.upload._setUI();
|
14
|
+
});
|
15
|
+
|
16
|
+
function reader(file, done) {
|
17
|
+
let fileReader = new mumuki.upload.FileUploader(file).uploadFileIfValid();
|
18
|
+
if (fileReader) {
|
19
|
+
fileReader.addEventListener('load', () => done());
|
20
|
+
fileReader.addEventListener('error', done);
|
21
|
+
return fileReader;
|
22
|
+
} else {
|
23
|
+
done();
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
describe('no file is uploaded', () => {
|
28
|
+
beforeEach((done) => {
|
29
|
+
reader(null, done);
|
30
|
+
});
|
31
|
+
|
32
|
+
it('loads no solution', function () {
|
33
|
+
expect($('#solution_content').html()).toEqual('');
|
34
|
+
});
|
35
|
+
|
36
|
+
it('does not allow submitting', function () {
|
37
|
+
expect($('.btn-submit').hasClass('disabled')).toBe(true);
|
38
|
+
});
|
39
|
+
|
40
|
+
it('does not exceed max file size', function () {
|
41
|
+
expect($('#mu-upload-file-limit-exceeded').hasClass('hidden')).toBe(true);
|
42
|
+
});
|
43
|
+
});
|
44
|
+
|
45
|
+
describe('small file is uploaded', () => {
|
46
|
+
beforeEach((done) => {
|
47
|
+
reader(new File(["short solution"], "short.txt"), done);
|
48
|
+
});
|
49
|
+
|
50
|
+
it('loads solution', function () {
|
51
|
+
expect($('#solution_content').html()).toEqual('short solution');
|
52
|
+
});
|
53
|
+
|
54
|
+
it('allows submitting', function () {
|
55
|
+
expect($('.btn-submit').hasClass('disabled')).toBe(false);
|
56
|
+
});
|
57
|
+
|
58
|
+
it('does not exceed max file size', function () {
|
59
|
+
expect($('#mu-upload-file-limit-exceeded').hasClass('hidden')).toBe(true);
|
60
|
+
});
|
61
|
+
});
|
62
|
+
|
63
|
+
describe('large file is uploaded', () => {
|
64
|
+
beforeEach((done) => {
|
65
|
+
reader(new File(["solution that is too long to be allowed"], "long.txt"), done);
|
66
|
+
});
|
67
|
+
|
68
|
+
it('loads no solution', function () {
|
69
|
+
expect($('#solution_content').html()).toEqual('');
|
70
|
+
});
|
71
|
+
|
72
|
+
it('does not allow submitting', function () {
|
73
|
+
expect($('.btn-submit').hasClass('disabled')).toBe(true);
|
74
|
+
});
|
75
|
+
|
76
|
+
it('exceeds max file size', function () {
|
77
|
+
expect($('#mu-upload-file-limit-exceeded').hasClass('hidden')).toBe(false);
|
78
|
+
});
|
79
|
+
});
|
80
|
+
});
|
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.6.
|
4
|
+
version: 8.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Franco Bulgarelli
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-02-
|
11
|
+
date: 2021-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -810,6 +810,7 @@ files:
|
|
810
810
|
- spec/javascripts/sync-mode-spec.js
|
811
811
|
- spec/javascripts/timeout-spec.js
|
812
812
|
- spec/javascripts/timer-spec.js
|
813
|
+
- spec/javascripts/upload-spec.js
|
813
814
|
- spec/login_helper.rb
|
814
815
|
- spec/mailers/previews/user_mailer_preview.rb
|
815
816
|
- spec/mailers/user_mailer_spec.rb
|
@@ -859,7 +860,7 @@ homepage: https://mumuki.io
|
|
859
860
|
licenses:
|
860
861
|
- AGPL-3.0
|
861
862
|
metadata: {}
|
862
|
-
post_install_message:
|
863
|
+
post_install_message:
|
863
864
|
rdoc_options: []
|
864
865
|
require_paths:
|
865
866
|
- lib
|
@@ -874,9 +875,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
874
875
|
- !ruby/object:Gem::Version
|
875
876
|
version: '0'
|
876
877
|
requirements: []
|
877
|
-
rubyforge_project:
|
878
|
+
rubyforge_project:
|
878
879
|
rubygems_version: 2.7.6
|
879
|
-
signing_key:
|
880
|
+
signing_key:
|
880
881
|
specification_version: 4
|
881
882
|
summary: Code assement web application for the Mumuki Platform.
|
882
883
|
test_files:
|
@@ -987,6 +988,7 @@ test_files:
|
|
987
988
|
- spec/javascripts/editors-spec.js
|
988
989
|
- spec/javascripts/exercise-spec.js
|
989
990
|
- spec/javascripts/elipsis-spec.js
|
991
|
+
- spec/javascripts/upload-spec.js
|
990
992
|
- spec/javascripts/spec-helper.js
|
991
993
|
- spec/javascripts/submissions-store-spec.js
|
992
994
|
- spec/javascripts/gamification-spec.js
|