decidim-meetings 0.29.2 → 0.30.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/meetings/cancel_registration_meeting_button/cancelation_modal.erb +1 -1
  3. data/app/cells/decidim/meetings/cancel_registration_meeting_button/show.erb +3 -1
  4. data/app/cells/decidim/meetings/cancel_registration_meeting_button_cell.rb +1 -1
  5. data/app/cells/decidim/meetings/dates_and_map/show.erb +1 -1
  6. data/app/cells/decidim/meetings/highlighted_meetings_for_component/show.erb +1 -1
  7. data/app/cells/decidim/meetings/join_meeting_button/show.erb +5 -2
  8. data/app/cells/decidim/meetings/meeting_card_metadata_cell.rb +3 -3
  9. data/app/cells/decidim/meetings/meeting_l_cell.rb +12 -0
  10. data/app/commands/decidim/meetings/admin/copy_meeting.rb +1 -2
  11. data/app/commands/decidim/meetings/admin/create_meeting.rb +8 -2
  12. data/app/commands/decidim/meetings/admin/update_meeting.rb +8 -2
  13. data/app/commands/decidim/meetings/create_meeting.rb +2 -2
  14. data/app/commands/decidim/meetings/update_meeting.rb +2 -3
  15. data/app/controllers/concerns/decidim/meetings/admin/filterable.rb +9 -5
  16. data/app/controllers/concerns/decidim/meetings/component_filterable.rb +1 -2
  17. data/app/controllers/decidim/meetings/admin/meetings_controller.rb +14 -22
  18. data/app/controllers/decidim/meetings/admin/registration_form_controller.rb +8 -0
  19. data/app/controllers/decidim/meetings/directory/meetings_controller.rb +2 -4
  20. data/app/controllers/decidim/meetings/meetings_controller.rb +40 -6
  21. data/app/forms/decidim/meetings/admin/meeting_form.rb +16 -30
  22. data/app/forms/decidim/meetings/base_meeting_form.rb +6 -0
  23. data/app/forms/decidim/meetings/meeting_form.rb +2 -30
  24. data/app/helpers/decidim/meetings/admin/application_helper.rb +11 -1
  25. data/app/helpers/decidim/meetings/application_helper.rb +35 -1
  26. data/app/helpers/decidim/meetings/directory/application_helper.rb +9 -48
  27. data/app/helpers/decidim/meetings/meetings_helper.rb +5 -0
  28. data/app/models/decidim/meetings/invite.rb +10 -0
  29. data/app/models/decidim/meetings/meeting.rb +23 -1
  30. data/app/models/decidim/meetings/meeting_link.rb +25 -0
  31. data/app/packs/entrypoints/decidim_meetings_admin.js +1 -0
  32. data/app/packs/src/decidim/meetings/admin/meetings_components_form.js +77 -0
  33. data/app/packs/src/decidim/meetings/admin/meetings_form.js +8 -0
  34. data/app/permissions/decidim/meetings/admin/permissions.rb +1 -1
  35. data/app/permissions/decidim/meetings/permissions.rb +13 -9
  36. data/app/presenters/decidim/meetings/admin_log/meeting_presenter.rb +1 -1
  37. data/app/presenters/decidim/meetings/meeting_presenter.rb +13 -1
  38. data/app/queries/decidim/meetings/filtered_meetings.rb +2 -2
  39. data/app/queries/decidim/meetings/metrics/meeting_followers_metric_measure.rb +2 -2
  40. data/app/queries/decidim/meetings/metrics/meetings_metric_manage.rb +6 -6
  41. data/app/serializers/decidim/meetings/base_download_your_data_serializer.rb +32 -0
  42. data/app/serializers/decidim/meetings/download_your_data_invite_serializer.rb +6 -26
  43. data/app/serializers/decidim/meetings/download_your_data_meeting_serializer.rb +15 -0
  44. data/app/serializers/decidim/meetings/download_your_data_registration_serializer.rb +6 -24
  45. data/app/views/decidim/meetings/admin/meetings/_component.html.erb +15 -0
  46. data/app/views/decidim/meetings/admin/meetings/_form.html.erb +7 -9
  47. data/app/views/decidim/meetings/admin/meetings/_linked_spaces.html.erb +53 -0
  48. data/app/views/decidim/meetings/admin/meetings/_meeting-tr.html.erb +42 -0
  49. data/app/views/decidim/meetings/admin/meetings/_meeting_actions.html.erb +70 -0
  50. data/app/views/decidim/meetings/admin/meetings/_meetings-thead.html.erb +26 -0
  51. data/app/views/decidim/meetings/admin/meetings/index.html.erb +16 -142
  52. data/app/views/decidim/meetings/admin/meetings/manage_trash.html.erb +23 -0
  53. data/app/views/decidim/meetings/admin/registration_form/edit_questions.html.erb +44 -0
  54. data/app/views/decidim/meetings/admin/registrations/edit.html.erb +1 -0
  55. data/app/views/decidim/meetings/directory/meetings/index.html.erb +1 -2
  56. data/app/views/decidim/meetings/live_events/show.html.erb +5 -5
  57. data/app/views/decidim/meetings/meetings/_form.html.erb +4 -8
  58. data/app/views/decidim/meetings/meetings/_meeting.html.erb +51 -26
  59. data/app/views/decidim/meetings/meetings/_meeting_actions.html.erb +34 -0
  60. data/app/views/decidim/meetings/meetings/_meeting_aside.html.erb +20 -59
  61. data/app/views/decidim/meetings/meetings/_meeting_poll_actions.html.erb +2 -5
  62. data/app/views/decidim/meetings/meetings/_schema_org_event_meeting.html.erb +3 -0
  63. data/app/views/decidim/meetings/meetings/index.html.erb +10 -2
  64. data/app/views/decidim/meetings/meetings/show.html.erb +5 -5
  65. data/app/views/decidim/meetings/polls/answers/index.html.erb +5 -5
  66. data/app/views/decidim/meetings/shared/_filters.html.erb +1 -13
  67. data/app/views/decidim/meetings/shared/_index.html.erb +1 -1
  68. data/app/views/decidim/meetings/shared/_index.js.erb +3 -2
  69. data/app/views/decidim/meetings/shared/_meetings_aside.html.erb +2 -2
  70. data/app/views/decidim/participatory_spaces/_conference_venues.html.erb +1 -1
  71. data/config/locales/ar.yml +17 -17
  72. data/config/locales/bg.yml +5 -25
  73. data/config/locales/ca.yml +137 -25
  74. data/config/locales/cs.yml +138 -28
  75. data/config/locales/de.yml +106 -26
  76. data/config/locales/el.yml +1 -22
  77. data/config/locales/en.yml +133 -21
  78. data/config/locales/es-MX.yml +137 -25
  79. data/config/locales/es-PY.yml +137 -25
  80. data/config/locales/es.yml +137 -25
  81. data/config/locales/eu.yml +138 -26
  82. data/config/locales/fi-plain.yml +138 -26
  83. data/config/locales/fi.yml +138 -26
  84. data/config/locales/fr-CA.yml +79 -26
  85. data/config/locales/fr.yml +79 -26
  86. data/config/locales/ga-IE.yml +0 -13
  87. data/config/locales/gl.yml +1 -12
  88. data/config/locales/hu.yml +1 -19
  89. data/config/locales/id-ID.yml +1 -13
  90. data/config/locales/is-IS.yml +0 -12
  91. data/config/locales/it.yml +1 -17
  92. data/config/locales/ja.yml +95 -25
  93. data/config/locales/lb.yml +0 -11
  94. data/config/locales/lt.yml +1 -23
  95. data/config/locales/lv.yml +1 -13
  96. data/config/locales/nl.yml +1 -17
  97. data/config/locales/no.yml +1 -16
  98. data/config/locales/pl.yml +5 -21
  99. data/config/locales/pt-BR.yml +1 -21
  100. data/config/locales/pt.yml +1 -17
  101. data/config/locales/ro-RO.yml +30 -17
  102. data/config/locales/ru.yml +1 -13
  103. data/config/locales/sk.yml +1 -13
  104. data/config/locales/sv.yml +74 -26
  105. data/config/locales/tr-TR.yml +1 -19
  106. data/config/locales/uk.yml +0 -12
  107. data/config/locales/zh-CN.yml +1 -18
  108. data/config/locales/zh-TW.yml +1 -21
  109. data/db/migrate/20181107175558_add_questionnaire_to_existing_meetings.rb +1 -1
  110. data/db/migrate/20200827153856_add_commentable_counter_cache_to_meetings.rb +1 -1
  111. data/db/migrate/20201016065302_fix_meetings_registration_terms.rb +1 -1
  112. data/db/migrate/20210310120731_add_followable_counter_cache_to_meetings.rb +1 -1
  113. data/db/migrate/20240712104245_create_decidim_meetings_meeting_link.rb +12 -0
  114. data/db/migrate/20240828103603_add_deleted_at_to_decidim_meetings_meetings.rb +8 -0
  115. data/decidim-meetings.gemspec +1 -1
  116. data/lib/decidim/api/agenda_item_type.rb +6 -7
  117. data/lib/decidim/api/agenda_type.rb +3 -4
  118. data/lib/decidim/api/meeting_type.rb +33 -41
  119. data/lib/decidim/api/meetings_type.rb +4 -5
  120. data/lib/decidim/api/service_type.rb +1 -1
  121. data/lib/decidim/meetings/admin_engine.rb +9 -1
  122. data/lib/decidim/meetings/component.rb +14 -4
  123. data/lib/decidim/meetings/download_your_data_user_answers_serializer.rb +13 -7
  124. data/lib/decidim/meetings/meeting_serializer.rb +70 -59
  125. data/lib/decidim/meetings/schema_org_event_meeting_serializer.rb +151 -0
  126. data/lib/decidim/meetings/seeds.rb +2 -4
  127. data/lib/decidim/meetings/test/factories.rb +8 -0
  128. data/lib/decidim/meetings/test/translated_event.rb +3 -3
  129. data/lib/decidim/meetings/version.rb +1 -1
  130. data/lib/decidim/meetings.rb +1 -0
  131. metadata +32 -21
  132. data/app/cells/decidim/meetings/meetings_map/show.erb +0 -16
  133. data/app/cells/decidim/meetings/meetings_map_cell.rb +0 -32
  134. data/app/commands/decidim/meetings/admin/destroy_meeting.rb +0 -21
  135. data/app/helpers/decidim/meetings/map_helper.rb +0 -21
  136. data/app/views/decidim/meetings/meetings/_actions.html.erb +0 -6
