decidim-meetings 0.29.1 → 0.30.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/meetings/cancel_registration_meeting_button/cancelation_modal.erb +1 -1
- data/app/cells/decidim/meetings/cancel_registration_meeting_button/show.erb +3 -1
- data/app/cells/decidim/meetings/cancel_registration_meeting_button_cell.rb +1 -1
- data/app/cells/decidim/meetings/dates_and_map/show.erb +6 -4
- data/app/cells/decidim/meetings/dates_and_map_cell.rb +1 -1
- data/app/cells/decidim/meetings/highlighted_meetings_for_component/show.erb +1 -1
- data/app/cells/decidim/meetings/join_meeting_button/show.erb +5 -2
- data/app/cells/decidim/meetings/meeting_card_metadata_cell.rb +3 -3
- data/app/cells/decidim/meetings/meeting_l_cell.rb +17 -0
- data/app/commands/decidim/meetings/admin/copy_meeting.rb +1 -2
- data/app/commands/decidim/meetings/admin/create_meeting.rb +8 -2
- data/app/commands/decidim/meetings/admin/update_meeting.rb +8 -2
- data/app/commands/decidim/meetings/create_meeting.rb +2 -2
- data/app/commands/decidim/meetings/update_meeting.rb +2 -3
- data/app/controllers/concerns/decidim/meetings/admin/filterable.rb +9 -5
- data/app/controllers/concerns/decidim/meetings/component_filterable.rb +1 -2
- data/app/controllers/decidim/meetings/admin/meetings_controller.rb +14 -22
- data/app/controllers/decidim/meetings/admin/registration_form_controller.rb +8 -0
- data/app/controllers/decidim/meetings/directory/meetings_controller.rb +2 -4
- data/app/controllers/decidim/meetings/meetings_controller.rb +40 -6
- data/app/forms/decidim/meetings/admin/close_meeting_form.rb +1 -1
- data/app/forms/decidim/meetings/admin/meeting_agenda_items_form.rb +1 -1
- data/app/forms/decidim/meetings/admin/meeting_form.rb +17 -31
- data/app/forms/decidim/meetings/admin/meeting_registrations_form.rb +2 -2
- data/app/forms/decidim/meetings/base_meeting_form.rb +6 -0
- data/app/forms/decidim/meetings/meeting_form.rb +2 -30
- data/app/helpers/decidim/meetings/admin/application_helper.rb +11 -1
- data/app/helpers/decidim/meetings/application_helper.rb +35 -1
- data/app/helpers/decidim/meetings/directory/application_helper.rb +9 -48
- data/app/helpers/decidim/meetings/meetings_helper.rb +5 -0
- data/app/models/decidim/meetings/invite.rb +10 -0
- data/app/models/decidim/meetings/meeting.rb +23 -1
- data/app/models/decidim/meetings/meeting_link.rb +25 -0
- data/app/packs/entrypoints/decidim_meetings_admin.js +1 -0
- data/app/packs/src/decidim/meetings/admin/meetings_components_form.js +77 -0
- data/app/packs/src/decidim/meetings/admin/meetings_form.js +8 -0
- data/app/packs/stylesheets/decidim/meetings/_item.scss +5 -17
- data/app/permissions/decidim/meetings/admin/permissions.rb +1 -1
- data/app/permissions/decidim/meetings/permissions.rb +20 -11
- data/app/presenters/decidim/meetings/admin_log/meeting_presenter.rb +1 -1
- data/app/presenters/decidim/meetings/meeting_presenter.rb +14 -6
- data/app/queries/decidim/meetings/filtered_meetings.rb +2 -2
- data/app/queries/decidim/meetings/metrics/meeting_followers_metric_measure.rb +2 -2
- data/app/queries/decidim/meetings/metrics/meetings_metric_manage.rb +6 -6
- data/app/serializers/decidim/meetings/base_download_your_data_serializer.rb +32 -0
- data/app/serializers/decidim/meetings/download_your_data_invite_serializer.rb +6 -26
- data/app/serializers/decidim/meetings/download_your_data_meeting_serializer.rb +15 -0
- data/app/serializers/decidim/meetings/download_your_data_registration_serializer.rb +6 -24
- data/app/views/decidim/meetings/admin/meetings/_component.html.erb +15 -0
- data/app/views/decidim/meetings/admin/meetings/_form.html.erb +7 -9
- data/app/views/decidim/meetings/admin/meetings/_linked_spaces.html.erb +53 -0
- data/app/views/decidim/meetings/admin/meetings/_meeting-tr.html.erb +42 -0
- data/app/views/decidim/meetings/admin/meetings/_meeting_actions.html.erb +70 -0
- data/app/views/decidim/meetings/admin/meetings/_meetings-thead.html.erb +26 -0
- data/app/views/decidim/meetings/admin/meetings/index.html.erb +16 -142
- data/app/views/decidim/meetings/admin/meetings/manage_trash.html.erb +23 -0
- data/app/views/decidim/meetings/admin/registration_form/edit_questions.html.erb +44 -0
- data/app/views/decidim/meetings/admin/registrations/edit.html.erb +1 -0
- data/app/views/decidim/meetings/directory/meetings/index.html.erb +1 -2
- data/app/views/decidim/meetings/live_events/show.html.erb +5 -5
- data/app/views/decidim/meetings/meetings/_form.html.erb +4 -8
- data/app/views/decidim/meetings/meetings/_meeting.html.erb +51 -26
- data/app/views/decidim/meetings/meetings/_meeting_actions.html.erb +34 -0
- data/app/views/decidim/meetings/meetings/_meeting_aside.html.erb +20 -59
- data/app/views/decidim/meetings/meetings/_meeting_poll_actions.html.erb +2 -5
- data/app/views/decidim/meetings/meetings/_schema_org_event_meeting.html.erb +3 -0
- data/app/views/decidim/meetings/meetings/index.html.erb +10 -2
- data/app/views/decidim/meetings/meetings/show.html.erb +5 -5
- data/app/views/decidim/meetings/polls/answers/index.html.erb +5 -5
- data/app/views/decidim/meetings/registration_mailer/confirmation.html.erb +1 -1
- data/app/views/decidim/meetings/shared/_filters.html.erb +1 -13
- data/app/views/decidim/meetings/shared/_index.html.erb +1 -1
- data/app/views/decidim/meetings/shared/_index.js.erb +5 -5
- data/app/views/decidim/meetings/shared/_meetings_aside.html.erb +2 -2
- data/app/views/decidim/participatory_spaces/_conference_venues.html.erb +1 -1
- data/config/locales/ar.yml +17 -15
- data/config/locales/bg.yml +5 -26
- data/config/locales/bn-BD.yml +1 -0
- data/config/locales/bs-BA.yml +8 -0
- data/config/locales/ca.yml +137 -25
- data/config/locales/cs.yml +139 -28
- data/config/locales/de.yml +172 -92
- data/config/locales/el.yml +1 -20
- data/config/locales/en.yml +133 -21
- data/config/locales/es-MX.yml +137 -25
- data/config/locales/es-PY.yml +137 -25
- data/config/locales/es.yml +137 -25
- data/config/locales/eu.yml +167 -55
- data/config/locales/fi-plain.yml +138 -26
- data/config/locales/fi.yml +150 -38
- data/config/locales/fr-CA.yml +79 -26
- data/config/locales/fr.yml +79 -26
- data/config/locales/ga-IE.yml +0 -10
- data/config/locales/gl.yml +1 -8
- data/config/locales/hu.yml +1 -17
- data/config/locales/id-ID.yml +1 -5
- data/config/locales/is-IS.yml +0 -4
- data/config/locales/it.yml +1 -12
- data/config/locales/ja.yml +96 -26
- data/config/locales/lb.yml +0 -8
- data/config/locales/lt.yml +1 -24
- data/config/locales/lv.yml +1 -5
- data/config/locales/nl.yml +1 -15
- data/config/locales/no.yml +1 -14
- data/config/locales/pl.yml +5 -22
- data/config/locales/pt-BR.yml +1 -22
- data/config/locales/pt.yml +1 -12
- data/config/locales/ro-RO.yml +32 -16
- data/config/locales/ru.yml +1 -5
- data/config/locales/sk.yml +1 -5
- data/config/locales/sv.yml +74 -26
- data/config/locales/tr-TR.yml +1 -8
- data/config/locales/uk.yml +0 -4
- data/config/locales/zh-CN.yml +1 -8
- data/config/locales/zh-TW.yml +1 -19
- data/db/migrate/20181107175558_add_questionnaire_to_existing_meetings.rb +1 -1
- data/db/migrate/20200827153856_add_commentable_counter_cache_to_meetings.rb +1 -1
- data/db/migrate/20201016065302_fix_meetings_registration_terms.rb +1 -1
- data/db/migrate/20210310120731_add_followable_counter_cache_to_meetings.rb +1 -1
- data/db/migrate/20240712104245_create_decidim_meetings_meeting_link.rb +12 -0
- data/db/migrate/20240828103603_add_deleted_at_to_decidim_meetings_meetings.rb +8 -0
- data/decidim-meetings.gemspec +2 -2
- data/lib/decidim/api/agenda_item_type.rb +6 -7
- data/lib/decidim/api/agenda_type.rb +3 -4
- data/lib/decidim/api/meeting_type.rb +44 -40
- data/lib/decidim/api/meetings_type.rb +5 -8
- data/lib/decidim/api/service_type.rb +1 -1
- data/lib/decidim/meetings/admin_engine.rb +9 -1
- data/lib/decidim/meetings/component.rb +14 -4
- data/lib/decidim/meetings/download_your_data_user_answers_serializer.rb +13 -7
- data/lib/decidim/meetings/engine.rb +2 -0
- data/lib/decidim/meetings/meeting_serializer.rb +86 -38
- data/lib/decidim/meetings/schema_org_event_meeting_serializer.rb +151 -0
- data/lib/decidim/meetings/seeds.rb +2 -4
- data/lib/decidim/meetings/test/factories.rb +14 -0
- data/lib/decidim/meetings/test/translated_event.rb +3 -3
- data/lib/decidim/meetings/version.rb +1 -1
- data/lib/decidim/meetings.rb +1 -0
- metadata +35 -22
- data/app/cells/decidim/meetings/meetings_map/show.erb +0 -16
- data/app/cells/decidim/meetings/meetings_map_cell.rb +0 -32
- data/app/commands/decidim/meetings/admin/destroy_meeting.rb +0 -21
- data/app/helpers/decidim/meetings/map_helper.rb +0 -21
- data/app/views/decidim/meetings/meetings/_actions.html.erb +0 -6
@@ -9,8 +9,6 @@ module Decidim
|
|
9
9
|
attribute :location, String
|
10
10
|
attribute :location_hints, String
|
11
11
|
|
12
|
-
attribute :decidim_scope_id, Integer
|
13
|
-
attribute :decidim_category_id, Integer
|
14
12
|
attribute :user_group_id, Integer
|
15
13
|
attribute :registration_type, String
|
16
14
|
attribute :registrations_enabled, Boolean, default: false
|
@@ -21,8 +19,8 @@ module Decidim
|
|
21
19
|
attribute :iframe_access_level, String
|
22
20
|
|
23
21
|
validates :iframe_embed_type, inclusion: { in: Decidim::Meetings::Meeting.participants_iframe_embed_types }
|
24
|
-
validates :title, presence: true
|
25
|
-
validates :description, presence: true
|
22
|
+
validates :title, presence: true, etiquette: true
|
23
|
+
validates :description, presence: true, etiquette: true
|
26
24
|
validates :type_of_meeting, presence: true
|
27
25
|
validates :location, presence: true, if: ->(form) { form.in_person_meeting? || form.hybrid_meeting? }
|
28
26
|
validates :online_meeting_url, presence: true, url: true, if: ->(form) { form.online_meeting? || form.hybrid_meeting? }
|
@@ -30,9 +28,6 @@ module Decidim
|
|
30
28
|
validates :available_slots, numericality: { greater_than_or_equal_to: 0 }, presence: true, if: ->(form) { form.on_this_platform? }
|
31
29
|
validates :registration_terms, presence: true, if: ->(form) { form.on_this_platform? }
|
32
30
|
validates :registration_url, presence: true, url: true, if: ->(form) { form.on_different_platform? }
|
33
|
-
validates :category, presence: true, if: ->(form) { form.decidim_category_id.present? }
|
34
|
-
validates :scope, presence: true, if: ->(form) { form.decidim_scope_id.present? }
|
35
|
-
validates :decidim_scope_id, scope_belongs_to_component: true, if: ->(form) { form.decidim_scope_id.present? }
|
36
31
|
validates :clean_type_of_meeting, presence: true
|
37
32
|
validates(
|
38
33
|
:iframe_access_level,
|
@@ -41,10 +36,7 @@ module Decidim
|
|
41
36
|
)
|
42
37
|
validate :embeddable_meeting_url
|
43
38
|
|
44
|
-
delegate :categories, to: :current_component
|
45
|
-
|
46
39
|
def map_model(model)
|
47
|
-
self.decidim_category_id = model.categorization.decidim_category_id if model.categorization
|
48
40
|
presenter = MeetingEditionPresenter.new(model)
|
49
41
|
self.title = presenter.title(all_locales: false)
|
50
42
|
self.description = presenter.editor_description(all_locales: false)
|
@@ -56,26 +48,6 @@ module Decidim
|
|
56
48
|
|
57
49
|
alias component current_component
|
58
50
|
|
59
|
-
# Finds the Scope from the given decidim_scope_id, uses the component scope if missing.
|
60
|
-
#
|
61
|
-
# Returns a Decidim::Scope
|
62
|
-
def scope
|
63
|
-
@scope ||= @attributes["decidim_scope_id"].value ? current_component.scopes.find_by(id: @attributes["decidim_scope_id"].value) : current_component.scope
|
64
|
-
end
|
65
|
-
|
66
|
-
# Scope identifier
|
67
|
-
#
|
68
|
-
# Returns the scope identifier related to the meeting
|
69
|
-
def decidim_scope_id
|
70
|
-
super || scope&.id
|
71
|
-
end
|
72
|
-
|
73
|
-
def category
|
74
|
-
return unless current_component
|
75
|
-
|
76
|
-
@category ||= categories.find_by(id: decidim_category_id)
|
77
|
-
end
|
78
|
-
|
79
51
|
def clean_type_of_meeting
|
80
52
|
type_of_meeting.presence
|
81
53
|
end
|
@@ -7,7 +7,6 @@ module Decidim
|
|
7
7
|
#
|
8
8
|
module ApplicationHelper
|
9
9
|
include Decidim::MapHelper
|
10
|
-
include Decidim::Admin::ResourceScopeHelper
|
11
10
|
include Decidim::PaginateHelper
|
12
11
|
|
13
12
|
def tabs_id_for_service(service)
|
@@ -21,6 +20,17 @@ module Decidim
|
|
21
20
|
def tabs_id_for_agenda_item_child(agenda_item)
|
22
21
|
"meeting_agenda_item_#{agenda_item.to_param_child}"
|
23
22
|
end
|
23
|
+
|
24
|
+
def find_meeting_components_for_select
|
25
|
+
spaces = current_organization.public_participatory_spaces
|
26
|
+
meeting_components = Decidim::Component
|
27
|
+
.where(manifest_name: "meetings", participatory_space_id: spaces.pluck(:id))
|
28
|
+
.where.not(id: current_component.id)
|
29
|
+
|
30
|
+
meeting_components.map do |component|
|
31
|
+
[component.hierarchy_title, component.id]
|
32
|
+
end.sort_by(&:first)
|
33
|
+
end
|
24
34
|
end
|
25
35
|
end
|
26
36
|
end
|
@@ -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, :
|
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"));
|
@@ -6,29 +6,17 @@
|
|
6
6
|
}
|
7
7
|
|
8
8
|
&__calendar {
|
9
|
-
@apply
|
9
|
+
@apply order-first flex flex-col min-w-48 rounded bg-background text-center md:w-14;
|
10
10
|
|
11
11
|
&:only-child &-month {
|
12
12
|
@apply rounded-t;
|
13
13
|
}
|
14
14
|
|
15
15
|
&-container {
|
16
|
-
@apply
|
16
|
+
@apply flex flex-wrap flex-col md:flex-row gap-2 border-4 border-background rounded;
|
17
17
|
|
18
|
-
|
19
|
-
@apply
|
20
|
-
|
21
|
-
&:not(:last-child) {
|
22
|
-
@apply col-span-2 md:col-auto order-2 md:order-1;
|
23
|
-
}
|
24
|
-
|
25
|
-
&:last-child {
|
26
|
-
@apply md:col-span-2 pr-4;
|
27
|
-
}
|
28
|
-
}
|
29
|
-
|
30
|
-
> *:nth-child(3) {
|
31
|
-
@apply order-1 md:order-2 h-[135px] md:h-full;
|
18
|
+
ul {
|
19
|
+
@apply flex-1 p-2;
|
32
20
|
}
|
33
21
|
}
|
34
22
|
|
@@ -55,7 +43,7 @@
|
|
55
43
|
}
|
56
44
|
|
57
45
|
&__lg {
|
58
|
-
@apply
|
46
|
+
@apply flex min-w-48;
|
59
47
|
}
|
60
48
|
|
61
49
|
&__lg &-month {
|
@@ -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, :
|
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?)
|
@@ -4,12 +4,17 @@ module Decidim
|
|
4
4
|
module Meetings
|
5
5
|
class Permissions < Decidim::DefaultPermissions
|
6
6
|
def permissions
|
7
|
-
return permission_action unless user
|
8
|
-
|
9
7
|
# Delegate the admin permission checks to the admin permissions class
|
10
8
|
return Decidim::Meetings::Admin::Permissions.new(user, permission_action, context).permissions if permission_action.scope == :admin
|
11
9
|
return permission_action if permission_action.scope != :public
|
12
10
|
|
11
|
+
if permission_action.subject == :meeting && permission_action.action == :read
|
12
|
+
toggle_allow(!meeting&.hidden? && meeting&.current_user_can_visit_meeting?(user))
|
13
|
+
return permission_action
|
14
|
+
end
|
15
|
+
|
16
|
+
return permission_action unless user
|
17
|
+
|
13
18
|
case permission_action.subject
|
14
19
|
when :answer
|
15
20
|
case permission_action.action
|
@@ -79,13 +84,20 @@ module Decidim
|
|
79
84
|
end
|
80
85
|
|
81
86
|
def can_create_meetings?
|
82
|
-
component_settings&.creation_enabled_for_participants? &&
|
87
|
+
(component_settings&.creation_enabled_for_participants? && can_participate?) || initiative_authorship?
|
83
88
|
end
|
84
89
|
|
85
|
-
def
|
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
|
+
|
86
97
|
participatory_space = context[:current_component].participatory_space
|
87
98
|
|
88
|
-
participatory_space.
|
99
|
+
participatory_space.is_a?(Decidim::Initiative) &&
|
100
|
+
participatory_space.has_authorship?(user)
|
89
101
|
end
|
90
102
|
|
91
103
|
# Neither platform admins, nor space admins should be able to create meetings from the public side.
|
@@ -96,21 +108,18 @@ module Decidim
|
|
96
108
|
end
|
97
109
|
|
98
110
|
def can_update_meeting?
|
99
|
-
|
100
|
-
meeting.authored_by?(user) &&
|
111
|
+
meeting.authored_by?(user) &&
|
101
112
|
!meeting.closed?
|
102
113
|
end
|
103
114
|
|
104
115
|
def can_withdraw_meeting?
|
105
|
-
|
106
|
-
meeting.authored_by?(user) &&
|
116
|
+
meeting.authored_by?(user) &&
|
107
117
|
!meeting.withdrawn? &&
|
108
118
|
!meeting.past?
|
109
119
|
end
|
110
120
|
|
111
121
|
def can_close_meeting?
|
112
|
-
|
113
|
-
meeting.authored_by?(user) &&
|
122
|
+
meeting.authored_by?(user) &&
|
114
123
|
meeting.past?
|
115
124
|
end
|
116
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
|
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)
|
@@ -74,7 +82,7 @@ module Decidim
|
|
74
82
|
return unless meeting
|
75
83
|
|
76
84
|
handle_locales(meeting.registration_email_custom_content, all_locales) do |content|
|
77
|
-
renderer = Decidim::ContentRenderers::HashtagRenderer.new(
|
85
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(decidim_sanitize_editor_admin(content))
|
78
86
|
renderer.render(links:).html_safe
|
79
87
|
end
|
80
88
|
end
|
@@ -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
|
@@ -135,10 +147,6 @@ module Decidim
|
|
135
147
|
|
136
148
|
proposals.map.with_index { |proposal, index| "#{index + 1}) #{proposal.title}\n" }
|
137
149
|
end
|
138
|
-
|
139
|
-
def sanitized(content)
|
140
|
-
decidim_sanitize_editor(content)
|
141
|
-
end
|
142
150
|
end
|
143
151
|
end
|
144
152
|
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(
|
32
|
-
meetings = meetings.where(
|
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
|