mumuki-laboratory 9.19.0 → 9.22.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/mumuki_laboratory/application/_layout.scss +0 -8
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_discussion.scss +1 -3
- data/app/assets/stylesheets/mumuki_laboratory/application/modules/_user_profile.scss +1 -9
- data/app/assets/stylesheets/mumuki_laboratory/application.scss +0 -1
- data/app/controllers/appendixes_controller.rb +7 -0
- data/app/controllers/application_controller.rb +6 -2
- data/app/controllers/complements_controller.rb +13 -0
- data/app/helpers/application_helper.rb +3 -1
- data/app/helpers/discussions_helper.rb +41 -26
- data/app/helpers/profile_helper.rb +1 -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/users/_basic_profile_fields.html.erb +20 -16
- data/app/views/users/_edit_user_form.html.erb +9 -7
- 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/es-CL.yml +1 -1
- data/lib/mumuki/laboratory/locales/es.yml +1 -1
- data/lib/mumuki/laboratory/version.rb +1 -1
- data/spec/controllers/discussions_messages_controller_spec.rb +5 -5
- data/spec/controllers/messages_controller_spec.rb +3 -3
- data/spec/dummy/db/schema.rb +4 -1
- data/spec/features/discussion_flow_spec.rb +2 -2
- data/spec/features/guides_flow_spec.rb +29 -7
- data/spec/features/immersive_redirection_spec.rb +1 -1
- 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
- metadata +107 -108
- data/app/assets/stylesheets/mumuki_laboratory/application/_alerts.scss +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 132cadbd6244acaece507d8f75d1613daf1c4f9f682b1b929d5c6468102a596b
|
4
|
+
data.tar.gz: 45ce5c37552fe64a9766ac4548f944f045f843177b843706277ca56f42125dbd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c6046c3ce7394386bc2f43d3e063c7eae999a70d96fde67243809e1e107d4f35638333cdf87e9af9aa5f3ae797585c82bd69a1ba293511842eb9bc4608c4518
|
7
|
+
data.tar.gz: fdeaa6997d54fb7dd6a75224c25a3a40f0d2e05414b934ff1fc3e5f60568c2de6ac32b39c6bcbb0f5b6e09cffc3b53b51e6cb8264e3ade7ee1060ccd05ae4252
|
@@ -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,6 +7,7 @@
|
|
7
7
|
|
8
8
|
.mu-profile-actions {
|
9
9
|
margin-left: auto;
|
10
|
+
text-align: center;
|
10
11
|
|
11
12
|
.btn {
|
12
13
|
width: 150px;
|
@@ -18,15 +19,6 @@
|
|
18
19
|
border-color: lighten($mu-color-complementary, 15%);
|
19
20
|
}
|
20
21
|
}
|
21
|
-
|
22
|
-
&.mobile {
|
23
|
-
text-align: center;
|
24
|
-
margin: 20px 5px -20px -10px;
|
25
|
-
|
26
|
-
.btn {
|
27
|
-
width: calc(50% - 20px);
|
28
|
-
}
|
29
|
-
}
|
30
22
|
}
|
31
23
|
|
32
24
|
.mu-profile-info {
|
@@ -44,7 +44,8 @@ class ApplicationController < ActionController::Base
|
|
44
44
|
:theme_stylesheet_url,
|
45
45
|
:extension_javascript_url,
|
46
46
|
:current_immersive_path,
|
47
|
-
:current_access_mode
|
47
|
+
:current_access_mode,
|
48
|
+
:limited_query?
|
48
49
|
|
49
50
|
add_flash_types :info
|
50
51
|
|
@@ -129,7 +130,6 @@ class ApplicationController < ActionController::Base
|
|
129
130
|
def validate_user_profile!
|
130
131
|
unless current_user.profile_completed?
|
131
132
|
save_location_before! :profile_completion
|
132
|
-
flash[:info] = I18n.t :please_fill_profile_data
|
133
133
|
redirect_to edit_user_path
|
134
134
|
end
|
135
135
|
end
|
@@ -171,4 +171,8 @@ class ApplicationController < ActionController::Base
|
|
171
171
|
current_user.restore_organization_progress!(Organization.current)
|
172
172
|
end
|
173
173
|
end
|
174
|
+
|
175
|
+
def limited_query?
|
176
|
+
params[:limit].present?
|
177
|
+
end
|
174
178
|
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
|
@@ -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)
|
@@ -4,7 +4,7 @@ module ProfileHelper
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def cancel_edit_profile_button
|
7
|
-
link_to t(:cancel), :user, class: 'btn btn-
|
7
|
+
link_to t(:cancel), :user, class: 'btn btn-outline-complementary' if current_user.profile_completed?
|
8
8
|
end
|
9
9
|
|
10
10
|
def save_edit_profile_button(form)
|
@@ -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,19 +1,23 @@
|
|
1
|
-
<
|
2
|
-
<
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
<
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
<
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
<div class="row">
|
2
|
+
<fieldset class="col-lg-6">
|
3
|
+
<div><%= form.label(t :first_name) %></div>
|
4
|
+
<div><%= form.text_field :first_name, required: true, class: 'form-control' %></div>
|
5
|
+
</fieldset>
|
6
|
+
<fieldset class="col-lg-6">
|
7
|
+
<div><%= form.label(t :last_name) %></div>
|
8
|
+
<div><%= form.text_field :last_name, required: true, class: 'form-control' %></div>
|
9
|
+
</fieldset>
|
10
|
+
</div>
|
11
|
+
<div class="row">
|
12
|
+
<fieldset class="col-lg-4">
|
13
|
+
<div><%= form.label(t :birthdate) %></div>
|
14
|
+
<div><%= form.date_field :birthdate, min: Date.new(1900), max: 3.years.ago.end_of_year, required: true, class: 'form-control' %></div>
|
15
|
+
</fieldset>
|
16
|
+
<fieldset class="col-lg-4 offset-lg-2">
|
17
|
+
<div><%= form.label(t :gender) %></div>
|
18
|
+
<div><%= form.select :gender, options_for_select(User.genders.map { |gender, _| [t(gender), gender] }, @user.gender), {}, required: true, class: 'form-control form-select' %></div>
|
19
|
+
</fieldset>
|
20
|
+
</div>
|
17
21
|
<fieldset>
|
18
22
|
<div><%= form.label(t :email) %></div>
|
19
23
|
<div><%= form.text_field :email, readonly: true, class: 'form-control' %></div>
|
@@ -1,22 +1,24 @@
|
|
1
1
|
<%= form_for :user, url: user_path, :html => { id: 'mu-user-form', class: 'mu-form' }, method: :put do |f| %>
|
2
2
|
<div class="mu-user-header">
|
3
3
|
<h1><%= t(:edit_profile) %></h1>
|
4
|
-
<div class="mu-profile-actions d-none d-md-block">
|
5
|
-
<%= cancel_edit_profile_button %>
|
6
|
-
<%= save_edit_profile_button f %>
|
7
|
-
</div>
|
8
4
|
</div>
|
9
5
|
<div class="row mu-tab-body">
|
10
|
-
<div class="col-md-6 col-lg-4 mu-user-avatar-container">
|
6
|
+
<div class="col-md-6 col-lg-4 mu-user-avatar-container mb-3">
|
11
7
|
<%= profile_picture_for(@user, id: 'mu-user-avatar', class: 'mu-user-avatar') %>
|
12
8
|
<button class="fas fa-pencil-alt fa-2x btn mu-edit-avatar" type="button" data-bs-toggle="modal" data-bs-target="#mu-avatar-picker" tabindex="0"></button>
|
13
9
|
</div>
|
14
|
-
<div class="col-md-6 col-lg-8">
|
10
|
+
<div class="col-md-6 col-lg-8 mb-4">
|
11
|
+
<% unless current_user.profile_completed? %>
|
12
|
+
<div class="alert alert-info alert-dismissible fade show" role="alert">
|
13
|
+
<%= fa_icon 'info-circle', class: 'fa-lg me-2 align-middle', text: t(:please_fill_profile_data) %>
|
14
|
+
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
15
|
+
</div>
|
16
|
+
<% end %>
|
15
17
|
<%= render partial: 'profile_fields', locals: {form: f} %>
|
16
18
|
<%= render partial: 'layouts/terms_acceptance_disclaimer', locals: {user: @user} %>
|
17
19
|
</div>
|
18
20
|
</div>
|
19
|
-
<div class="mu-profile-actions
|
21
|
+
<div class="mu-profile-actions">
|
20
22
|
<%= cancel_edit_profile_button %>
|
21
23
|
<%= save_edit_profile_button f %>
|
22
24
|
</div>
|
@@ -41,27 +41,27 @@ module Mumuki::Laboratory::Controllers::DynamicErrors
|
|
41
41
|
def forbidden
|
42
42
|
message = "The operation on organization #{Organization.current} was forbidden to user #{current_user.uid} with permissions #{current_user.permissions}"
|
43
43
|
Rails.logger.info message
|
44
|
-
render_error 'forbidden', 403, locals: { explanation: :forbidden_explanation }, error_message: message
|
44
|
+
render_error 'forbidden', 403, locals: { error_code: :forbidden, explanation: :forbidden_explanation }, error_message: message
|
45
45
|
end
|
46
46
|
|
47
47
|
def disabled
|
48
|
-
render_error 'forbidden', 403, locals: { explanation: :disabled_explanation }
|
48
|
+
render_error 'forbidden', 403, locals: { error_code: :disabled, explanation: :disabled_explanation }
|
49
49
|
end
|
50
50
|
|
51
51
|
def blocked_forum
|
52
|
-
render_error 'forbidden', 403, locals: { explanation: :blocked_forum_explanation }
|
52
|
+
render_error 'forbidden', 403, locals: { error_code: :blocked_forum, explanation: :blocked_forum_explanation }
|
53
53
|
end
|
54
54
|
|
55
55
|
def gone
|
56
|
-
render_error 'gone', 410, locals: { explanation: :gone_explanation }
|
56
|
+
render_error 'gone', 410, locals: { error_code: :gone, explanation: :gone_explanation }
|
57
57
|
end
|
58
58
|
|
59
59
|
def unprepared_organization
|
60
|
-
render_error 'forbidden', 403, locals: { explanation: :unprepared_organization_explanation }
|
60
|
+
render_error 'forbidden', 403, locals: { error_code: :unprepared_organization, explanation: :unprepared_organization_explanation }
|
61
61
|
end
|
62
62
|
|
63
63
|
def disabled_organization
|
64
|
-
render_error 'gone', 410, locals: { explanation: :disabled_organization_explanation }
|
64
|
+
render_error 'gone', 410, locals: { error_code: :disabled_organization, explanation: :disabled_organization_explanation }
|
65
65
|
end
|
66
66
|
|
67
67
|
def render_error(template, status, options={})
|