mumuki-laboratory 8.6.1 → 9.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/mumuki_laboratory/application/_layout.scss +3 -0
  3. data/app/assets/stylesheets/mumuki_laboratory/application/_modules.scss +1 -0
  4. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_content_show.scss +15 -2
  5. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_medal.scss +1 -1
  6. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_menu.scss +35 -0
  7. data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_profile.scss +11 -0
  8. data/app/controllers/api/base_controller.rb +0 -1
  9. data/app/controllers/api/courses_controller.rb +1 -1
  10. data/app/controllers/api/organizations_controller.rb +5 -2
  11. data/app/controllers/api/roles_controller.rb +4 -0
  12. data/app/controllers/api/users_controller.rb +6 -1
  13. data/app/controllers/concerns/with_authorization.rb +1 -16
  14. data/app/controllers/concerns/with_user_params.rb +4 -0
  15. data/app/controllers/discussions_messages_controller.rb +0 -1
  16. data/app/controllers/users_controller.rb +8 -5
  17. data/app/helpers/breadcrumbs_helper.rb +4 -0
  18. data/app/helpers/content_view_helper.rb +19 -0
  19. data/app/helpers/links_helper.rb +2 -2
  20. data/app/helpers/menu_bar_helper.rb +1 -1
  21. data/app/helpers/user_menu_helper.rb +18 -0
  22. data/app/views/chapters/show.html.erb +15 -14
  23. data/app/views/complements/show.html.erb +1 -1
  24. data/app/views/exams/show.html.erb +1 -1
  25. data/app/views/{layouts → exercises}/_exercise_skipped.html.erb +0 -0
  26. data/app/views/exercises/_exercise_title_icons.html.erb +4 -0
  27. data/app/views/exercises/show.html.erb +4 -7
  28. data/app/views/{layouts → guides}/_guide.html.erb +0 -0
  29. data/app/views/guides/_guide_container.html.erb +24 -0
  30. data/app/views/{layouts → guides}/_guide_title_icons.html.erb +1 -3
  31. data/app/views/layouts/_progress_listing.html.erb +1 -1
  32. data/app/views/layouts/_user_menu.html.erb +21 -0
  33. data/app/views/lessons/show.html.erb +1 -1
  34. data/app/views/users/_user_form.html.erb +10 -8
  35. data/app/views/users/discussions.html.erb +28 -0
  36. data/app/views/users/edit.html.erb +1 -1
  37. data/app/views/users/messages.html.erb +27 -0
  38. data/app/views/users/show.html.erb +4 -51
  39. data/app/views/users/terms.html.erb +1 -1
  40. data/config/routes.rb +3 -0
  41. data/lib/mumuki/laboratory/locales/en.yml +3 -1
  42. data/lib/mumuki/laboratory/locales/es-CL.yml +3 -1
  43. data/lib/mumuki/laboratory/locales/es.yml +3 -1
  44. data/lib/mumuki/laboratory/locales/pt.yml +3 -1
  45. data/lib/mumuki/laboratory/version.rb +1 -1
  46. data/spec/controllers/organizations_api_controller_spec.rb +16 -9
  47. data/spec/dummy/db/schema.rb +23 -0
  48. data/spec/features/exercise_flow_spec.rb +3 -3
  49. data/spec/features/login_flow_spec.rb +1 -1
  50. data/spec/features/menu_bar_spec.rb +24 -24
  51. data/spec/features/profile_flow_spec.rb +5 -7
  52. metadata +17 -10
  53. data/app/views/layouts/_guide_container.html.erb +0 -28