@@ -7,7 +7,6 @@ module Decidim
7
7
  module ApplicationHelper
8
8
  include PaginateHelper
9
9
  include Decidim::MapHelper
10
- include Decidim::Meetings::MapHelper
11
10
  include Decidim::Comments::CommentsHelper
12
11
  include Decidim::SanitizeHelper
13
12
  include Decidim::CheckBoxesTreeHelper
@@ -39,6 +38,41 @@ module Decidim
39
38
  flat_filter_values(:all, :upcoming, :past, scope: "decidim.meetings.meetings.filters.date_values")
40
39
  end
41
40
 
41
+ # rubocop:disable Metrics/ParameterLists
42
+ # rubocop:disable Metrics/CyclomaticComplexity
43
+ def filter_sections(date: false, type: false, origin: false, taxonomies: false, space_type: false, activity: false)
44
+ @filter_sections ||= begin
45
+ items = []
46
+ if date
47
+ items.append(method: :with_any_date, collection: filter_date_values, label: t("decidim.meetings.meetings.filters.date"), id: "date",
48
+ type: :radio_buttons)
49
+ end
50
+ items.append(method: :with_any_type, collection: filter_type_values, label: t("decidim.meetings.meetings.filters.type"), id: "type") if type
51
+ if taxonomies
52
+ available_taxonomy_filters.each do |taxonomy_filter|
53
+ items.append(method: "with_any_taxonomies[#{taxonomy_filter.root_taxonomy_id}]",
54
+ collection: filter_taxonomy_values_for(taxonomy_filter),
55
+ label: decidim_sanitize_translated(taxonomy_filter.name),
56
+ id: "taxonomy-#{taxonomy_filter.root_taxonomy_id}")
57
+ end
58
+ end
59
+ items.append(method: :with_any_origin, collection: filter_origin_values, label: t("decidim.meetings.meetings.filters.origin"), id: "origin") if origin
60
+ if space_type
61
+ items.append(method: :with_any_space, collection: directory_meeting_spaces_values, label: t("decidim.meetings.directory.meetings.index.space_type"),
62
+ id: "space_type")
63
+ end
64
+ if activity
65
+ items.append(method: :activity, collection: activity_filter_values, label: t("decidim.meetings.meetings.filters.activity"), id: "activity",
66
+ type: :radio_buttons)
67
+ end
68
+ items.reject { |item| item[:collection].blank? }
69
+ end
70
+ end
71
+ # rubocop:enable Metrics/ParameterLists
72
+ # rubocop:enable Metrics/CyclomaticComplexity
73
+
74
+ delegate :available_taxonomy_filters, to: :current_component
75
+
42
76
  # Options to filter meetings by activity.
43
77
  def activity_filter_values
44
78
  flat_filter_values(:all, :my_meetings, scope: "decidim.meetings.meetings.filters")
@@ -8,7 +8,6 @@ module Decidim
8
8
  module ApplicationHelper
9
9
  include PaginateHelper
10
10
  include Decidim::MapHelper
11
- include Decidim::Meetings::MapHelper
12
11
  include Decidim::Meetings::MeetingsHelper
13
12
  include Decidim::Comments::CommentsHelper
14
13
  include Decidim::SanitizeHelper
@@ -27,6 +26,15 @@ module Decidim
27
26
  )
28
27
  end
29
28
 
29
+ def available_taxonomy_filters
30
+ @available_taxonomy_filters ||= begin
31
+ participatory_spaces = current_organization.public_participatory_spaces
32
+ components = Decidim::Component.where(manifest_name: "meetings", participatory_space: participatory_spaces)
33
+ filter_ids = components.map(&:settings).pluck(:taxonomy_filters).flatten.compact
34
+ Decidim::TaxonomyFilter.for(current_organization).where(id: filter_ids)
35
+ end
36
+ end
37
+
30
38
  def filter_date_values
31
39
  %w(all upcoming past).map { |k| [k, t(k, scope: "decidim.meetings.meetings.filters.date_values")] }
