decidim-meetings 0.29.2 → 0.30.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +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 +12 -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/meeting_form.rb +16 -30
- 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/permissions/decidim/meetings/admin/permissions.rb +1 -1
- data/app/permissions/decidim/meetings/permissions.rb +13 -9
- data/app/presenters/decidim/meetings/admin_log/meeting_presenter.rb +1 -1
- data/app/presenters/decidim/meetings/meeting_presenter.rb +13 -1
- 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/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 +3 -2
- 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 -17
- data/config/locales/bg.yml +5 -25
- data/config/locales/ca.yml +137 -25
- data/config/locales/cs.yml +138 -28
- data/config/locales/de.yml +138 -26
- data/config/locales/el.yml +1 -22
- 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 +138 -26
- data/config/locales/fi-plain.yml +138 -26
- data/config/locales/fi.yml +138 -26
- data/config/locales/fr-CA.yml +79 -26
- data/config/locales/fr.yml +79 -26
- data/config/locales/ga-IE.yml +0 -13
- data/config/locales/gl.yml +1 -12
- data/config/locales/hu.yml +1 -19
- data/config/locales/id-ID.yml +1 -13
- data/config/locales/is-IS.yml +0 -12
- data/config/locales/it.yml +1 -17
- data/config/locales/ja.yml +95 -25
- data/config/locales/lb.yml +0 -11
- data/config/locales/lt.yml +1 -23
- data/config/locales/lv.yml +1 -13
- data/config/locales/nl.yml +1 -17
- data/config/locales/no.yml +1 -16
- data/config/locales/pl.yml +5 -21
- data/config/locales/pt-BR.yml +1 -21
- data/config/locales/pt.yml +1 -17
- data/config/locales/ro-RO.yml +30 -17
- data/config/locales/ru.yml +1 -13
- data/config/locales/sk.yml +1 -13
- data/config/locales/sv.yml +74 -26
- data/config/locales/tr-TR.yml +1 -19
- data/config/locales/uk.yml +0 -12
- data/config/locales/zh-CN.yml +1 -18
- data/config/locales/zh-TW.yml +1 -21
- 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 +1 -1
- 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 +33 -41
- data/lib/decidim/api/meetings_type.rb +4 -5
- 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/meeting_serializer.rb +70 -59
- 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 +8 -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 +32 -21
- 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
@@ -7,32 +7,53 @@ module Decidim
|
|
7
7
|
|
8
8
|
implements Decidim::Comments::CommentableInterface
|
9
9
|
implements Decidim::Core::AuthorableInterface
|
10
|
-
implements Decidim::Core::
|
11
|
-
implements Decidim::Core::ScopableInterface
|
10
|
+
implements Decidim::Core::TaxonomizableInterface
|
12
11
|
implements Decidim::Core::AttachableInterface
|
13
12
|
implements Decidim::Core::TimestampsInterface
|
14
13
|
implements Decidim::Meetings::ServicesInterface
|
15
14
|
implements Decidim::Meetings::LinkedResourcesInterface if Decidim::Meetings.enable_proposal_linking
|
16
15
|
implements Decidim::Forms::QuestionnaireEntityInterface
|
17
16
|
|
17
|
+
field :address, GraphQL::Types::String, "The physical address of this meeting (used for geolocation)", null: true
|
18
|
+
field :agenda, Decidim::Meetings::AgendaType, "Agenda for this meeting, if available", null: true
|
19
|
+
field :attendee_count, GraphQL::Types::Int, "Amount of attendees to this meeting", method: :attendees_count, null: true
|
20
|
+
field :attending_organizations, GraphQL::Types::String, "list of attending organizations", null: true
|
21
|
+
field :audio_url, GraphQL::Types::String, "URL for the audio of the session, if any", null: true
|
22
|
+
field :closed, GraphQL::Types::Boolean, "Whether this meeting is closed or not.", method: :closed?, null: false
|
23
|
+
field :closing_report, Decidim::Core::TranslatedFieldType, "The closing report of this meeting.", null: true
|
24
|
+
field :contribution_count, GraphQL::Types::Int, "Amount of contributions to this meeting", method: :contributions_count, null: true
|
25
|
+
field :coordinates, Decidim::Core::CoordinatesType, "Physical coordinates for this meeting", null: true
|
26
|
+
field :description, Decidim::Core::TranslatedFieldType, "The description of this meeting.", null: true
|
27
|
+
field :end_time, Decidim::Core::DateTimeType, "The time this meeting ends", null: false
|
18
28
|
field :id, GraphQL::Types::ID, "ID of this meeting", null: false
|
29
|
+
field :iframe_embed_type, GraphQL::Types::String, "The type of displaying of the online meeting URL", null: true
|
30
|
+
field :is_withdrawn, GraphQL::Types::Boolean, "Whether this meeting is withdrawn or not.", method: :withdrawn?, null: false
|
31
|
+
field :location, Decidim::Core::TranslatedFieldType, "The location of this meeting (free format)", null: true
|
32
|
+
field :location_hints, Decidim::Core::TranslatedFieldType, "The location of this meeting (free format)", null: true
|
33
|
+
field :online_meeting_url, GraphQL::Types::String, "The URL of the meeting (when the type is online)", null: false
|
34
|
+
field :private_meeting, GraphQL::Types::Boolean, "Whether the meeting is private or not (it can only be true if transparent)", null: false
|
19
35
|
field :reference, GraphQL::Types::String, "Reference for this meeting", null: false
|
20
|
-
field :
|
21
|
-
field :
|
36
|
+
field :registration_form, Decidim::Forms::QuestionnaireType, description: "If registration requires to fill a form, this is the questionnaire", null: true
|
37
|
+
field :registration_form_enabled, GraphQL::Types::Boolean, "Whether the registrations have a form or not", null: false
|
38
|
+
field :registration_terms, Decidim::Core::TranslatedFieldType, "The registration terms", null: true
|
39
|
+
field :registrations_enabled, GraphQL::Types::Boolean, "Whether the registrations are enabled or not", null: false
|
40
|
+
field :remaining_slots, GraphQL::Types::Int, "Amount of slots available for this meeting", null: true
|
22
41
|
field :start_time, Decidim::Core::DateTimeType, "The time this meeting starts", null: false
|
23
|
-
field :
|
24
|
-
field :
|
42
|
+
field :title, Decidim::Core::TranslatedFieldType, "The title of this meeting.", null: false
|
43
|
+
field :transparent, GraphQL::Types::Boolean, "For private meetings, information is public if transparent", null: false
|
44
|
+
field :type_of_meeting, GraphQL::Types::String, "The type of the meeting (online or in-person)", null: false
|
45
|
+
field :video_url, GraphQL::Types::String, "URL for the video of the session, if any", null: true
|
46
|
+
field :withdrawn, GraphQL::Types::Boolean, "Whether this meeting has been withdrawn or not", method: :withdrawn?, null: true
|
47
|
+
field :withdrawn_at, Decidim::Core::DateTimeType, description: "The date and time this meeting was withdrawn", null: true
|
48
|
+
|
49
|
+
def registration_form
|
50
|
+
object.questionnaire if object.registration_form_enabled?
|
51
|
+
end
|
25
52
|
|
26
53
|
def agenda
|
27
54
|
object.agenda if object.agenda&.visible?
|
28
55
|
end
|
29
56
|
|
30
|
-
field :closed, GraphQL::Types::Boolean, "Whether this meeting is closed or not.", method: :closed?, null: false
|
31
|
-
field :isWithdrawn, GraphQL::Types::Boolean, "Whether this meeting is withdrawn or not.", method: :withdrawn?, null: false
|
32
|
-
field :closing_report, Decidim::Core::TranslatedFieldType, "The closing report of this meeting.", null: true
|
33
|
-
field :video_url, GraphQL::Types::String, "URL for the video of the session, if any", null: true
|
34
|
-
field :audio_url, GraphQL::Types::String, "URL for the audio of the session, if any", null: true
|
35
|
-
|
36
57
|
def closing_report
|
37
58
|
object.closing_report if object.closing_visible?
|
38
59
|
end
|
@@ -45,38 +66,9 @@ module Decidim
|
|
45
66
|
object.audio_url if object.closing_visible?
|
46
67
|
end
|
47
68
|
|
48
|
-
field :withdrawn_at, Decidim::Core::DateTimeType, description: "The date and time this meeting was withdrawn", null: true
|
49
|
-
field :withdrawn, GraphQL::Types::Boolean, "Whether this meeting has been withdrawn or not", method: :withdrawn?, null: true
|
50
|
-
|
51
|
-
field :created_at, Decidim::Core::DateTimeType, description: "The date and time this minutes was created", null: true
|
52
|
-
field :updated_at, Decidim::Core::DateTimeType, description: "The date and time this minutes was updated", null: true
|
53
|
-
|
54
|
-
field :attending_organizations, GraphQL::Types::String, "list of attending organizations", null: true
|
55
|
-
field :attendee_count, GraphQL::Types::Int, "Amount of attendees to this meeting", method: :attendees_count, null: true
|
56
|
-
field :contribution_count, GraphQL::Types::Int, "Amount of contributions to this meeting", method: :contributions_count, null: true
|
57
|
-
|
58
|
-
field :private_meeting, GraphQL::Types::Boolean, "Whether the meeting is private or not (it can only be true if transparent)", null: false
|
59
|
-
field :transparent, GraphQL::Types::Boolean, "For private meetings, information is public if transparent", null: false
|
60
|
-
field :registrations_enabled, GraphQL::Types::Boolean, "Whether the registrations are enabled or not", null: false
|
61
|
-
field :registration_terms, Decidim::Core::TranslatedFieldType, "The registration terms", null: true
|
62
|
-
field :remaining_slots, GraphQL::Types::Int, "Amount of slots available for this meeting", null: true
|
63
|
-
field :registration_form_enabled, GraphQL::Types::Boolean, "Whether the registrations have a form or not", null: false
|
64
|
-
field :registration_form, Decidim::Forms::QuestionnaireType, description: "If registration requires to fill a form, this is the questionnaire", null: true
|
65
|
-
|
66
|
-
def registration_form
|
67
|
-
object.questionnaire if object.registration_form_enabled?
|
68
|
-
end
|
69
|
-
field :location, Decidim::Core::TranslatedFieldType, "The location of this meeting (free format)", null: true
|
70
|
-
field :location_hints, Decidim::Core::TranslatedFieldType, "The location of this meeting (free format)", null: true
|
71
|
-
field :address, GraphQL::Types::String, "The physical address of this meeting (used for geolocation)", null: true
|
72
|
-
field :coordinates, Decidim::Core::CoordinatesType, "Physical coordinates for this meeting", null: true
|
73
|
-
|
74
69
|
def coordinates
|
75
70
|
[object.latitude, object.longitude]
|
76
71
|
end
|
77
|
-
field :type_of_meeting, GraphQL::Types::String, "The type of the meeting (online or in-person)", null: false
|
78
|
-
field :online_meeting_url, GraphQL::Types::String, "The URL of the meeting (when the type is online)", null: false
|
79
|
-
field :iframe_embed_type, GraphQL::Types::String, "The type of displaying of the online meeting URL", null: true
|
80
72
|
|
81
73
|
def self.authorized?(object, context)
|
82
74
|
context[:meeting] = object
|
@@ -6,16 +6,15 @@ module Decidim
|
|
6
6
|
graphql_name "Meetings"
|
7
7
|
description "A meetings component of a participatory space."
|
8
8
|
|
9
|
-
field :
|
9
|
+
field :meeting, Decidim::Meetings::MeetingType, "A single Meeting object", null: true do
|
10
|
+
argument :id, GraphQL::Types::ID, "The id of the Meeting requested", required: true
|
11
|
+
end
|
12
|
+
field :meetings, Decidim::Meetings::MeetingType.connection_type, "A collection of Meetings", null: true, connection: true
|
10
13
|
|
11
14
|
def meetings
|
12
15
|
Meeting.published.visible.where(component: object).includes(:component)
|
13
16
|
end
|
14
17
|
|
15
|
-
field :meeting, Decidim::Meetings::MeetingType, null: true do
|
16
|
-
argument :id, GraphQL::Types::ID, required: true
|
17
|
-
end
|
18
|
-
|
19
18
|
def meeting(**args)
|
20
19
|
Meeting.published.visible.where(component: object).find_by(id: args[:id])
|
21
20
|
end
|
@@ -6,8 +6,8 @@ module Decidim
|
|
6
6
|
graphql_name "MeetingService"
|
7
7
|
description "A meeting service"
|
8
8
|
|
9
|
-
field :title, Decidim::Core::TranslatedFieldType, "The title for the service", null: true
|
10
9
|
field :description, Decidim::Core::TranslatedFieldType, "The description for the service", null: true
|
10
|
+
field :title, Decidim::Core::TranslatedFieldType, "The title for the service", null: true
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -18,13 +18,20 @@ module Decidim
|
|
18
18
|
member do
|
19
19
|
put :publish
|
20
20
|
put :unpublish
|
21
|
+
patch :soft_delete
|
22
|
+
patch :restore
|
21
23
|
end
|
22
24
|
resources :meeting_closes, only: [:edit, :update] do
|
23
25
|
get :proposals_picker, on: :collection
|
24
26
|
end
|
25
27
|
resource :registrations, only: [:edit, :update] do
|
26
28
|
resources :invites, only: [:index, :create]
|
27
|
-
resource :form, only: [:edit, :update], controller: "registration_form"
|
29
|
+
resource :form, only: [:edit, :update], controller: "registration_form" do
|
30
|
+
member do
|
31
|
+
get :edit_questions
|
32
|
+
patch :update_questions
|
33
|
+
end
|
34
|
+
end
|
28
35
|
collection do
|
29
36
|
get :export
|
30
37
|
post :validate_registration_code
|
@@ -35,6 +42,7 @@ module Decidim
|
|
35
42
|
resources :attachments, except: [:show]
|
36
43
|
resources :copies, controller: "meeting_copies", only: [:new, :create]
|
37
44
|
resource :poll, only: [:edit, :update], controller: "meetings_poll"
|
45
|
+
get :manage_trash, on: :collection
|
38
46
|
end
|
39
47
|
root to: "meetings#index"
|
40
48
|
end
|
@@ -8,7 +8,11 @@ Decidim.register_component(:meetings) do |component|
|
|
8
8
|
component.permissions_class_name = "Decidim::Meetings::Permissions"
|
9
9
|
|
10
10
|
component.query_type = "Decidim::Meetings::MeetingsType"
|
11
|
-
component.data_portable_entities = [
|
11
|
+
component.data_portable_entities = [
|
12
|
+
"Decidim::Meetings::Registration",
|
13
|
+
"Decidim::Meetings::Invite",
|
14
|
+
"Decidim::Meetings::Meeting"
|
15
|
+
]
|
12
16
|
|
13
17
|
component.on(:before_destroy) do |instance|
|
14
18
|
raise StandardError, "Cannot remove this component" if Decidim::Meetings::Meeting.where(component: instance).any?
|
@@ -38,13 +42,20 @@ Decidim.register_component(:meetings) do |component|
|
|
38
42
|
meetings.sum(:comments_count)
|
39
43
|
end
|
40
44
|
|
45
|
+
component.register_stat :attendees_count, primary: true, priority: Decidim::StatsRegistry::MEDIUM_PRIORITY do |components, start_at, end_at|
|
46
|
+
meetings = Decidim::Meetings::Meeting.closed.not_hidden.published.where(component: components, closing_visible: true)
|
47
|
+
meetings = meetings.where(closed_at: start_at..) if start_at.present?
|
48
|
+
meetings = meetings.where(closed_at: ..end_at) if end_at.present?
|
49
|
+
meetings.sum(:attendees_count)
|
50
|
+
end
|
51
|
+
|
41
52
|
component.exports :meetings do |exports|
|
42
53
|
exports.collection do |component_instance|
|
43
54
|
Decidim::Meetings::Meeting
|
44
55
|
.not_hidden
|
45
56
|
.visible
|
46
57
|
.where(component: component_instance)
|
47
|
-
.includes(:
|
58
|
+
.includes(:taxonomies, :attachments, component: { participatory_space: :organization })
|
48
59
|
end
|
49
60
|
|
50
61
|
exports.include_in_open_data = true
|
@@ -77,8 +88,7 @@ Decidim.register_component(:meetings) do |component|
|
|
77
88
|
component.actions = %w(join comment)
|
78
89
|
|
79
90
|
component.settings(:global) do |settings|
|
80
|
-
settings.attribute :
|
81
|
-
settings.attribute :scope_id, type: :scope
|
91
|
+
settings.attribute :taxonomy_filters, type: :taxonomy_filters
|
82
92
|
settings.attribute :announcement, type: :text, translated: true, editor: true
|
83
93
|
settings.attribute :default_registration_terms, type: :text, translated: true, editor: true
|
84
94
|
settings.attribute :comments_enabled, type: :boolean, default: true
|
@@ -8,16 +8,16 @@ module Decidim
|
|
8
8
|
def serialize
|
9
9
|
{
|
10
10
|
id: resource.id,
|
11
|
-
user: {
|
12
|
-
name: resource.user.name,
|
13
|
-
email: resource.user.email
|
14
|
-
},
|
15
11
|
questionnaire: {
|
16
|
-
id: resource.question.questionnaire.id
|
12
|
+
id: resource.question.questionnaire.id,
|
13
|
+
title: translated_attribute(resource.question.questionnaire.title),
|
14
|
+
description: translated_attribute(resource.question.questionnaire.description),
|
15
|
+
tos: translated_attribute(resource.question.questionnaire.tos)
|
17
16
|
},
|
18
17
|
question: {
|
19
18
|
id: resource.question.id,
|
20
|
-
body: translated_attribute(resource.question.body)
|
19
|
+
body: translated_attribute(resource.question.body),
|
20
|
+
description: translated_attribute(resource.question.description)
|
21
21
|
},
|
22
22
|
answer: normalize_body(resource)
|
23
23
|
}
|
@@ -26,7 +26,13 @@ module Decidim
|
|
26
26
|
private
|
27
27
|
|
28
28
|
def normalize_body(resource)
|
29
|
-
resource.choices.pluck(:body)
|
29
|
+
attachments_for(resource) || resource.body || resource.choices.pluck(:body)
|
30
|
+
end
|
31
|
+
|
32
|
+
def attachments_for(resource)
|
33
|
+
return if resource.attachments.blank?
|
34
|
+
|
35
|
+
resource.attachments.map(&:url)
|
30
36
|
end
|
31
37
|
end
|
32
38
|
end
|
@@ -8,63 +8,77 @@ module Decidim
|
|
8
8
|
include Decidim::ApplicationHelper
|
9
9
|
include Decidim::ResourceHelper
|
10
10
|
|
11
|
-
# Public: Initializes the serializer with a meeting.
|
12
|
-
def initialize(meeting)
|
13
|
-
@meeting = meeting
|
14
|
-
end
|
15
|
-
|
16
11
|
# Public: Exports a hash with the serialized data for this meeting.
|
17
12
|
def serialize
|
18
13
|
{
|
19
|
-
id:
|
20
|
-
category: {
|
21
|
-
id: meeting.category.try(:id),
|
22
|
-
name: meeting.category.try(:name)
|
23
|
-
},
|
24
|
-
scope: {
|
25
|
-
id: meeting.scope.try(:id),
|
26
|
-
name: meeting.scope.try(:name)
|
27
|
-
},
|
14
|
+
id: resource.id,
|
28
15
|
author: {
|
29
16
|
**author_fields
|
30
17
|
},
|
31
18
|
participatory_space: {
|
32
|
-
id:
|
33
|
-
url: Decidim::ResourceLocatorPresenter.new(
|
19
|
+
id: resource.participatory_space.id,
|
20
|
+
url: Decidim::ResourceLocatorPresenter.new(resource.participatory_space).url
|
34
21
|
},
|
22
|
+
taxonomies:,
|
35
23
|
component: { id: component.id },
|
36
|
-
title:
|
37
|
-
description:
|
38
|
-
start_time:
|
39
|
-
end_time:
|
40
|
-
attendees:
|
41
|
-
contributions:
|
42
|
-
organizations:
|
43
|
-
address:
|
44
|
-
location:
|
45
|
-
reference:
|
46
|
-
|
47
|
-
attachments: meeting.attachments.size,
|
48
|
-
followers: meeting.follows.size,
|
24
|
+
title: resource.title,
|
25
|
+
description: resource.description,
|
26
|
+
start_time: resource.start_time,
|
27
|
+
end_time: resource.end_time,
|
28
|
+
attendees: resource.attendees_count.to_i,
|
29
|
+
contributions: resource.contributions_count.to_i,
|
30
|
+
organizations: resource.attending_organizations,
|
31
|
+
address: resource.address,
|
32
|
+
location: include_location? ? resource.location : nil,
|
33
|
+
reference: resource.reference,
|
34
|
+
attachments: resource.attachments.size,
|
49
35
|
url:,
|
50
36
|
related_proposals:,
|
51
37
|
related_results:,
|
52
|
-
published:
|
53
|
-
withdrawn:
|
54
|
-
withdrawn_at:
|
38
|
+
published: resource.published_at.present?,
|
39
|
+
withdrawn: resource.withdrawn?,
|
40
|
+
withdrawn_at: resource.withdrawn_at,
|
41
|
+
location_hints: resource.location_hints,
|
42
|
+
created_at: resource.created_at,
|
43
|
+
updated_at: resource.updated_at,
|
44
|
+
latitude: resource.latitude,
|
45
|
+
longitude: resource.longitude,
|
46
|
+
follows_count: resource.follows_count,
|
47
|
+
private_meeting: resource.private_meeting,
|
48
|
+
transparent: resource.transparent,
|
49
|
+
registration_form_enabled: resource.registration_form_enabled,
|
50
|
+
comments: {
|
51
|
+
**comment_fields
|
52
|
+
},
|
53
|
+
online_meeting_url: resource.online_meeting_url,
|
54
|
+
closing_visible: resource.closing_visible,
|
55
|
+
closing_report: resource.closing_report,
|
56
|
+
attending_organizations: resource.attending_organizations,
|
57
|
+
registration_url: resource.registration_url,
|
58
|
+
decidim_user_group_id: resource.decidim_user_group_id,
|
59
|
+
decidim_author_type: resource.decidim_author_type,
|
60
|
+
video_url: resource.video_url,
|
61
|
+
audio_url: resource.audio_url,
|
62
|
+
closed_at: resource.closed_at,
|
63
|
+
registration_terms: resource.registration_terms,
|
64
|
+
available_slots: resource.available_slots,
|
65
|
+
registrations_enabled: resource.registrations_enabled,
|
66
|
+
customize_registration_email: resource.customize_registration_email,
|
67
|
+
type_of_meeting: resource.type_of_meeting,
|
68
|
+
iframe_access_level: resource.iframe_access_level,
|
69
|
+
iframe_embed_type: resource.iframe_embed_type,
|
70
|
+
reserved_slots: resource.reserved_slots,
|
71
|
+
registration_type: resource.registration_type
|
55
72
|
}
|
56
73
|
end
|
57
74
|
|
58
75
|
private
|
59
76
|
|
60
|
-
attr_reader :meeting
|
61
|
-
alias resource meeting
|
62
|
-
|
63
77
|
def author_fields
|
64
78
|
{
|
65
|
-
id:
|
66
|
-
name: author_name(
|
67
|
-
url: author_url(
|
79
|
+
id: resource.author.id,
|
80
|
+
name: author_name(resource.author),
|
81
|
+
url: author_url(resource.author)
|
68
82
|
}
|
69
83
|
end
|
70
84
|
|
@@ -80,38 +94,35 @@ module Decidim
|
|
80
94
|
end
|
81
95
|
end
|
82
96
|
|
83
|
-
def profile_url(author)
|
84
|
-
return "" if author.respond_to?(:deleted?) && author.deleted?
|
85
|
-
|
86
|
-
Decidim::Core::Engine.routes.url_helpers.profile_url(author.nickname, host:)
|
87
|
-
end
|
88
|
-
|
89
|
-
def root_url
|
90
|
-
Decidim::Core::Engine.routes.url_helpers.root_url(host:)
|
91
|
-
end
|
92
|
-
|
93
|
-
def host
|
94
|
-
resource.organization.host
|
95
|
-
end
|
96
|
-
|
97
|
-
def component
|
98
|
-
meeting.component
|
99
|
-
end
|
100
|
-
|
101
97
|
def related_proposals
|
102
|
-
|
98
|
+
resource.linked_resources(:proposals, "proposals_from_meeting").map do |proposal|
|
103
99
|
Decidim::ResourceLocatorPresenter.new(proposal).url
|
104
100
|
end
|
105
101
|
end
|
106
102
|
|
107
103
|
def related_results
|
108
|
-
|
104
|
+
resource.linked_resources(:results, "meetings_through_proposals").map do |result|
|
109
105
|
Decidim::ResourceLocatorPresenter.new(result).url
|
110
106
|
end
|
111
107
|
end
|
112
108
|
|
113
109
|
def url
|
114
|
-
Decidim::ResourceLocatorPresenter.new(
|
110
|
+
Decidim::ResourceLocatorPresenter.new(resource).url
|
111
|
+
end
|
112
|
+
|
113
|
+
def comment_fields
|
114
|
+
return {} unless resource.comments
|
115
|
+
|
116
|
+
{
|
117
|
+
start_time: resource.comments_start_time,
|
118
|
+
end_time: resource.comments_end_time,
|
119
|
+
enabled: resource.comments_enabled,
|
120
|
+
count: resource.comments_count
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
def include_location?
|
125
|
+
resource.iframe_access_level == "all"
|
115
126
|
end
|
116
127
|
end
|
117
128
|
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Meetings
|
5
|
+
class SchemaOrgEventMeetingSerializer < Decidim::Exporters::Serializer
|
6
|
+
include Decidim::TranslationsHelper
|
7
|
+
include Decidim::SanitizeHelper
|
8
|
+
include ActionView::Helpers::UrlHelper
|
9
|
+
|
10
|
+
# Public: Initializes the serializer with a meeting.
|
11
|
+
def initialize(meeting)
|
12
|
+
@meeting = meeting
|
13
|
+
end
|
14
|
+
|
15
|
+
# Serializes a meeting for the Schema.org Event type
|
16
|
+
#
|
17
|
+
# @see https://schema.org/Event
|
18
|
+
# @see https://developers.google.com/search/docs/appearance/structured-data/event?hl=en
|
19
|
+
def serialize
|
20
|
+
attributes = {
|
21
|
+
"@context": "https://schema.org",
|
22
|
+
"@type": "Event",
|
23
|
+
name: decidim_escape_translated(meeting.title),
|
24
|
+
description: decidim_escape_translated(meeting.description),
|
25
|
+
startDate: meeting.start_time.iso8601,
|
26
|
+
endDate: meeting.end_time.iso8601,
|
27
|
+
organizer:,
|
28
|
+
eventAttendanceMode: event_attendance_mode,
|
29
|
+
eventStatus: "https://schema.org/EventScheduled",
|
30
|
+
location:
|
31
|
+
}
|
32
|
+
|
33
|
+
attributes = attributes.merge(image:) if meeting.photos.any?
|
34
|
+
attributes
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :meeting
|
40
|
+
alias resource meeting
|
41
|
+
|
42
|
+
def organizer
|
43
|
+
return organizer_user_group if meeting.decidim_user_group_id?
|
44
|
+
|
45
|
+
case meeting.author.class.name
|
46
|
+
when "Decidim::Organization"
|
47
|
+
organizer_organization
|
48
|
+
when "Decidim::User"
|
49
|
+
organizer_user
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def organizer_user_group
|
54
|
+
{
|
55
|
+
"@type": "Organization",
|
56
|
+
name: meeting.author.name,
|
57
|
+
url: profile_url(meeting.user_group)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def organizer_organization
|
62
|
+
{
|
63
|
+
"@type": "Organization",
|
64
|
+
name: decidim_escape_translated(meeting.author.name),
|
65
|
+
url: EngineRouter.new("decidim", router_options).root_url
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def organizer_user
|
70
|
+
{
|
71
|
+
"@type": "Person",
|
72
|
+
name: decidim_escape_translated(meeting.author.name),
|
73
|
+
url: profile_url(meeting.author)
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def router_options = { host: meeting.organization.host }
|
78
|
+
|
79
|
+
def event_attendance_mode
|
80
|
+
case meeting.type_of_meeting
|
81
|
+
when "online"
|
82
|
+
"https://schema.org/OnlineEventAttendanceMode"
|
83
|
+
when "hybrid"
|
84
|
+
"https://schema.org/MixedEventAttendanceMode"
|
85
|
+
else
|
86
|
+
"https://schema.org/OfflineEventAttendanceMode"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def location
|
91
|
+
case meeting.type_of_meeting
|
92
|
+
when "online"
|
93
|
+
location_virtual
|
94
|
+
when "hybrid"
|
95
|
+
[location_postal_address, location_virtual]
|
96
|
+
else
|
97
|
+
location_postal_address
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def location_postal_address
|
102
|
+
address = {
|
103
|
+
"@type": "PostalAddress",
|
104
|
+
streetAddress: decidim_escape_translated(meeting.address)
|
105
|
+
}
|
106
|
+
|
107
|
+
address = address.merge({ addressLocality: geocoder_city }) if geocoder_city.present?
|
108
|
+
address = address.merge({ addressRegion: geocoder_state }) if geocoder_state.present?
|
109
|
+
address = address.merge({ postalCode: geocoder_postal_code }) if geocoder_postal_code.present?
|
110
|
+
address = address.merge({ addressCountry: geocoder_country }) if geocoder_country.present?
|
111
|
+
|
112
|
+
{
|
113
|
+
"@type": "Place",
|
114
|
+
name: decidim_escape_translated(meeting.location),
|
115
|
+
address:
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
def location_virtual
|
120
|
+
{
|
121
|
+
"@type": "VirtualLocation",
|
122
|
+
url: meeting.online_meeting_url
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
def geocoder
|
127
|
+
return if meeting.latitude.blank? || meeting.longitude.blank?
|
128
|
+
|
129
|
+
@geocoder ||= Geocoder.search([meeting.latitude, meeting.longitude]).first
|
130
|
+
end
|
131
|
+
|
132
|
+
def geocoder_city
|
133
|
+
@geocoder_city ||= geocoder&.city
|
134
|
+
end
|
135
|
+
|
136
|
+
def geocoder_state
|
137
|
+
@geocoder_state ||= geocoder&.state
|
138
|
+
end
|
139
|
+
|
140
|
+
def geocoder_postal_code
|
141
|
+
@geocoder_postal_code ||= geocoder&.postal_code
|
142
|
+
end
|
143
|
+
|
144
|
+
def geocoder_country
|
145
|
+
@geocoder_country ||= geocoder&.country
|
146
|
+
end
|
147
|
+
|
148
|
+
def image = meeting.photos.map(&:thumbnail_url)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -63,14 +63,12 @@ module Decidim
|
|
63
63
|
|
64
64
|
params = {
|
65
65
|
component:,
|
66
|
-
scope: random_scope(participatory_space:),
|
67
|
-
category: participatory_space.categories.sample,
|
68
66
|
title: Decidim::Faker::Localized.sentence(word_count: 2),
|
69
67
|
description: Decidim::Faker::Localized.wrapped("<p>", "</p>") do
|
70
68
|
Decidim::Faker::Localized.paragraph(sentence_count: 3)
|
71
69
|
end,
|
72
|
-
location: Decidim::Faker::Localized.sentence,
|
73
|
-
location_hints: Decidim::Faker::Localized.sentence,
|
70
|
+
location: Decidim::Faker::Localized.sentence(word_count: rand(2..20)),
|
71
|
+
location_hints: Decidim::Faker::Localized.sentence(word_count: rand(2..20)),
|
74
72
|
start_time:,
|
75
73
|
end_time:,
|
76
74
|
address: "#{::Faker::Address.street_address} #{::Faker::Address.zip} #{::Faker::Address.city}",
|
@@ -47,6 +47,7 @@ FactoryBot.define do
|
|
47
47
|
component { build(:meeting_component) }
|
48
48
|
iframe_access_level { :all }
|
49
49
|
iframe_embed_type { :none }
|
50
|
+
deleted_at { nil }
|
50
51
|
|
51
52
|
author do
|
52
53
|
component.try(:organization)
|
@@ -73,6 +74,8 @@ FactoryBot.define do
|
|
73
74
|
trait :online do
|
74
75
|
type_of_meeting { :online }
|
75
76
|
online_meeting_url { "https://decidim.org" }
|
77
|
+
latitude { nil }
|
78
|
+
longitude { nil }
|
76
79
|
end
|
77
80
|
|
78
81
|
trait :hybrid do
|
@@ -183,6 +186,11 @@ FactoryBot.define do
|
|
183
186
|
end
|
184
187
|
end
|
185
188
|
|
189
|
+
factory :meeting_link, class: "Decidim::Meetings::MeetingLink" do
|
190
|
+
meeting
|
191
|
+
component
|
192
|
+
end
|
193
|
+
|
186
194
|
factory :registration, class: "Decidim::Meetings::Registration" do
|
187
195
|
transient do
|
188
196
|
skip_injection { false }
|
@@ -4,17 +4,17 @@ shared_examples_for "a translated meeting event" do
|
|
4
4
|
describe "translated notifications" do
|
5
5
|
let(:en_body) { "This is Sparta!" }
|
6
6
|
let(:body) { { en: en_body, machine_translations: { ca: "C'est Sparta!" } } }
|
7
|
-
let(:participatory_process) { create
|
7
|
+
let(:participatory_process) { create(:participatory_process, organization:) }
|
8
8
|
let(:meeting_component) { create(:meeting_component, participatory_space: participatory_process) }
|
9
9
|
let(:translatable) { true }
|
10
10
|
let(:en_version) { resource.description["en"] }
|
11
11
|
let(:machine_translated) { resource.description["machine_translations"]["ca"] }
|
12
12
|
|
13
13
|
let(:resource) do
|
14
|
-
create
|
14
|
+
create(:meeting,
|
15
15
|
component: meeting_component,
|
16
16
|
title: { en: "A nice event", machine_translations: { ca: "Une belle event" } },
|
17
|
-
description: body
|
17
|
+
description: body)
|
18
18
|
end
|
19
19
|
|
20
20
|
it_behaves_like "a translated event"
|
data/lib/decidim/meetings.rb
CHANGED
@@ -16,6 +16,7 @@ module Decidim
|
|
16
16
|
autoload :MeetingSerializer, "decidim/meetings/meeting_serializer"
|
17
17
|
autoload :UserAnswersSerializer, "decidim/meetings/user_answers_serializer"
|
18
18
|
autoload :DownloadYourDataUserAnswersSerializer, "decidim/meetings/download_your_data_user_answers_serializer"
|
19
|
+
autoload :SchemaOrgEventMeetingSerializer, "decidim/meetings/schema_org_event_meeting_serializer"
|
19
20
|
|
20
21
|
include ActiveSupport::Configurable
|
21
22
|
|