@@ -0,0 +1,24 @@
1
+ <%= content_for :breadcrumbs do %>
2
+ <%= breadcrumbs subject %>
3
+ <% end %>
4
+
5
+ <%= render layout: 'guides/guide', locals: { subject: subject } do %>
6
+
7
+ <div class="row">
8
+ <div class="mu-inline-block-right hidden-xs">
9
+ <h1><%= language_icon @guide.language %></h1>
10
+ </div>
11
+ <div class="mu-inline-block-left">
12
+ <h1><%= short_title_for @guide %></h1>
13
+ <%= render partial: 'guides/guide_title_icons' %>
14
+ </div>
15
+ </div>
16
+ <div class="row">
17
+ <div class="col-md-12">
18
+ <div class="text-box">
19
+ <%= @guide.description_html %>
20
+ </div>
21
+ </div>
22
+ </div>
23
+
24
+ <% end %>
@@ -1,8 +1,6 @@
1
- <div class="guide-title-icons pull-left">
1
+ <div class="mu-content-title-icons">
2
2
  <% if current_user? && should_display_medal?(@guide, Organization.current) %>
3
- <div class="pull-left">
4
3
  <%= content_medal_for(@guide, current_user) %>
5
- </div>
6
4
  <% end %>
7
5
  <%= teacher_info_button @guide %>
8
6
  <%= link_to_bibliotheca_guide @guide %>
@@ -1,6 +1,6 @@
1
1
  <ul class="progress-listing">
2
2
  <% guide.assignments_for(current_user).each do |assignment| %>
3
- <% cache [assignment.exercise, assignment.status, Organization.current] do %>
3
+ <% cache [assignment.exercise, assignment.status, Organization.current.name, current_user?] do %>
4
4
  <li <%= turbolinks_enable_for(assignment.exercise) %>>
5
5
  <%= assignment_status_icon assignment %>
6
6
  <%= link_to_path_element(assignment.exercise) %>
@@ -0,0 +1,21 @@
1
+ <div class="col-md-3 mu-tab-body mu-user-menu">
2
+ <div class="col-md-12">
3
+ <div class="mu-user-menu-header">
4
+ <%= t(:my_account) %>
5
+ </div>
6
+ <div class="mu-user-menu-item">
7
+ <%= profile_user_menu_link %>
8
+ </div>
9
+ <div class="mu-user-menu-divider horizontal"></div>
10
+ <div class="mu-user-menu-item">
11
+ <%= messages_user_menu_link %>
12
+ </div>
13
+ <% if current_user&.can_discuss_here? %>
14
+ <div class="mu-user-menu-item">
15
+ <%= discussions_user_menu_link %>
16
+ </div>
17
+ <% end %>
18
+ </div>
19
+ <div class="mu-user-menu-divider vertical hidden-sm hidden-xs"></div>
20
+ </div>
21
+ <div class="mu-user-menu-divider horizontal visible-sm visible-xs"></div>
@@ -1 +1 @@
1
- <%= render partial: "layouts/guide_container", locals: { subject: @lesson }%>
1
+ <%= render partial: "guides/guide_container", locals: { subject: @lesson }%>
@@ -1,11 +1,11 @@
1
1
  <div class="mu-user-header">
2
- <h1><%= @user.name %></h1>
2
+ <h1><%= t(:my_profile) %></h1>
3
3
  <div class="mu-profile-actions hidden-xs">
4
4
  <%= edit_profile_button %>
5
5
  </div>
6
6
  </div>
7
- <div class="row mu-tab-body">
8
- <div class="col-md-4 mu-profile-info-left">
7
+ <div class="mu-profile-info">
8
+ <div class="mu-profile-info-left">
9
9
  <%= profile_picture_for(@user, id: 'mu-user-avatar', class: 'mu-user-avatar') %>
10
10
  <% if in_gamified_context? %>
11
11
  <svg class="mu-level-progress" width="300" height="300" viewBox="0 0 100 100">
@@ -18,7 +18,10 @@
18
18
  </div>
19
19
  <% end %>
20
20
  </div>
21
- <div class="col-md-8 mu-profile-info-right">
21
+ <div class="mu-profile-info-right">
22
+ <div>
23
+ <span> <strong><%= t :name %>:</strong> <%= "#{@user.name}" %> </span>
24
+ </div>
22
25
  <% if @user.age.present? %>
23
26
  <div>