32
40
  end
@@ -43,57 +51,10 @@ module Decidim
43
51
  filter_tree_from_array(spaces)
44
52
  end
45
53
 
46
- def directory_filter_categories_values
47
- participatory_spaces = current_organization.public_participatory_spaces
48
- list_of_ps = participatory_spaces.flat_map do |current_participatory_space|
49
- next unless current_participatory_space.respond_to?(:categories)
50
-
51
- sorted_main_categories = current_participatory_space.categories.first_class.includes(:subcategories).sort_by do |category|
52
- [category.weight, translated_attribute(category.name, current_organization)]
53
- end
54
-
55
- categories_values = categories_values(sorted_main_categories)
56
-
57
- next if categories_values.empty?
58
-
59
- key_point = current_participatory_space.class.name.gsub("::", "__") + current_participatory_space.id.to_s
60
-
61
- TreeNode.new(
62
- TreePoint.new(key_point, translated_attribute(current_participatory_space.title, current_organization)),
63
- categories_values
64
- )
65
- end
66
-
67
- list_of_ps.compact!
68
- TreeNode.new(
69
- TreePoint.new("", t("decidim.meetings.application_helper.filter_category_values.all")),
70
- list_of_ps
71
- )
72
- end
73
-
74
54
  # Options to filter meetings by activity.
75
55
  def activity_filter_values
76
56
  %w(all my_meetings).map { |k| [k, t(k, scope: "decidim.meetings.meetings.filters")] }
77
57
  end
78
-
79
- protected
80
-
81
- def categories_values(sorted_main_categories)
82
- sorted_main_categories.flat_map do |category|
83
- sorted_descendant_categories = category.descendants.includes(:subcategories).sort_by do |subcategory|
84
- [subcategory.weight, translated_attribute(subcategory.name, current_organization)]
85
- end
86
-
87
- subcategories = sorted_descendant_categories.flat_map do |subcategory|
88
- TreePoint.new(subcategory.id.to_s, translated_attribute(subcategory.name, current_organization))
89
- end
90
-
91
- TreeNode.new(
92
- TreePoint.new(category.id.to_s, translated_attribute(category.name, current_organization)),
93
- subcategories
94
- )
95
- end
96
- end
97
58
  end
98
59
  end
99
60
  end
@@ -142,6 +142,11 @@ module Decidim
142
142
  base_url = "https://calendar.google.com/calendar/u/0/r/eventedit"
143
143
  "#{base_url}?#{params.to_param}"
144
144
  end
145
+
146
+ def render_schema_org_event_meeting(meeting)
147
+ exported_meeting = Decidim::Exporters::JSON.new([meeting], Decidim::Meetings::SchemaOrgEventMeetingSerializer).export.read
148
+ JSON.pretty_generate(JSON.parse(exported_meeting).first)
149
+ end
145
150
  end
146
151
  end
147
152
  end
@@ -33,6 +33,16 @@ module Decidim
33
33
  update!(rejected_at: Time.current, accepted_at: nil)
34
34
  end
35
35
  alias decline! reject!
36
+
37
+ def self.ransackable_attributes(auth_object = nil)
38
+ return [] unless auth_object&.admin?
39
+
40
+ %w(accepted_at rejected_at sent_at)
41
+ end
42
+
43
+ def self.ransackable_associations(_auth_object = nil)
44
+ %w(user)
45
+ end
36
46
  end
37
47
  end
38
48
  end
@@ -12,12 +12,14 @@ module Decidim
12
12
  include Decidim::HasReference
13
13
  include Decidim::ScopableResource
14
14
  include Decidim::HasCategory
15
+ include Decidim::Taxonomizable
15
16
  include Decidim::Followable
16
17
  include Decidim::Comments::CommentableWithComponent
17
18
  include Decidim::Comments::HasAvailabilityAttributes
18
19
  include Decidim::Searchable
19
20
  include Decidim::Traceable
20
21
  include Decidim::Loggable
22
+ include Decidim::DownloadYourData
21
23
  include Decidim::Forms::HasQuestionnaire
22
24
  include Decidim::Paddable
23
25
  include Decidim::ActsAsAuthor
