decidim-meetings 0.27.5 → 0.27.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/meetings/highlighted_meetings_for_component/show.erb +2 -2
  3. data/app/cells/decidim/meetings/meeting_s_cell.rb +1 -1
  4. data/app/controllers/decidim/meetings/widgets_controller.rb +11 -1
  5. data/app/helpers/decidim/meetings/directory/application_helper.rb +1 -1
  6. data/app/packs/src/decidim/meetings/poll.component.js +27 -0
  7. data/app/permissions/decidim/meetings/permissions.rb +10 -0
  8. data/app/presenters/decidim/meetings/admin_log/meeting_presenter.rb +0 -4
  9. data/app/presenters/decidim/meetings/admin_log/value_types/meeting_title_description_presenter.rb +1 -1
  10. data/app/services/decidim/meetings/close_meeting_reminder_generator.rb +11 -5
  11. data/app/views/decidim/meetings/admin/agenda/_form.html.erb +1 -1
  12. data/app/views/decidim/meetings/layouts/live_event.html.erb +1 -1
  13. data/app/views/decidim/meetings/meetings/_meeting_agenda.html.erb +2 -2
  14. data/app/views/decidim/meetings/meetings/show.html.erb +3 -1
  15. data/app/views/decidim/meetings/polls/answers/_multiple_option.html.erb +13 -9
  16. data/app/views/decidim/meetings/polls/answers/_single_option.html.erb +8 -8
  17. data/app/views/decidim/meetings/polls/questions/_published_question.html.erb +2 -2
  18. data/config/locales/ar.yml +0 -1
  19. data/config/locales/bg.yml +666 -0
  20. data/config/locales/ca.yml +4 -4
  21. data/config/locales/cs.yml +0 -1
  22. data/config/locales/de.yml +3 -3
  23. data/config/locales/el.yml +0 -1
  24. data/config/locales/es.yml +4 -4
  25. data/config/locales/fi-plain.yml +2 -0
  26. data/config/locales/fi.yml +3 -1
  27. data/config/locales/fr-CA.yml +2 -0
  28. data/config/locales/fr.yml +2 -0
  29. data/config/locales/gl.yml +0 -1
  30. data/config/locales/he-IL.yml +1 -0
  31. data/config/locales/hu.yml +4 -1
  32. data/config/locales/it.yml +0 -1
  33. data/config/locales/ja.yml +8 -1
  34. data/config/locales/lt.yml +0 -1
  35. data/config/locales/nl.yml +0 -1
  36. data/config/locales/no.yml +0 -1
  37. data/config/locales/pl.yml +103 -0
  38. data/config/locales/pt-BR.yml +50 -1
  39. data/config/locales/pt.yml +0 -1
  40. data/config/locales/ro-RO.yml +0 -1
  41. data/config/locales/sv.yml +1 -1
  42. data/config/locales/tr-TR.yml +3 -0
  43. data/config/locales/zh-TW.yml +0 -1
  44. data/decidim-meetings.gemspec +36 -0
  45. data/lib/decidim/meetings/engine.rb +1 -1
  46. data/lib/decidim/meetings/test/factories.rb +68 -30
  47. data/lib/decidim/meetings/version.rb +1 -1
  48. metadata +19 -19
  49. data/app/presenters/decidim/meetings/log/resource_presenter.rb +0 -18
  50. data/config/environment.rb +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a610ceae614ac794a5b7ea743fcbdcf71a0f2a70e8b559f6e57961afb5648db
4
- data.tar.gz: 40d10bb06adb06467f54953cae3c060e6388287b2e3191f9974cfa5dc4f9ee29
3
+ metadata.gz: 71a0790cb2d4d2270dc622fa73b690117680150c848a6262fddc39d9fa30437f
4
+ data.tar.gz: bf73625c7ea0b80d69f3313ea415eca7982e008f21e8b63060a8a8672f4e7737
5
5
  SHA512:
6
- metadata.gz: a27d0127cf7915042f66df45b51d8cc8dcb76adac2956ea18eaf8ccfba26b14676746f89c2f06b1e2967fa11682398d817a3c145a7aed5061fd0cfb63f7f1647
7
- data.tar.gz: 5b0601806650088310ee24494e5217d2733fe06d558fc0cf088237f3c4775d249c5ba3b01e4da3ff7e3659a4bed20b6be003d334e0382d9b4fecbbe1877632ad
6
+ metadata.gz: e1e5d4e38ec3c00cd02936c9fe02d3410ac3b5118a81988a8e26736a1bb2bda4a4cceb4d83a9d4fb90942a6a96078f2a2d0110b26ca536abf3dd89255bd96b33
7
+ data.tar.gz: 6c5039b5c1a953e2e77450f1817f1b1f942c68bd214a1d73e0fb60ae2aa9cd2abf8f280eb5182f47dfb984c8a222caefc2d7f7cb66b621b5677668865dc6c715
@@ -1,7 +1,7 @@
1
1
  <% if upcoming_meetings.any? %>
2
2
  <div class="section row collapse upcoming_meetings">
3
3
  <h3 class="section-heading">
4
- <%= translated_attribute(model.name) %> - <%= t("decidim.participatory_spaces.highlighted_meetings.upcoming_meetings") %>
4
+ <%= decidim_escape_translated(model.name) %> - <%= t("decidim.participatory_spaces.highlighted_meetings.upcoming_meetings") %>
5
5
  <a href="<%= main_component_path(model) %>" class="text-small"><%= t("decidim.participatory_spaces.highlighted_meetings.see_all", count: upcoming_meetings_count) %></a>
6
6
  </h3>
7
7
  <div class="card card--list">
@@ -18,7 +18,7 @@
18
18
  <% elsif past_meetings.any? %>
19
19
  <div class="section row collapse past_meetings">
20
20
  <h3 class="section-heading">
21
- <%= translated_attribute(model.name) %> - <%= t("decidim.participatory_spaces.highlighted_meetings.past_meetings") %> <a href="<%= main_component_path(model) %>" class="text-small"><%= t("decidim.participatory_spaces.highlighted_meetings.see_all", count: past_meetings_count) %></a>
21
+ <%= decidim_escape_translated(model.name) %> - <%= t("decidim.participatory_spaces.highlighted_meetings.past_meetings") %> <a href="<%= main_component_path(model) %>" class="text-small"><%= t("decidim.participatory_spaces.highlighted_meetings.see_all", count: past_meetings_count) %></a>
22
22
  </h3>
23
23
  <div class="card card--list">
24
24
  <% past_meetings.each do |meeting| %>
@@ -14,7 +14,7 @@ module Decidim
14
14
  end
15
15
 
16
16
  def participatory_space_title
17
- translated_attribute model.component.participatory_space.title
17
+ decidim_escape_translated model.component.participatory_space.title
18
18
  end
19
19
 
20
20
  def participatory_space_path
@@ -6,15 +6,25 @@ module Decidim
6
6
  helper MeetingsHelper
7
7
  helper Decidim::SanitizeHelper
8
8
 
9
+ def show
10
+ enforce_permission_to :embed, :meeting, meeting: model if model
11
+
12
+ super
13
+ end
14
+
9
15
  private
10
16
 
11
17
  def model
12
- @model ||= Meeting.where(component: params[:component_id]).find(params[:meeting_id])
18
+ @model ||= Meeting.except_withdrawn.published.not_hidden.where(component: current_component).find(params[:meeting_id])
13
19
  end
14
20
 
15
21
  def iframe_url
16
22
  @iframe_url ||= meeting_widget_url(model)
17
23
  end
24
+
25
+ def permission_class_chain
26
+ [Decidim::Meetings::Permissions]
27
+ end
18
28
  end
19
29
  end
20
30
  end
@@ -92,7 +92,7 @@ module Decidim
92
92
  key_point = current_participatory_space.class.name.gsub("::", "__") + current_participatory_space.id.to_s
93
93
 
94
94
  TreeNode.new(
95
- TreePoint.new(key_point, translated_attribute(current_participatory_space.title, current_organization)),
95
+ TreePoint.new(key_point, decidim_escape_translated(current_participatory_space.title)),
96
96
  categories_values
97
97
  )
98
98
  end
@@ -1,5 +1,8 @@
1
1
  /* eslint id-length: ["error", { "exceptions": ["$"] }] */