24
27
  <span> <strong><%= t :age %>:</strong> <%= "#{@user.age} #{t :years}" %> </span>
@@ -31,8 +34,7 @@
31
34
  <span> <strong><%= t :programming_since %>:</strong> <%= t(:time_since, time: time_ago_in_words(@user.created_at)) %> </span>
32
35
  </div>
33
36
  </div>
34
-
35
- <div class="mu-profile-actions mobile visible-xs">
36
- <%= edit_profile_button %>
37
- </div>
37
+ </div>
38
+ <div class="mu-profile-actions mobile visible-xs">
39
+ <%= edit_profile_button %>
38
40
  </div>
@@ -0,0 +1,28 @@
1
+ <%= content_for :breadcrumbs do %>
2
+ <%= breadcrumbs_for_my_account %>
3
+ <% end %>
4
+
5
+ <%= render partial: 'layouts/user_menu' %>
6
+
7
+ <div class="col-md-9 mu-tab-body">
8
+ <div class="mu-user-header">
9
+ <h1><%= t(:discussions) %></h1>
10
+ </div>
11
+ <% if @watched_discussions.empty? %>
12
+ <div class="mu-tab-body">
13
+ <%= t :discussions_will_be_here %>
14
+ </div>
15
+ <% else %>
16
+ <table class="table table-striped">
17
+ <% @watched_discussions.each do |discussion| %>
18
+ <tr>
19
+ <td>
20
+ <%= icon_for_read(discussion.read_by?(@user)) %>
21
+ </td>
22
+ <td><%= link_to discussion.item.name, item_discussion_path(discussion) %></td>
23
+ <td><%= time_ago_in_words discussion.last_message_date %></td>
24
+ </tr>
25
+ <% end %>
26
+ </table>
27
+ <% end %>
28
+ </div>
@@ -1,5 +1,5 @@
1
1
  <%= content_for :breadcrumbs do %>
2
- <%= breadcrumbs @user %>
2
+ <%= breadcrumbs_for_my_account %>
3
3
  <% end %>
4
4
 
5
5
  <%= render partial: 'edit_user_form' %>
@@ -0,0 +1,27 @@
1
+ <%= content_for :breadcrumbs do %>
2
+ <%= breadcrumbs_for_my_account %>
3
+ <% end %>
4
+
5
+ <%= render partial: 'layouts/user_menu' %>
6
+
7
+ <div class="col-md-9 mu-tab-body">
8
+ <div class="mu-user-header">
9
+ <h1><%= t(:messages) %></h1>
10
+ </div>
11
+ <% if @messages.empty? %>
12
+ <div class="mu-tab-body">
13
+ <%= t :no_messages %>
14
+ </div>
15
+ <% else %>
16
+ <table class="table table-striped">
17
+ <% @messages.each do |message| %>
18
+ <tr>
19
+ <td><%= icon_for_read(message.read?) %></td>
20
+ <td><%= link_to message.exercise.name, exercise_path(message.exercise.id) %></td>
21
+ <td><%= mail_to message.sender %></td>
22
+ <td><%= time_ago_in_words message.created_at %></td>
23
+ </tr>
24
+ <% end %>
25
+ </table>
26
+ <% end %>
27
+ </div>
@@ -1,56 +1,9 @@
1
1
  <%= content_for :breadcrumbs do %>
2
- <%= breadcrumbs @user %>
2
+ <%= breadcrumbs_for_my_account %>
3
3
  <% end %>
4
4
 
5
- <ul class="nav nav-tabs" role="tablist">
6
- <li role="presentation" class="active">
7
- <a data-target="#info" aria-controls="info" role="tab" data-toggle="tab"><%= t :profile %></a>
8
- </li>
9
- <li role="presentation">
10
- <a data-target="#messages" aria-controls="messages" role="tab" data-toggle="tab"><%= t :messages %></a>
11
- </li>
12
- <% if @watched_discussions.present? %>
13
- <li role="presentation">
14
- <a data-target="#discussions" aria-controls="discussions" role="tab" data-toggle="tab"><%= t :discussions %></a>
15
- </li>
16
- <% end %>
17
- </ul>
5
+ <%= render partial: 'layouts/user_menu' %>
18
6
 
19
- <div class="tab-content">
20
- <div role="tabpanel" class="tab-pane active" id="info">
21
- <%= render partial: 'user_form' %>
22
- </div>
23
- <div role="tabpanel" class="tab-pane" id="messages">
24
- <% if @messages.empty? %>
25
- <div class="row mu-tab-body col-md-12">
26
- <%= t :no_messages %>
27
- </div>
28
- <% else %>
29
- <table class="table table-striped">
30
- <% @messages.each do |message| %>
31
- <tr>
32
- <td><%= icon_for_read(message.read?) %></td>
33
- <td><%= link_to message.exercise.name, exercise_path(message.exercise.id) %></td>
34
- <td><%= mail_to message.sender %></td>
35
- <td><%= time_ago_in_words message.created_at %></td>
36
- </tr>
37
- <% end %>
38
- </table>
39
- <% end %>
40
- </div>
41
- <% if @watched_discussions.present? %>
42
- <div role="tabpanel" class="tab-pane" id="discussions">
43
- <table class="table table-striped">
44
- <% @watched_discussions.each do |discussion| %>
45
- <tr>
46
- <td>
47
- <%= icon_for_read(discussion.read_by?(@user)) %>
48
- </td>
49
- <td><%= link_to discussion.item.name, item_discussion_path(discussion) %></td>
50
- <td><%= time_ago_in_words discussion.last_message_date %></td>
51
- </tr>
52
- <% end %>
53
- </table>
54
- </div>
55
- <% end %>
7
+ <div class="col-md-9 mu-tab-body">
8
+ <%= render partial: 'user_form' %>
56
9
  </div>
@@ -1,6 +1,6 @@
1
1
  <%= content_for :breadcrumbs do %>
2
2
  <% if current_logged_user? %>
3
- <%= breadcrumbs @user %>
3
+ <%= breadcrumbs_for_my_account %>
4
4
  <% else %>
5
5
  <%= header_breadcrumbs %>
6
6
  <% end %>
data/config/routes.rb CHANGED
@@ -62,6 +62,9 @@ Rails.application.routes.draw do
62
62
 
63
63
  # Notification subscriptions
64
64
  get :unsubscribe
65
+
66
+ get :messages
67
+ get :discussions
65
68
  end
66
69
 
67
70
  resources :messages, only: [:index, :create]
@@ -68,6 +68,7 @@ en:
68
68
  new_discussion_message: New message on %{title}
69
69
  discussion_updated: Discussion updated
70
70
  discussions: Discussions
71
+ discussions_will_be_here: Your posts in the forum will appear here.
71
72
  dont_leave_us: Don't leave us! Learning is fun. You just have to keep at it.
72
73
  download: Download your solution
73
74
  edit: Edit
@@ -170,7 +171,9 @@ en:
170
171
  moderation: Mentoring
171
172
  moderator: Mentor
172
173
  more_messages: More
174
+ my_account: My account
173
175
  my_doubts: My doubts
176
+ my_profile: My profile
174
177
  my_submissions: My Submissions
175
178
  name: Name
176
179
  navigation_continue: 'Next: %{sibling}'
@@ -217,7 +220,6 @@ en:
217
220
  previous_exercise: Previous
218
221
  problem_with_exercise: '[Mumuki] Problem with exercise: %{title}'
219
222
  processing_your_solution: We are processing you solution
220
- profile: Profile
221
223
  profile_of: Profile of %{username}
222
224
  programming_since: Started programming
223
225
  progress: Progresss
@@ -68,6 +68,7 @@ es-CL:
68
68
  new_discussion_message: Mensaje nuevo en %{title}
69
69
  discussion_updated: Consulta actualizada
70
70
  discussions: Consultas
71
+ discussions_will_be_here: Las preguntas que realices en el espacio de consultas aparecerán aquí.
71
72
  dont_leave_us: ¡No nos abandones! Aprender a programar es divertido. Sólo tienes que seguir practicando.
72
73
  download: "Descarga lo que hiciste"
73
74
  edit: Editar
@@ -171,7 +172,9 @@ es-CL:
171
172
  moderation: Mentoría
172
173
  moderator: Mentor
173
174
  more_messages: Ver mensajes anteriores
175
+ my_account: Mi cuenta
174
176
  my_doubts: Mis consultas
177
+ my_profile: Mi perfil
175
178
  name: Nombre
176
179
  navigation_continue: 'Siguiente %{kind}: %{sibling}'
177
180
  navigation_next: Siguiente %{kind}
@@ -223,7 +226,6 @@ es-CL:
223
226
  previous_exercise: Anterior
224
227
  problem_with_exercise: '[Mumuki] Error con el ejercicio: %{title}'
225
228
  processing_your_solution: Estamos procesando tu solución
226
- profile: Perfil
227
229
  profile_of: Perfil de %{username}
228
230
  progress: Progreso
229
231
  read: Leído
@@ -75,6 +75,7 @@ es:
75
75
  discussion_updated: Consulta actualizada
76
76
  new_discussion_message: Mensaje nuevo en %{title}
77
77
  discussions: Consultas
78
+ discussions_will_be_here: Las preguntas que realices en el espacio de consultas aparecerán aquí.
78
79
  dont_leave_us: ¡No nos abandones! Aprender a programar es divertido. Sólo tenés que seguir practicando.
79
80
  download: "Descargá lo que hiciste"
80
81
  edit: Editar
@@ -182,7 +183,9 @@ es:
182
183
  moderation: Mentoría
183
184
  moderator: Mentor
184
185
  more_messages: Ver mensajes anteriores
186
+ my_account: Mi cuenta
185
187
  my_doubts: Mis consultas
188
+ my_profile: Mi perfil
186
189
  name: Nombre
187
190
  navigation_continue: 'Siguiente %{kind}: %{sibling}'
188
191
  navigation_next: Siguiente %{kind}
@@ -234,7 +237,6 @@ es:
234
237
  previous_exercise: Anterior
235
238
  problem_with_exercise: '[Mumuki] Error con el ejercicio: %{title}'
236
239
  processing_your_solution: Estamos procesando tu solución
237
- profile: Perfil
238
240
  profile_of: Perfil de %{username}
239
241
  programming_since: Programando desde
240
242
  progress: Progreso
@@ -72,6 +72,7 @@ pt:
72
72
  new_discussion_message: Nova mensagem em %{title}
73
73
  discussion_updated: Consulta actualizada
74
74
  discussions: Consultas
75
+ discussions_will_be_here: As perguntas que você fizer no espaço de consulta aparecerão aqui.
75
76
  download: Faça o download do que você fez
76
77
  edit: Editar
77
78
  edit_profile: Editar perfil
@@ -176,7 +177,9 @@ pt:
176
177
  moderation: Mentoria
177
178
  moderator: Mentor
178
179
  more_messages: Ver as mensagens anteriores
180
+ my_account: Minha conta
179
181
  my_doubts: Minhas duvidas
182
+ my_profile: Meu perfil
180
183
  name: Nome
181
184
  navigation_continue: "Próximo %{kind}: %{sibling}"
182
185
  navigation_next: Próximo %{kind}
@@ -225,7 +228,6 @@ pt:
225
228
  previous_exercise: Anterior
226
229
  problem_with_exercise: '[Mumuki] Erro com exercício %{title}'
227
230
  processing_your_solution: Estamos processando sua solução
228
- profile: Perfil
229
231
  profile_of: Perfil de %{username}
230
232
  programming_since: Sou programador
231
233
  progress: Progresso
@@ -1,5 +1,5 @@
1
1
  module Mumuki
2
2
  module Laboratory
3
- VERSION = '8.6.1'
3
+ VERSION = '9.0.0'
4
4
  end
5
5
  end
@@ -34,7 +34,7 @@ describe Api::OrganizationsController, type: :controller, organization_workspace
34
34
 
35
35
  context 'with wildcard permissions' do
36
36
  before { get :index }
37
- let(:api_client) { create :api_client, role: :janitor, grant: '*' }
37
+ let(:api_client) { create :api_client, role: :admin, grant: '*' }
38
38
 
39
39
  it { check_status! 200 }
40
40
 
@@ -42,7 +42,7 @@ describe Api::OrganizationsController, type: :controller, organization_workspace
42
42
  end
43
43
  context 'with non-wildcard permissions' do
44
44
  before { get :index }
45
- let(:api_client) { create :api_client, role: :janitor, grant: 'public/*:private/*' }
45
+ let(:api_client) { create :api_client, role: :admin, grant: 'public/*:private/*' }
46
46
 
47
47
  it { check_status! 200 }
48
48
 
@@ -54,14 +54,14 @@ describe Api::OrganizationsController, type: :controller, organization_workspace
54
54
  context 'with a public organization' do
55
55
  before { get :show, params: {id: 'public'} }
56
56
 
57
- context 'with a user without janitor permissions' do
57
+ context 'with a user without admin permissions' do
58
58
  let(:api_client) { create :api_client, role: :editor, grant: 'another_organization/*' }
59
59
 
60
60
  it { check_status! 403 }
61
61
  end
62
62
 
63
- context 'with a user with janitor' do
64
- let(:api_client) { create :api_client, role: :janitor, grant: 'public/*' }
63
+ context 'with a user with admin' do
64
+ let(:api_client) { create :api_client, role: :admin, grant: 'public/*' }
65
65
 
66
66
  it { check_status! 200 }
67
67
  end
@@ -70,7 +70,7 @@ describe Api::OrganizationsController, type: :controller, organization_workspace
70
70
  context 'with an organization that has a dot in its name' do
71
71
  before { get :show, params: {id: 'dot.org'} }
72
72
 
73
- let(:api_client) { create :api_client, role: :janitor, grant: 'dot.org/*' }
73
+ let(:api_client) { create :api_client, role: :admin, grant: 'dot.org/*' }
74
74
  it { check_status! 200 }
75
75
  end
76
76
 
@@ -84,7 +84,7 @@ describe Api::OrganizationsController, type: :controller, organization_workspace
84
84
  end
85
85
 
86
86
  context 'with a user with permissions' do
87
- let(:api_client) { create :api_client, role: :janitor, grant: 'private/*' }
87
+ let(:api_client) { create :api_client, role: :admin, grant: 'private/*' }
88
88
 
89
89
  it { check_status! 200 }
90
90
  it { expect(response.body).to json_like(private_organization.to_resource_h) }
@@ -181,7 +181,7 @@ describe Api::OrganizationsController, type: :controller, organization_workspace
181
181
  end
182
182
 
183
183
 
184
- context 'with not-janitor permissions' do
184
+ context 'with non-admin permissions' do
185
185
  let(:api_client) { create :api_client, role: :editor, grant: '*' }
186
186
 
187
187
  it { check_status! 403 }
@@ -228,7 +228,14 @@ describe Api::OrganizationsController, type: :controller, organization_workspace
228
228
  it { expect(updated_organizaton.contact_email).to eq 'second_email@gmail.com' }
229
229
  end
230
230
 
231
- context 'with not-janitor permissions' do
231
+ context 'with janitor permissions' do
232
+ let(:api_client) { create :api_client, role: :janitor, grant: 'existing-organization/*' }
233
+ before { put :update, params: {id: 'existing-organization', organization: update_json} }
234
+
235
+ it { check_status! 403 }
236
+ end
237
+
238
+ context 'with non-admin permissions' do
232
239
  let(:api_client) { create :api_client, role: :teacher, grant: 'existing-organization/*' }
233
240
  before { put :update, params: {id: 'existing-organization', organization: update_json} }
234
241