mumuki-laboratory 9.20.0 → 9.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -0
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_discussion.scss +1 -3
- data/app/controllers/appendixes_controller.rb +7 -0
- data/app/controllers/application_controller.rb +6 -3
- data/app/controllers/complements_controller.rb +13 -0
- data/app/controllers/login_controller.rb +11 -3
- data/app/controllers/users_controller.rb +11 -4
- data/app/helpers/application_helper.rb +3 -1
- data/app/helpers/discussions_helper.rb +41 -26
- data/app/helpers/mailer_helper.rb +5 -0
- data/app/helpers/user_menu_helper.rb +7 -3
- data/app/mailers/application_mailer.rb +1 -0
- data/app/mailers/user_mailer.rb +6 -1
- data/app/views/book/show.html.erb +21 -18
- data/app/views/chapters/show.html.erb +1 -1
- data/app/views/discussions/_description_message.html.erb +6 -4
- data/app/views/discussions/_message.html.erb +10 -8
- data/app/views/discussions/show.html.erb +1 -1
- data/app/views/errors/forbidden.html.erb +1 -3
- data/app/views/errors/gone.html.erb +1 -2
- data/app/views/errors/not_found.html.erb +1 -1
- data/app/views/guides/_guide.html.erb +9 -5
- data/app/views/layouts/_discussions.html.erb +1 -3
- data/app/views/layouts/_organization_chooser.html.erb +2 -2
- data/app/views/layouts/_user_menu.html.erb +2 -0
- data/app/views/user_mailer/delete_account.html.erb +7 -0
- data/app/views/users/_user_delete_confirmation.erb +17 -0
- data/app/views/users/_user_delete_modal.html.erb +35 -0
- data/app/views/users/delete_account.html.erb +27 -0
- data/app/views/users/delete_confirmation_invalid.html.erb +22 -0
- data/app/views/users/delete_request.html.erb +1 -0
- data/config/routes.rb +6 -3
- data/lib/mumuki/laboratory/controllers/dynamic_errors.rb +6 -6
- data/lib/mumuki/laboratory/controllers/validate_access_mode.rb +5 -1
- data/lib/mumuki/laboratory/locales/en.yml +19 -2
- data/lib/mumuki/laboratory/locales/es-CL.yml +20 -3
- data/lib/mumuki/laboratory/locales/es.yml +21 -3
- data/lib/mumuki/laboratory/locales/pt.yml +20 -4
- data/lib/mumuki/laboratory/version.rb +1 -1
- data/spec/capybara_helper.rb +10 -10
- data/spec/controllers/discussions_messages_controller_spec.rb +5 -5
- data/spec/controllers/messages_controller_spec.rb +3 -3
- data/spec/controllers/users_controller_spec.rb +20 -1
- data/spec/dummy/config/environments/development.rb +8 -2
- data/spec/dummy/config/environments/test.rb +4 -1
- data/spec/dummy/db/schema.rb +5 -2
- data/spec/features/discussion_flow_spec.rb +2 -2
- data/spec/features/dynamic_exam_spec.rb +4 -2
- data/spec/features/guides_flow_spec.rb +29 -7
- data/spec/features/immersive_redirection_spec.rb +2 -2
- data/spec/features/not_found_public_flow_spec.rb +8 -1
- data/spec/features/profile_flow_spec.rb +3 -1
- data/spec/features/read_only_flow_spec.rb +72 -1
- data/spec/mailers/previews/user_mailer_preview.rb +4 -0
- data/spec/mailers/user_mailer_spec.rb +10 -3
- metadata +133 -108
- data/spec/features/disable_user_flow_spec.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9a44eb8a52ea3e076a0e6dd62ba634664458f2010b8df7d5a9d36f2dc20d9fe
|
4
|
+
data.tar.gz: 16995ef8fe178a5e8f4ba5d9454e55628f7a17de7c61a61625fae017eb6beecd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7b567eb9a6b759b11c2d471bed6a5221e0c1c0123e7513c70111df499169714ea05ae2c26d5c86eeaf3a3ac1f85d490b3a9d529717834c865b15bc777a3d9b0
|
7
|
+
data.tar.gz: f7c010004b5dff4fd790e89bb6701277e7d3c8bc7fbf12a7c411aecf0bb437f36defbcc911381140ac74d2f101be83859bda2ce15726fdd7b2d53b8c8e5c9d7a
|
data/README.md
CHANGED
@@ -205,6 +205,17 @@ o.reindex_usages!
|
|
205
205
|
|
206
206
|
Now you will be able to visit that guide at `http://localhost:3000/central/guides/#{slug}`
|
207
207
|
|
208
|
+
## Debugging email sender
|
209
|
+
|
210
|
+
The development environment is configured to "send" emails via `mailcatcher`, a mock server, if it is available. Run these commands to install and run it - and do it _before_ the emails are sent, so it can actually _catch_ them:
|
211
|
+
|
212
|
+
```bash
|
213
|
+
gem install mailcatcher
|
214
|
+
mailcatcher
|
215
|
+
```
|
216
|
+
|
217
|
+
Once up and running, go to http://localhost:1080/ to see which emails have been sent. Unfortunately, the developers recommend not to install it via Bundler, so it has to be done this way. :woman_shrugging:
|
218
|
+
|
208
219
|
## JavaScript API Docs
|
209
220
|
|
210
221
|
In order to be customized by runners, Laboratory exposes the following selectors and methods
|
@@ -318,7 +318,6 @@ $moderator-badge-color: #dd9900;
|
|
318
318
|
margin-bottom: 20px;
|
319
319
|
.discussion-message-bubble-header {
|
320
320
|
background-color: $mu-color-highlight-background;
|
321
|
-
height: 40px;
|
322
321
|
&:before {
|
323
322
|
position: absolute;
|
324
323
|
top: calc(20px - #{$discussion-message-arrow-size + 2px} / 2);
|
@@ -330,12 +329,11 @@ $moderator-badge-color: #dd9900;
|
|
330
329
|
}
|
331
330
|
.discussion-message-bubble-title {
|
332
331
|
padding: 5px 15px;
|
333
|
-
display:
|
332
|
+
display: flex;
|
334
333
|
.message-date {
|
335
334
|
font-size: 15px;
|
336
335
|
}
|
337
336
|
.actions {
|
338
|
-
float: right;
|
339
337
|
> a, .dropdown {
|
340
338
|
margin-left: 20px;
|
341
339
|
cursor: pointer;
|
@@ -7,7 +7,6 @@ class ApplicationController < ActionController::Base
|
|
7
7
|
include Mumukit::Login::AuthenticationHelpers
|
8
8
|
|
9
9
|
include Mumuki::Laboratory::Controllers::Authorization
|
10
|
-
include Mumuki::Laboratory::Controllers::Disabling
|
11
10
|
include Mumuki::Laboratory::Controllers::Notifications
|
12
11
|
include Mumuki::Laboratory::Controllers::DynamicErrors
|
13
12
|
include Mumuki::Laboratory::Controllers::EmbeddedMode
|
@@ -18,7 +17,6 @@ class ApplicationController < ActionController::Base
|
|
18
17
|
before_action :set_locale!
|
19
18
|
before_action :set_time_zone!
|
20
19
|
|
21
|
-
before_action :ensure_user_enabled!, if: :current_user?
|
22
20
|
before_action :redirect_to_proper_context!, if: :immersive_context_wrong?
|
23
21
|
|
24
22
|
before_action :authorize_if_private!
|
@@ -44,7 +42,8 @@ class ApplicationController < ActionController::Base
|
|
44
42
|
:theme_stylesheet_url,
|
45
43
|
:extension_javascript_url,
|
46
44
|
:current_immersive_path,
|
47
|
-
:current_access_mode
|
45
|
+
:current_access_mode,
|
46
|
+
:limited_query?
|
48
47
|
|
49
48
|
add_flash_types :info
|
50
49
|
|
@@ -170,4 +169,8 @@ class ApplicationController < ActionController::Base
|
|
170
169
|
current_user.restore_organization_progress!(Organization.current)
|
171
170
|
end
|
172
171
|
end
|
172
|
+
|
173
|
+
def limited_query?
|
174
|
+
params[:limit].present?
|
175
|
+
end
|
173
176
|
end
|
@@ -1,8 +1,21 @@
|
|
1
1
|
class ComplementsController < GuideContainerController
|
2
|
+
include Mumuki::Laboratory::Controllers::ValidateAccessMode
|
2
3
|
|
3
4
|
private
|
4
5
|
|
5
6
|
def subject
|
6
7
|
@complement ||= Complement.find_by(id: params[:id])
|
7
8
|
end
|
9
|
+
|
10
|
+
def authorization_minimum_role
|
11
|
+
:ex_student
|
12
|
+
end
|
13
|
+
|
14
|
+
def subject_container
|
15
|
+
subject.guide
|
16
|
+
end
|
17
|
+
|
18
|
+
def contentless_subject?
|
19
|
+
subject_container.exercises.empty?
|
20
|
+
end
|
8
21
|
end
|
@@ -2,9 +2,17 @@ class LoginController < ApplicationController
|
|
2
2
|
Mumukit::Login.configure_login_controller! self
|
3
3
|
|
4
4
|
skip_before_action :verify_authenticity_token, if: lambda { Rails.env.development? }
|
5
|
-
skip_before_action :validate_user_profile
|
6
|
-
|
7
|
-
|
5
|
+
skip_before_action :validate_user_profile!,
|
6
|
+
:validate_accepted_role_terms!,
|
7
|
+
:validate_active_organization!,
|
8
|
+
:redirect_to_proper_context!,
|
9
|
+
:ensure_restore_progress!,
|
10
|
+
:visit_organization!
|
11
|
+
|
12
|
+
def logout_current_user!
|
13
|
+
flash.keep
|
14
|
+
super
|
15
|
+
end
|
8
16
|
|
9
17
|
private
|
10
18
|
|
@@ -47,11 +47,18 @@ class UsersController < ApplicationController
|
|
47
47
|
@exam_authorization_requests ||= ExamAuthorizationRequest.where(user: current_user, organization: Organization.current)
|
48
48
|
end
|
49
49
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
50
|
+
def send_delete_confirmation_email
|
51
|
+
current_user.generate_delete_account_token!
|
52
|
+
UserMailer.delete_account(current_user).post!
|
53
|
+
redirect_to delete_request_user_path
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete_confirmation
|
57
|
+
return redirect_to delete_confirmation_invalid_user_path unless @user.delete_account_token_matches? params[:token]
|
58
|
+
|
59
|
+
@user.destroy!
|
53
60
|
|
54
|
-
redirect_to
|
61
|
+
redirect_to logout_path, notice: I18n.t(:user_deleted_successfully)
|
55
62
|
end
|
56
63
|
|
57
64
|
def permissible_params
|
@@ -17,7 +17,9 @@ module ApplicationHelper
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def paginate(object, options = {})
|
20
|
-
|
20
|
+
unless limited_query?
|
21
|
+
super(object, {theme: 'bootstrap-5', pagination_class: 'flex-wrap justify-content-center'}.merge(options))
|
22
|
+
end
|
21
23
|
end
|
22
24
|
|
23
25
|
def last_box_class(trailing_boxes)
|
@@ -38,14 +38,14 @@ module DiscussionsHelper
|
|
38
38
|
|
39
39
|
def solve_discussion_params_for(user)
|
40
40
|
if user&.moderator_here?
|
41
|
-
{status: :pending_review, sort: :responses_count_asc,
|
41
|
+
{status: :pending_review, sort: :responses_count_asc, requires_attention: true}
|
42
42
|
else
|
43
43
|
{status: :opened, sort: :responses_count_desc}
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
def default_discussions_params
|
48
|
-
{status: :solved, sort: :
|
48
|
+
{status: :solved, sort: :created_at_desc, recent: true, limit: 15}
|
49
49
|
end
|
50
50
|
|
51
51
|
def user_avatar(user, image_class='')
|
@@ -53,37 +53,37 @@ module DiscussionsHelper
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def forum_terms_link
|
56
|
-
|
56
|
+
<<~HTML.html_safe
|
57
57
|
<span>
|
58
58
|
#{ t(:forum_terms_link, terms_link: link_to_forum_terms).html_safe }
|
59
59
|
</span>
|
60
|
-
|
60
|
+
HTML
|
61
61
|
end
|
62
62
|
|
63
63
|
def discussion_messages_count(discussion)
|
64
|
-
|
64
|
+
<<~HTML.html_safe
|
65
65
|
<span class="discussion-messages-count">
|
66
66
|
#{fa_icon :comments, type: :regular, text: discussion.messages_count}
|
67
67
|
</span>
|
68
|
-
|
68
|
+
HTML
|
69
69
|
end
|
70
70
|
|
71
71
|
def discussion_validated_messages_count(discussion)
|
72
|
-
|
72
|
+
<<~HTML.html_safe
|
73
73
|
<span class="discussion-validated-messages-count">
|
74
74
|
#{fa_icon :comment, type: :regular}#{fa_icon :check, text: discussion.validated_messages_count}
|
75
75
|
</span>
|
76
|
-
|
76
|
+
HTML
|
77
77
|
end
|
78
78
|
|
79
79
|
def discussion_upvotes_icon(discussion)
|
80
80
|
if discussion.upvotes_count > 0
|
81
|
-
|
81
|
+
<<~HTML.html_safe
|
82
82
|
<span class="discussion-icon fa-stack fa-xs">
|
83
83
|
<i class="far fa-star fa-stack-2x"></i>
|
84
84
|
<i class="fas fa-stack-1x">#{discussion.upvotes_count}</i>
|
85
85
|
</span>
|
86
|
-
|
86
|
+
HTML
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
@@ -99,16 +99,21 @@ module DiscussionsHelper
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def new_discussion_link(teaser_text, link_text)
|
102
|
-
|
102
|
+
<<~HTML.html_safe
|
103
103
|
<h4>
|
104
104
|
<span>#{t(teaser_text)}</span>
|
105
105
|
#{link_to t(link_text), new_exercise_discussion_path(@debatable, anchor: 'new-discussion-description-container') }
|
106
106
|
</h4>
|
107
|
-
|
107
|
+
HTML
|
108
108
|
end
|
109
109
|
|
110
|
-
def
|
111
|
-
discussions.scoped_query_by(discussion_filter_params, excluded_params: [:status], excluded_methods: [:page])
|
110
|
+
def discussion_status_counts(discussions)
|
111
|
+
discussions.scoped_query_by(discussion_filter_params, excluded_params: [:status], excluded_methods: [:page])
|
112
|
+
.group(:status)
|
113
|
+
.reorder('')
|
114
|
+
.pluck(:status, 'count(*)')
|
115
|
+
.to_h
|
116
|
+
.transform_keys(&:to_sym)
|
112
117
|
end
|
113
118
|
|
114
119
|
def discussions_reset_query_link
|
@@ -122,11 +127,21 @@ module DiscussionsHelper
|
|
122
127
|
#TODO: this one uses a long method chain in order to take advantage of eager load
|
123
128
|
# Delegate it once again when polymorphic association is removed
|
124
129
|
def discussions_languages(discussions)
|
125
|
-
@languages ||= discussions.
|
130
|
+
@languages ||= discussions.distinct
|
131
|
+
.joins(:exercise)
|
132
|
+
.pluck('languages.name')
|
126
133
|
end
|
127
134
|
|
128
|
-
def
|
129
|
-
|
135
|
+
def discussion_status_filter_links(discussions)
|
136
|
+
status_counts = discussion_status_counts(discussions)
|
137
|
+
|
138
|
+
discussions_statuses.map do |status|
|
139
|
+
discussion_status_filter_link(status, status_counts)
|
140
|
+
end.compact.join("\n").html_safe
|
141
|
+
end
|
142
|
+
|
143
|
+
def discussion_status_filter_link(status, status_counts)
|
144
|
+
discussions_count = status_counts[status.to_sym] || 0
|
130
145
|
if status.should_be_shown?(discussions_count, current_user)
|
131
146
|
discussion_filter_item(:status, status) do
|
132
147
|
discussion_status_filter(status, discussions_count)
|
@@ -135,17 +150,17 @@ module DiscussionsHelper
|
|
135
150
|
end
|
136
151
|
|
137
152
|
def discussion_status_filter(status, discussions_count)
|
138
|
-
|
139
|
-
|
153
|
+
<<~HTML.html_safe
|
154
|
+
#{discussion_status_fa_icon(status)}
|
140
155
|
<span>
|
141
156
|
#{t("#{status}_count", count: discussions_count)}
|
142
157
|
</span>
|
143
|
-
|
158
|
+
HTML
|
144
159
|
end
|
145
160
|
|
146
161
|
def discussion_dropdown_filter(label, filters, can_select_all = false, &block)
|
147
162
|
if filters.present?
|
148
|
-
|
163
|
+
<<~HTML.html_safe
|
149
164
|
<div class="dropdown discussions-toolbar-filter">
|
150
165
|
<a id="dropdown-#{label}" data-bs-toggle="dropdown" role="menu">
|
151
166
|
#{t label} #{fa_icon :'caret-down', class: 'fa-xs'}
|
@@ -155,7 +170,7 @@ module DiscussionsHelper
|
|
155
170
|
#{discussion_filter_list(label, filters, &block)}
|
156
171
|
</ul>
|
157
172
|
</div>
|
158
|
-
|
173
|
+
HTML
|
159
174
|
end
|
160
175
|
end
|
161
176
|
|
@@ -244,7 +259,7 @@ module DiscussionsHelper
|
|
244
259
|
end
|
245
260
|
|
246
261
|
def discussion_delete_message_dropdown(discussion, message)
|
247
|
-
|
262
|
+
<<~HTML.html_safe
|
248
263
|
<span class="dropdown">
|
249
264
|
#{content_tag :span, fa_icon('trash-alt', type: :regular, class: 'fa-lg'), role: 'menu', 'data-bs-toggle': 'dropdown',
|
250
265
|
class: 'discussion-delete-message', id: 'deleteDiscussionDropdown'}
|
@@ -254,17 +269,17 @@ module DiscussionsHelper
|
|
254
269
|
#{discussion_delete_message_option discussion, message, :discloses_personal_information, 'user-tag'}
|
255
270
|
</ul>
|
256
271
|
</span>
|
257
|
-
|
272
|
+
HTML
|
258
273
|
end
|
259
274
|
|
260
275
|
def discussion_delete_message_option(discussion, message, motive, icon)
|
261
|
-
|
276
|
+
<<~HTML.html_safe
|
262
277
|
<li>
|
263
278
|
#{link_to fa_icon(icon, text: t("deletion_motive.#{motive}.present"), class: 'fa-fw fixed-icon'),
|
264
279
|
discussion_message_path(discussion, message, motive: motive), method: :delete, class: 'dropdown-item',
|
265
280
|
role: 'menuitem', data: { confirm: t(:are_you_sure, action: t(:destroy_message)) } }
|
266
281
|
</li>
|
267
|
-
|
282
|
+
HTML
|
268
283
|
end
|
269
284
|
|
270
285
|
def message_deleted_text(message)
|
@@ -35,11 +35,15 @@ module UserMenuHelper
|
|
35
35
|
user_menu_item t(:notifications), notifications_user_path, 'notifications'
|
36
36
|
end
|
37
37
|
|
38
|
+
def delete_account_user_menu_link
|
39
|
+
user_menu_item t(:delete_account), delete_account_user_path, 'delete_account', 'text-danger'
|
40
|
+
end
|
41
|
+
|
38
42
|
private
|
39
43
|
|
40
|
-
def user_menu_item(label, path, active_on)
|
41
|
-
|
42
|
-
content_tag :div, link_to(label, path, { class: link_klass }.compact), class: 'mu-user-menu-item'
|
44
|
+
def user_menu_item(label, path, active_on, link_klass = '')
|
45
|
+
active_klass = 'active' if action_name == active_on
|
46
|
+
content_tag :div, link_to(label, path, { class: "#{link_klass} #{active_klass}" }.compact), class: 'mu-user-menu-item'
|
43
47
|
end
|
44
48
|
|
45
49
|
def user_menu_header_icon
|
data/app/mailers/user_mailer.rb
CHANGED
@@ -22,6 +22,12 @@ class UserMailer < ApplicationMailer
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
def delete_account(user)
|
26
|
+
with_locale(user) do
|
27
|
+
build_email t(:delete_account_mumuki), 'delete_account'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
25
31
|
def certificate(certificate)
|
26
32
|
with_locale certificate.user, certificate.organization do
|
27
33
|
attachments[certificate.filename] = pdf_for(certificate)
|
@@ -39,7 +45,6 @@ class UserMailer < ApplicationMailer
|
|
39
45
|
|
40
46
|
def with_locale(user, organization = nil, &block)
|
41
47
|
@user = user
|
42
|
-
@unsubscribe_code = User.unsubscription_verifier.generate(user.id)
|
43
48
|
@organization = organization || user.last_organization
|
44
49
|
|
45
50
|
I18n.with_locale(@organization.locale, &block)
|
@@ -17,30 +17,33 @@
|
|
17
17
|
<% end %>
|
18
18
|
<% end %>
|
19
19
|
|
20
|
-
<%
|
21
|
-
|
22
|
-
|
20
|
+
<% unless @book.chapters.empty? %>
|
21
|
+
<% if show_content?(@book) %>
|
22
|
+
<h2><%= t(:chapters) %></h2>
|
23
|
+
<% end %>
|
23
24
|
|
24
|
-
|
25
|
+
<% @book.chapter_visibilities_in(current_workspace).each do |it, enabled| %>
|
25
26
|
|
26
|
-
|
27
|
+
<% next unless show_content?(it.topic) %>
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
<div class="chapter-container">
|
30
|
+
<div class="chapter <%= enabled ? '' : 'mu-locked' %>">
|
31
|
+
<h3><%= it.number %>. <%= link_to_path_element it, mode: :plain %></h3>
|
32
|
+
<div class="text-box" <%= 'aria-label=""' unless enabled %>>
|
33
|
+
<%= it.description_teaser_html %>
|
34
|
+
</div>
|
33
35
|
</div>
|
34
|
-
</div>
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
37
|
+
<% unless enabled %>
|
38
|
+
<div class="text-center mu-lock">
|
39
|
+
<i class="fas fa-lock fa-5x"></i>
|
40
|
+
<p><%= t :locked_content %></p>
|
41
|
+
</div>
|
42
|
+
<% end %>
|
43
|
+
</div>
|
44
|
+
<% end %>
|
43
45
|
<% end %>
|
46
|
+
|
44
47
|
<% if current_user? && @exams.present? %>
|
45
48
|
<h2><%= t(:exams) %></h2>
|
46
49
|
<% @exams.each_with_index do |it, index| %>
|
@@ -2,10 +2,12 @@
|
|
2
2
|
<div class="discussion-message-bubble">
|
3
3
|
<div class="discussion-message-bubble-header">
|
4
4
|
<div class="discussion-message-bubble-title">
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
<div class="flex-fill">
|
6
|
+
<%= linked_discussion_user_name(discussion.initiator) %>
|
7
|
+
<span class="message-date">
|
8
|
+
<%= friendly_time(discussion.created_at, :time_since) %>
|
9
|
+
</span>
|
10
|
+
</div>
|
9
11
|
</div>
|
10
12
|
</div>
|
11
13
|
<div class="discussion-message-bubble-content">
|
@@ -2,14 +2,16 @@
|
|
2
2
|
<div class="discussion-message-bubble">
|
3
3
|
<div class="discussion-message-bubble-header">
|
4
4
|
<div class="discussion-message-bubble-title">
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
<div class="flex-fill">
|
6
|
+
<%= linked_discussion_user_name user %>
|
7
|
+
<% if message.from_moderator? %>
|
8
|
+
<span class="moderator-badge"><%= t(:moderation) %></span>
|
9
|
+
<% end %>
|
10
|
+
<span class="message-date">
|
11
|
+
<%= friendly_time(message.created_at, :time_since) %>
|
12
|
+
</span>
|
13
|
+
</div>
|
14
|
+
<span class="actions flex-shrink-0">
|
13
15
|
<% if message.authorized?(current_user) && !message.deleted? %>
|
14
16
|
<% if current_user&.moderator_here? %>
|
15
17
|
<a class="discussion-message-approved <%= 'selected' if message.approved? %>"
|
@@ -26,7 +26,7 @@
|
|
26
26
|
<%= render partial: 'discussions/description_message', locals: { discussion: @discussion } %>
|
27
27
|
<% end %>
|
28
28
|
<% @discussion.visible_messages.each do |message| %>
|
29
|
-
<%= render partial: 'discussions/message', locals: { user: message.
|
29
|
+
<%= render partial: 'discussions/message', locals: { user: message.sender, message: message } %>
|
30
30
|
<% end %>
|
31
31
|
<% if @discussion.commentable_by?(current_user) %>
|
32
32
|
<hr class="message-divider">
|
@@ -8,12 +8,10 @@
|
|
8
8
|
<%= t(:error_description, error: link_to_status_codes(403)).html_safe %>
|
9
9
|
</p>
|
10
10
|
<p class="mu-error-explanation-line">
|
11
|
-
<%= Organization.current.explain_error(
|
11
|
+
<%= Organization.current.explain_error(error_code, explanation).html_safe %>
|
12
12
|
</p>
|
13
13
|
<p class="mu-error-contact-line mu-maybe">
|
14
14
|
<%= t(:contact_administrator, link: mail_to_administrator).html_safe %>
|
15
15
|
</p>
|
16
16
|
</div>
|
17
17
|
<% end %>
|
18
|
-
|
19
|
-
|
@@ -8,8 +8,7 @@
|
|
8
8
|
<%= t(:error_description, error: link_to_status_codes(410)).html_safe %>
|
9
9
|
</p>
|
10
10
|
<p class="mu-error-explanation-line">
|
11
|
-
<%= Organization.current.explain_error(
|
11
|
+
<%= Organization.current.explain_error(error_code, explanation).html_safe %>
|
12
12
|
</p>
|
13
13
|
</div>
|
14
14
|
<% end %>
|
15
|
-
|
@@ -8,7 +8,7 @@
|
|
8
8
|
<%= t(:error_description, error: link_to_error_404).html_safe %>
|
9
9
|
</p>
|
10
10
|
<p class="mu-error-explanation-line">
|
11
|
-
<%= Organization.current.explain_error(
|
11
|
+
<%= Organization.current.explain_error(:not_found, :not_found_explanation).html_safe %>
|
12
12
|
</p>
|
13
13
|
</div>
|
14
14
|
<% end %>
|
@@ -8,12 +8,16 @@
|
|
8
8
|
|
9
9
|
<%= yield if block_given? %>
|
10
10
|
|
11
|
-
|
12
|
-
<%= t :exercises %>
|
13
|
-
<%= restart_guide_link(@guide) if current_user && @stats.started? && @guide.resettable? %>
|
14
|
-
</h3>
|
11
|
+
<% unless @guide.exercises.empty? %>
|
15
12
|
|
16
|
-
|
13
|
+
<h3>
|
14
|
+
<%= t :exercises %>
|
15
|
+
<%= restart_guide_link(@guide) if current_user && @stats.started? && @guide.resettable? %>
|
16
|
+
</h3>
|
17
|
+
|
18
|
+
<%= render partial: 'layouts/progress_listing', locals: { guide: @guide } %>
|
19
|
+
|
20
|
+
<% end %>
|
17
21
|
|
18
22
|
<% if @stats&.done? %>
|
19
23
|
<div class="text-box">
|
@@ -3,9 +3,7 @@
|
|
3
3
|
<div class="discussions-toolbar">
|
4
4
|
<div class="discussions-toolbar-status">
|
5
5
|
<div class="d-none d-lg-block">
|
6
|
-
|
7
|
-
<%= discussion_status_filter_link(status, @discussions) %>
|
8
|
-
<% end %>
|
6
|
+
<%= discussion_status_filter_links(@discussions) %>
|
9
7
|
</div>
|
10
8
|
</div>
|
11
9
|
<div>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="modal fade mu-organization-chooser" id="
|
1
|
+
<div class="modal fade mu-organization-chooser" id="organization-chooser-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
2
2
|
<div class="modal-dialog">
|
3
3
|
<div class="modal-content">
|
4
4
|
<div class="modal-header">
|
@@ -14,7 +14,7 @@
|
|
14
14
|
</div>
|
15
15
|
</div>
|
16
16
|
<script>
|
17
|
-
$("#
|
17
|
+
$("#organization-chooser-modal").modal({
|
18
18
|
backdrop: 'static',
|
19
19
|
keyboard: false
|
20
20
|
});
|
@@ -12,6 +12,8 @@
|
|
12
12
|
<%= activity_user_menu_link %>
|
13
13
|
<%= certificates_user_menu_link %>
|
14
14
|
<%= exam_authorizations_user_menu_link %>
|
15
|
+
<%= user_menu_divider %>
|
16
|
+
<%= delete_account_user_menu_link %>
|
15
17
|
</div>
|
16
18
|
</div>
|
17
19
|
<div class="mu-user-menu-divider vertical d-none d-md-block"></div>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<%= render partial: 'user_mailer/mail_template', locals: {
|
2
|
+
title: t('mailer.title.delete_account'),
|
3
|
+
subtitle: t('mailer.subtitle.delete_account'),
|
4
|
+
text: t('mailer.text.delete_account').html_safe,
|
5
|
+
button: t('mailer.button.delete_account'),
|
6
|
+
url: delete_account_url_for(@user)
|
7
|
+
} %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<%= content_for :breadcrumbs do %>
|
2
|
+
<%= breadcrumbs @user %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<div class="row">
|
6
|
+
<div class="mu-inline-block-left">
|
7
|
+
<h1>
|
8
|
+
<%= t :email_sent %>
|
9
|
+
</h1>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<div class="row">
|
14
|
+
<div class="col-md-12">
|
15
|
+
<%= t :delete_account_confirmation_email_explain_html, user_email: @user.email, disable_email: Rails.configuration.disable_email %>
|
16
|
+
</div>
|
17
|
+
</div>
|