@@ -26,6 +28,7 @@ module Decidim
26
28
  include Decidim::TranslatableResource
27
29
  include Decidim::Publicable
28
30
  include Decidim::FilterableResource
31
+ include Decidim::SoftDeletable
29
32
 
30
33
  TYPE_OF_MEETING = { in_person: 0, online: 10, hybrid: 20 }.freeze
31
34
  REGISTRATION_TYPES = { registration_disabled: 0, on_this_platform: 10, on_different_platform: 20 }.freeze
@@ -45,6 +48,8 @@ module Decidim
45
48
  foreign_key: :decidim_user_id,
46
49
  source: :user
47
50
  )
51
+ has_many :meeting_links, dependent: :destroy, class_name: "Decidim::Meetings::MeetingLink", foreign_key: "decidim_meeting_id"
52
+ has_many :components, through: :meeting_links, class_name: "Decidim::Component", foreign_key: "decidim_component_id"
48
53
 
49
54
  enum iframe_access_level: [:all, :signed_in, :registered], _prefix: true
50
55
  enum iframe_embed_type: [:none, :embed_in_meeting_page, :open_in_live_event_page, :open_in_new_tab], _prefix: true
@@ -57,6 +62,7 @@ module Decidim
57
62
 
58
63
  geocoded_by :address
59
64
 
65
+ scope :closed, -> { where.not(closed_at: nil) }
60
66
  scope :published, -> { where.not(published_at: nil) }
61
67
  scope :past, -> { where(arel_table[:end_time].lteq(Time.current)) }
62
68
  scope :upcoming, -> { where(arel_table[:end_time].gteq(Time.current)) }
@@ -151,6 +157,10 @@ module Decidim
151
157
  # we create a salt for the meeting only on new meetings to prevent changing old IDs for existing (Ether)PADs
152
158
  before_create :set_default_salt
153
159
 
160
+ def self.export_serializer
161
+ Decidim::Meetings::DownloadYourDataMeetingSerializer
162
+ end
163
+
154
164
  def self.participants_iframe_embed_types
155
165
  iframe_embed_types.except(:open_in_live_event_page)
156
166
  end
@@ -370,7 +380,19 @@ module Decidim
370
380
  end
371
381
 
372
382
  def self.ransackable_scopes(_auth_object = nil)
373
- [:with_any_type, :with_any_date, :with_any_space, :with_any_origin, :with_any_scope, :with_any_category, :with_any_global_category]
383
+ [:with_any_type, :with_any_date, :with_any_space, :with_any_origin, :with_any_taxonomies, :with_any_global_category]
384
+ end
385
+
386
+ def self.ransackable_attributes(auth_object = nil)
387
+ base = %w(description id_string search_text title)
388
+
389
+ return base unless auth_object&.admin?
390
+
391
+ base + %w(is_upcoming closed_at)
392
+ end
393
+
394
+ def self.ransackable_associations(_auth_object = nil)
395
+ %w(taxonomies)
374
396
  end
375
397
 
376
398
  def self.ransack(params = {}, options = {})
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ class MeetingLink < Meetings::ApplicationRecord
6
+ include Decidim::HasComponent
7
+
8
+ belongs_to :meeting, foreign_key: "decidim_meeting_id", class_name: "Decidim::Meetings::Meeting"
9
+ belongs_to :component, foreign_key: "decidim_component_id", class_name: "Decidim::Component"
10
+
11
+ # Finds all the meetings linked to the given component
12
+ # filtering out meetings that belong to private not transparent spaces.
13
+ def self.find_meetings(component:)
14
+ meetings = Meeting
15
+ .joins(:meeting_links)
16
+ .where("decidim_meetings_meeting_links.component": component)
17
+ .filter do |meeting|
18
+ !meeting.component.private_non_transparent_space?
19
+ end
20
+
21
+ Meeting.where(id: meetings.map(&:id))
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,5 +1,6 @@
1
1
  import "src/decidim/meetings/admin/agendas"
2
2
  import "src/decidim/meetings/admin/destroy_meeting_alert"
3
3
  import "src/decidim/meetings/admin/meetings_form"
4
+ import "src/decidim/meetings/admin/meetings_components_form"
4
5
  import "src/decidim/meetings/admin/registrations_form"
5
6
  import "src/decidim/meetings/admin/registrations_invite_form"
@@ -0,0 +1,77 @@
1
+ import TomSelect from "tom-select/dist/cjs/tom-select.popular";
2
+ import createTooltip from "src/decidim/tooltips"
3
+
4
+ /**
5
+ * This module manages the Linked Spaces section from the
6
+ * admin meeting edit form.
7
+ *
8
+ * It allows to add and remove components to the meeting and
9
+ * setup a TomSelect for the components selector.
10
+ */
11
+
12
+ const handleRemoveButton = (button) => {
13
+ button.addEventListener("click", function() {
14
+ button.closest("tr").remove();
15
+ });
16
+ };
17
+
18
+ const handleAddButton = () => {
19
+ const select = document.querySelector("select[name='add_component_select']");
20
+ const componentId = select.value;
21
+ const componentTitle = select.options[select.selectedIndex].text;
22
+
23
+ if (!componentId) {
24
+ return;
25
+ }
26
+
27
+ const table = document.querySelector(".js-components");
28
+ const body = document.querySelector(".js-components tbody");
29
+ const template = document.querySelector("#meeting_component_template");
30
+ const clone = template.content.cloneNode(true);
31
+ const title = clone.querySelector(".js-component-title");
32
+ const id = clone.querySelector("input");
33
+ const button = clone.querySelector(".js-remove-component");
34
+
35
+ title.textContent = componentTitle;
36
+ id.value = componentId;
37
+ if (button) {
38
+ handleRemoveButton(button);
39
+ }
40
+
41
+ body.appendChild(clone);
42
+
43
+ const tooltips = body.querySelectorAll("[data-tooltip]")
44
+
45
+ if (tooltips.length) {
46
+ createTooltip(tooltips[tooltips.length - 1]);
47
+ }
48
+
49
+ select.value = "";
50
+ table.classList.remove("hidden");
51
+ };
52
+
53
+ const setupTomSelect = () => {
54
+ const componentsSelect = document.querySelector(
55
+ "#add_component_select"
56
+ );
57
+
58
+ const config = {
59
+ plugins: ["dropdown_input"]
60
+ };
61
+
62
+ if (componentsSelect) {
63
+ return new TomSelect(componentsSelect, config);
64
+ }
65
+ return null;
66
+ }
67
+
68
+ document.addEventListener("DOMContentLoaded", () => {
69
+ document.querySelectorAll(".js-remove-component").forEach(handleRemoveButton);
70
+ const addButton = document.querySelector(".js-add-component")
71
+
72
+ if (addButton) {
73
+ addButton.addEventListener("click", handleAddButton);
74
+ }
75
+
76
+ setupTomSelect();
77
+ });
@@ -86,10 +86,16 @@ $(() => {
86
86
  if ($form.length > 0) {
87
87
  const $privateMeeting = $form.find("#private_meeting");
88
88
  const $transparent = $form.find("#transparent");
89
+ const $warning = $form.find(".js-private-warning");
90
+ const $assign = $form.find(".js-add-component");
89
91
 
90
92
  const toggleDisabledHiddenFields = () => {
91
93
  const enabledPrivateSpace = $privateMeeting.find("input[type='checkbox']").prop("checked");
94
+ const enabledTransparent = $transparent.find("input[type='checkbox']").prop("checked");
95
+
92
96
  $transparent.find("input[type='checkbox']").attr("disabled", "disabled");
97
+ $warning?.toggleClass("hidden", !enabledPrivateSpace || enabledTransparent);
98
+ $assign?.attr("disabled", enabledPrivateSpace && !enabledTransparent);
93
99
 
94
100
  if (enabledPrivateSpace) {
95
101
  $transparent.find("input[type='checkbox']").attr("disabled", !enabledPrivateSpace);
@@ -97,6 +103,8 @@ $(() => {
97
103
  };
98
104
 
99
105
  $privateMeeting.on("change", toggleDisabledHiddenFields);
106
+ $transparent.on("change", toggleDisabledHiddenFields);
107
+
100
108
  toggleDisabledHiddenFields();
101
109
 
102
110
  attachGeocoding($form.find("#meeting_address"));
@@ -41,7 +41,7 @@ module Decidim
41
41
  return disallow! if meeting && !meeting.official?
42
42
 
43
43
  case permission_action.action
44
- when :close, :copy, :destroy, :export_registrations, :update, :read_invites
44
+ when :close, :copy, :export_registrations, :update, :read_invites
45
45
  toggle_allow(meeting.present?)
46
46
  when :invite_attendee
47
47
  toggle_allow(meeting.present? && meeting.registrations_enabled?)
@@ -84,13 +84,20 @@ module Decidim
84
84
  end
85
85
 
86
86
  def can_create_meetings?
87
- component_settings&.creation_enabled_for_participants? && public_space_or_member?
87
+ (component_settings&.creation_enabled_for_participants? && can_participate?) || initiative_authorship?
88
88
  end
89
89
 
90
- def public_space_or_member?
90
+ def can_participate?
91
+ context[:current_component].participatory_space.can_participate?(user)
92
+ end
93
+
94
+ def initiative_authorship?
95
+ return false unless Decidim.module_installed?("initiatives")
96
+
91
97
  participatory_space = context[:current_component].participatory_space
92
98
 
93
- participatory_space.private_space? ? space_member?(participatory_space, user) : true
99
+ participatory_space.is_a?(Decidim::Initiative) &&
100
+ participatory_space.has_authorship?(user)
94
101
  end
95
102
 
96
103
  # Neither platform admins, nor space admins should be able to create meetings from the public side.
@@ -101,21 +108,18 @@ module Decidim
101
108
  end
102
109
 
103
110
  def can_update_meeting?
104
- component_settings&.creation_enabled_for_participants? &&
105
- meeting.authored_by?(user) &&
111
+ meeting.authored_by?(user) &&
106
112
  !meeting.closed?
107
113
  end
108
114
 
109
115
  def can_withdraw_meeting?
110
- component_settings&.creation_enabled_for_participants? &&
111
- meeting.authored_by?(user) &&
116
+ meeting.authored_by?(user) &&
112
117
  !meeting.withdrawn? &&
113
118
  !meeting.past?
114
119
  end
115
120
 
116
121
  def can_close_meeting?
117
- component_settings&.creation_enabled_for_participants? &&
118
- meeting.authored_by?(user) &&
122
+ meeting.authored_by?(user) &&
119
123
  meeting.past?
120
124
  end
121
125
 
@@ -39,7 +39,7 @@ module Decidim
39
39
 
40
40
  def action_string
41
41
  case action
42
- when "close", "create", "delete", "export_registrations", "update"
42
+ when "close", "create", "delete", "export_registrations", "update", "soft_delete", "restore"
43
43
  "decidim.meetings.admin_log.meeting.#{action}"
44
44
  else
45
45
  super
@@ -10,6 +10,8 @@ module Decidim
10
10
  include ActionView::Helpers::UrlHelper
11
11
  include Decidim::SanitizeHelper
12
12
 
13
+ alias super_title title
14
+
13
15
  def meeting
14
16
  __getobj__
15
17
  end
@@ -18,6 +20,12 @@ module Decidim
18
20
  Decidim::ResourceLocatorPresenter.new(meeting).path
19
21
  end
20
22
 
23
+ def taxonomy_names(html_escape: false, all_locales: false)
24
+ meeting.taxonomies.map do |taxonomy|
25
+ super_title(taxonomy.name, false, html_escape, all_locales)
26
+ end
27
+ end
28
+
21
29
  def display_mention
22
30
  link_to title, meeting_path
23
31
  end
@@ -25,7 +33,7 @@ module Decidim
25
33
  def title(links: false, html_escape: false, all_locales: false)
26
34
  return unless meeting
27
35
 
28
- super meeting.title, links, html_escape, all_locales
36
+ super(meeting.title, links, html_escape, all_locales)
29
37
  end
30
38
 
31
39
  def description(links: false, extras: true, strip_tags: false, all_locales: false)
@@ -103,6 +111,10 @@ module Decidim
103
111
  ""
104
112
  end
105
113
 
114
+ def space_title
115
+ translated_attribute component.participatory_space.title
116
+ end
117
+
106
118
  def profile_path
107
119
  resource_locator(meeting).path
108
120
  end
@@ -28,8 +28,8 @@ module Decidim
28
28
  # by a range of dates.
29
29
  def query
30
30
  meetings = Decidim::Meetings::Meeting.not_hidden.published.where(component: @components)
31
- meetings = meetings.where("created_at >= ?", @start_at) if @start_at.present?
32
- meetings = meetings.where("created_at <= ?", @end_at) if @end_at.present?
31
+ meetings = meetings.where(created_at: @start_at..) if @start_at.present?
32
+ meetings = meetings.where(created_at: ..@end_at) if @end_at.present?
33
33
  meetings
34
34
  end
35
35
  end
@@ -14,10 +14,10 @@ module Decidim
14
14
  meetings = Decidim::Meetings::Meeting.where(component: @resource).joins(:component)
15
15
 
16
16
  meetings_followers = Decidim::Follow.where(followable: meetings).joins(:user)
17
- .where("decidim_follows.created_at <= ?", end_time)
17
+ .where(decidim_follows: { created_at: ..end_time })
18
18
  cumulative_users = meetings_followers.pluck(:decidim_user_id)
19
19
 
20
- meetings_followers = meetings_followers.where("decidim_follows.created_at >= ?", start_time)
20
+ meetings_followers = meetings_followers.where(decidim_follows: { created_at: start_time.. })
21
21
  quantity_users = meetings_followers.pluck(:decidim_user_id)
22
22
 
23
23
  {
@@ -13,9 +13,9 @@ module Decidim
13
13
  next if cumulative_value.zero?
14
14
 
15
15
  quantity_value = quantity[key] || 0
16
- category_id, space_type, space_id = key
16
+ taxonomy_id, space_type, space_id = key
17
17
  record = Decidim::Metric.find_or_initialize_by(day: @day.to_s, metric_type: @metric_name,
18
- organization: @organization, decidim_category_id: category_id,
18
+ organization: @organization, decidim_taxonomy_id: taxonomy_id,
19
19
  participatory_space_type: space_type, participatory_space_id: space_id)
20
20
  record.assign_attributes(cumulative: cumulative_value, quantity: quantity_value)
21
21
  record.save!
@@ -31,16 +31,16 @@ module Decidim
31
31
  manifest.participatory_spaces.call(@organization).public_spaces
32
32
  end
33
33
  @query = Decidim::Meetings::Meeting.where(component: visible_components_from_spaces(spaces)).joins(:component)
34
- .left_outer_joins(:category).visible
35
- @query = @query.where("decidim_meetings_meetings.created_at <= ?", end_time)
36
- @query = @query.group("decidim_categorizations.decidim_category_id",
34
+ .left_outer_joins(:taxonomizations).visible
35
+ @query = @query.where(decidim_meetings_meetings: { created_at: ..end_time })
36
+ @query = @query.group("decidim_taxonomizations.taxonomy_id",
37
37
  :participatory_space_type,
38
38
  :participatory_space_id)
39
39
  @query
40
40
  end
41
41
 
42
42
  def quantity
43
- @quantity ||= query.where("decidim_meetings_meetings.created_at >= ?", start_time).count
43
+ @quantity ||= query.where(decidim_meetings_meetings: { created_at: start_time.. }).count
44
44
  end
45
45
  end
46
46
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ class BaseDownloadYourDataSerializer < Decidim::Exporters::Serializer
6
+ # This is the Base class for Invite and Registrations models for the download your data feature
7
+ def serialize
8
+ {
9
+ id: resource.id,
10
+ created_at: resource.created_at,
11
+ updated_at: resource.updated_at,
12
+ meeting: {
13
+ title: resource.meeting.title,
14
+ url: Decidim::ResourceLocatorPresenter.new(resource.meeting).url,
15
+ description: resource.meeting.description,
16
+ start_time: resource.meeting.start_time,
17
+ end_time: resource.meeting.end_time,
18
+ address: resource.meeting.address,
19
+ location: resource.meeting.location,
20
+ location_hints: resource.meeting.location_hints,
21
+ reference: resource.meeting.reference,
22
+ attendees_count: resource.meeting.attendees_count,
23
+ attending_organizations: resource.meeting.attending_organizations,
24
+ closed_at: resource.meeting.closed_at,
25
+ closing_report: resource.meeting.closing_report,
26
+ published_at: resource.meeting.published_at
27
+ }
28
+ }
29
+ end
30
+ end
31
+ end
32
+ end
@@ -2,34 +2,14 @@
2
2
 
3
3
  module Decidim
4
4
  module Meetings
5
- class DownloadYourDataInviteSerializer < Decidim::Exporters::Serializer
5
+ class DownloadYourDataInviteSerializer < BaseDownloadYourDataSerializer
6
6
  # Serializes an invite for download your data
7
7
  def serialize
8
- {
9
- id: resource.id,
10
- sent_at: resource.sent_at,
11
- accepted_at: resource.accepted_at,
12
- rejected_at: resource.rejected_at,
13
- user: {
14
- name: resource.user.name,
15
- email: resource.user.email
16
- },
17
- meeting: {
18
- title: resource.meeting.title,
19
- description: resource.meeting.description,
20
- start_time: resource.meeting.start_time,
21
- end_time: resource.meeting.end_time,
22
- address: resource.meeting.address,
23
- location: resource.meeting.location,
24
- location_hints: resource.meeting.location_hints,
25
- reference: resource.meeting.reference,
26
- attendees_count: resource.meeting.attendees_count,
27
- attending_organizations: resource.meeting.attending_organizations,
28
- closed_at: resource.meeting.closed_at,
29
- closing_report: resource.meeting.closing_report,
30
- published_at: resource.meeting.published_at
31
- }
32
- }
8
+ super.merge({
9
+ sent_at: resource.sent_at,
10
+ accepted_at: resource.accepted_at,
11
+ rejected_at: resource.rejected_at
12
+ })
33
13
  end
34
14
  end
35
15
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ class DownloadYourDataMeetingSerializer < Decidim::Meetings::MeetingSerializer
6
+ # Serializes a Meeting for download your data feature
7
+ #
8
+ # Remove the author information as it is the same of the user that
9
+ # requested the data
10
+ def serialize
11
+ super.except!(:author)
12
+ end
13
+ end
14
+ end
15
+ end