2
2
 
3
+ import createOptionAttachedInputs from "src/decidim/forms/option_attached_inputs.component"
4
+ import createMaxChoicesAlertComponent from "src/decidim/forms/max_choices_alert.component"
5
+
3
6
  /**
4
7
  * A plain Javascript component that handles questions from polls in meetings:
5
8
  * - fetches them via Ajax
@@ -75,6 +78,7 @@ export default class PollComponent {
75
78
  this._updateCounter();
76
79
  this._setQuestionsState(this.$element);
77
80
  this._pollQuestions();
81
+ this._addValidations();
78
82
  });
79
83
  }
80
84
 
@@ -163,4 +167,27 @@ export default class PollComponent {
163
167
  this.$counter.html(`(${questionsCount})`);
164
168
  }
165
169
  }
170
+
171
+ _addValidations() {
172
+ $(".js-radio-button-collection, .js-check-box-collection").each((idx, el) => {
173
+ createOptionAttachedInputs({
174
+ wrapperField: $(el),
175
+ controllerFieldSelector: "input[type=radio], input[type=checkbox]",
176
+ dependentInputSelector: "input[type=text], input[type=hidden]"
177
+ });
178
+ });
179
+
180
+ $.unique($(".js-check-box-collection").parents(".answer")).each((idx, el) => {
181
+ const maxChoices = $(el).data("max-choices");
182
+ if (maxChoices) {
183
+ createMaxChoicesAlertComponent({
184
+ wrapperField: $(el),
185
+ controllerFieldSelector: "input[type=checkbox]",
186
+ controllerCollectionSelector: ".js-check-box-collection",
187
+ alertElement: $(el).find(".max-choices-alert"),
188
+ maxChoices: maxChoices
189
+ });
190
+ }
191
+ });
192
+ }
166
193
  }
@@ -4,6 +4,7 @@ module Decidim
4
4
  module Meetings
5
5
  class Permissions < Decidim::DefaultPermissions
6
6
  def permissions
7
+ allow_embed_meeting?
7
8
  return permission_action unless user
8
9
 
9
10
  # Delegate the admin permission checks to the admin permissions class
@@ -57,6 +58,15 @@ module Decidim
57
58
  @question ||= context.fetch(:question, nil)
58
59
  end
59
60
 
61
+ # As this is a public action, we need to run this before other checks
62
+ def allow_embed_meeting?
63
+ return unless permission_action.action == :embed && permission_action.subject == :meeting && meeting
64
+ return disallow! if meeting.withdrawn?
65
+ return allow! if meeting.published?
66
+
67
+ disallow!
68
+ end
69
+
60
70
  def can_join_meeting?
61
71
  meeting.can_be_joined_by?(user) &&
62
72
  authorized?(:join, resource: meeting)
@@ -15,10 +15,6 @@ module Decidim
15
15
  class MeetingPresenter < Decidim::Log::BasePresenter
16
16
  private
17
17
 
18
- def resource_presenter
19
- @resource_presenter ||= Decidim::Meetings::Log::ResourcePresenter.new(action_log.resource, h, action_log.extra["resource"])
20
- end
21
-
22
18
  def diff_fields_mapping
23
19
  {
24
20
  address: :string,
@@ -10,7 +10,7 @@ module Decidim
10
10
  def present
11
11
  return unless value
12
12
 
13
- renderer = Decidim::ContentRenderers::HashtagRenderer.new(h.translated_attribute(value))
13
+ renderer = Decidim::ContentRenderers::HashtagRenderer.new(h.decidim_escape_translated(value))
14
14
  renderer.render(links: false).html_safe
15
15
  end
16
16
  end
@@ -38,11 +38,9 @@ module Decidim
38
38
 
39
39
  def send_reminders(component)
40
40
  intervals = Array(reminder_manifest.settings.attributes[:reminder_times].default)
41
- space_admins = Decidim::ParticipatoryProcessUserRole.where(decidim_participatory_process_id: component.participatory_space_id, role: "admin").collect(&:user)
42
- space_admins = (global_admins + space_admins).uniq
43
41
  intervals.each do |interval|
44
42
  finder_query(component.id, interval).find_each do |meeting|
45
- authors = meeting.official? ? space_admins : [meeting.author]
43
+ authors = meeting.official? ? space_admins(component) : [meeting.author]
46
44
  authors.each do |author|
47
45
  send_notif = author.notification_settings.fetch("close_meeting_reminder", "1")
48
46
  next unless send_notif == "1"
@@ -60,8 +58,16 @@ module Decidim
60
58
  end
61
59
  end
62
60
 
63
- def global_admins
64
- @global_admins ||= Decidim::User.where(admin: true).all
61
+ def space_admins(component)
62
+ @space_admins ||= begin
63
+ space_admins = if component.participatory_space.respond_to?(:user_roles)
64
+ component.participatory_space.user_roles(:admin).collect(&:user)
65
+ else
66
+ []
67
+ end
68
+ global_admins = component.organization.admins
69
+ (global_admins + space_admins).uniq
70
+ end
65
71
  end
66
72
  end
67
73
  end
@@ -3,7 +3,7 @@
3
3
  <h2 class="card-title">
4
4
  <div class="flex--sbc">
5
5
  <div class="grid-x align-middle">
6
- <u> <%= present(@meeting).title %> </u> &nbsp;<%= icon "arrow-right" %>&nbsp;<%= title %>
6
+ <u> <%= present(@meeting).title(html_escape: true) %> </u> &nbsp;<%= icon "arrow-right" %>&nbsp;<%= title %>
7
7
  </div>
8
8
  </div>
9
9
  </h2>
@@ -24,7 +24,7 @@
24
24
  <% end %>
25
25
 
26
26
  <div>
27
- <strong class="text-secondary"><%= current_organization.name %></strong> / <strong><%= present(meeting).title(links: true) %></strong>
27
+ <strong class="text-secondary"><%= current_organization.name %></strong> / <strong><%= present(meeting).title(links: true, html_escape: true) %></strong>
28
28
  </div>
29
29
 
30
30
  <div class="flex--cc">
@@ -11,7 +11,7 @@
11
11
  <span class="text-small"><%= display_duration_agenda_items(agenda_item.id, index, agenda_items_times) %></span>
12
12
  </h5>
13
13
  <hr class="reset m-none mb-s">
14
- <p><%= translated_attribute(agenda_item.description).html_safe %></p>
14
+ <p><%= decidim_sanitize_translated(agenda_item.description).html_safe %></p>
15
15
 
16
16
  <% if agenda_item.agenda_item_children.presence %>
17
17
  <% parent_start_time = agenda_items_times[index][:start_time] %>
@@ -22,7 +22,7 @@
22
22
  <strong><%= translated_attribute(agenda_item_child.title) %></strong>&nbsp;
23
23
  <span class="text-small"><%= display_duration_agenda_items(agenda_item_child.id, index_child, agenda_item_children_times) %></span>
24
24
  </h6>
25
- <p><%= translated_attribute(agenda_item_child.description).html_safe %></p>
25
+ <p><%= decidim_sanitize_translated(agenda_item_child.description).html_safe %></p>
26
26
  <% end %>
27
27
  <% end %>
28
28
  <% end %>
@@ -105,7 +105,9 @@ edit_link(
105
105
  <%= resource_version(meeting, versions_path: meeting_versions_path(meeting)) %>
106
106
  <%= cell "decidim/meetings/cancel_registration_meeting_button", meeting %>
107
107
  <%= render partial: "decidim/shared/share_modal" %>
108
- <%= embed_modal_for meeting_widget_url(meeting, format: :js) %>
108
+ <% if allowed_to? :embed, :meeting, meeting: @meeting %>
109
+ <%= embed_modal_for meeting_widget_url(meeting, format: :js) %>
110
+ <% end %>
109
111
  <%= render partial: "calendar_modal", locals: { ics_url: calendar_meeting_url(meeting), google_url: google_calendar_event_url(meeting) } %>
110
112
  </div>
111
113
  <div class="columns mediumlarge-8 mediumlarge-pull-4">
@@ -1,13 +1,17 @@
1
- <% question.answer_options.each_with_index do |answer_option, idx| %>
2
- <% choice = answer.choices.find { |choice| choice.decidim_answer_option_id == answer_option.id } if answer %>
1
+ <div class="answer-questionnaire__single-option js-check-box-collection">
2
+ <% question.answer_options.each_with_index do |answer_option, idx| %>
3
+ <% choice = answer.choices.find { |choice| choice.decidim_answer_option_id == answer_option.id } if answer %>
3
4
 
4
- <%= label_tag do %>
5
- <%= check_box_tag "answer[choices][#{idx}][body]",
6
- translated_attribute(answer_option.body),
7
- choice.present?, disabled: disabled %>
5
+ <div class="js-collection-input">
6
+ <%= label_tag do %>
7
+ <%= check_box_tag "answer[choices][#{idx}][body]",
8
+ translated_attribute(answer_option.body),
9
+ choice.present?, disabled: disabled %>
8
10
 
9
- <%= translated_attribute(answer_option.body) %>
11
+ <%= translated_attribute(answer_option.body) %>
10
12
 
11
- <%= hidden_field_tag "answer[choices][#{idx}][answer_option_id]", answer_option.id, disabled: disabled %>
13
+ <%= hidden_field_tag "answer[choices][#{idx}][answer_option_id]", answer_option.id, disabled: disabled %>
14
+ <% end %>
15
+ </div>
12
16
  <% end %>
13
- <% end %>
17
+ </div>
@@ -4,16 +4,16 @@
4
4
  <% choice_id = "#{field_id}_choices_#{idx}" %>
5
5
 
6
6
  <%= label_tag "#{choice_id}_body" do %>
7
- <%= radio_button_tag "answer[choices][#{idx}][body]",
8
- translated_attribute(answer_option.body),
9
- answer_option.id == choice.try(:decidim_answer_option_id),
10
- id: "#{choice_id}_body", disabled: disabled %>
7
+ <%= radio_button_tag "answer[choices][#{question.id}][body]",
8
+ translated_attribute(answer_option.body),
9
+ answer_option.id == choice.try(:decidim_answer_option_id),
10
+ id: "#{choice_id}_body", disabled: disabled %>
11
11
 
12
12
  <%= translated_attribute(answer_option.body) %>
13
13
 
14
- <%= hidden_field_tag "answer[choices][#{idx}][answer_option_id]",
15
- answer_option.id,
16
- id: "#{choice_id}_answer_option",
17
- disabled: disabled %>
14
+ <%= hidden_field_tag "answer[choices][#{question.id}][answer_option_id]",
15
+ answer_option.id,
16
+ id: "#{choice_id}_answer_option",
17
+ disabled: disabled %>
18
18
  <% end %>
19
19
  <% end %>
@@ -6,12 +6,12 @@
6
6
  <% @form = form || Decidim::Meetings::AnswerForm.new(question_id: question.id, current_user: current_user) %>
7
7
  <%= decidim_form_for(@form, url: meeting_polls_answers_path(meeting), method: :post, remote: true, html: { class: "form answer-questionnaire" }, data: { "safe-path" => meeting_live_event_path(meeting) }) do |form| %>
8
8
  <div class="row column answer question" data-max-choices="<%= question.max_choices %>">
9
+ <small class="form-error max-choices-alert"><%= t(".max_choices_alert") %></small>
10
+
9
11
  <%= render partial: "decidim/meetings/polls/answers/#{question.question_type}", locals: { answer: @form.answer, question: question, answer_form: form, disabled: question.answered_by?(current_user), field_id: question.id } %>
10
12
 
11
13
  <%= form.hidden_field :question_id %>
12
14
 
13
- <small class="form-error max-choices-alert"><%= t(".max_choices_alert") %></small>
14
-
15
15
  <% @form.errors.full_messages.each do |msg| %>
16
16
  <small class="form-error is-visible margin-top-1"><%= msg %></small>
17
17
  <% end %>
@@ -460,7 +460,6 @@ ar:
460
460
  new_meeting_at_html: "<span>اجتماع جديد في %{link}</span>"
461
461
  layouts:
462
462
  live_event:
463
- administrate: إدارة
464
463
  close: إغلاق
465
464
  questions: الأسئلة
466
465
  mailer: