decidim-meetings 0.26.9 → 0.27.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/content_blocks/highlighted_meetings_cell.rb +1 -1
- data/app/cells/decidim/meetings/content_blocks/upcoming_meetings/show.erb +2 -2
- data/app/cells/decidim/meetings/content_blocks/upcoming_meetings_cell.rb +4 -12
- data/app/cells/decidim/meetings/highlighted_meetings_for_component_cell.rb +10 -1
- data/app/cells/decidim/meetings/meeting_list_item_cell.rb +1 -1
- data/app/cells/decidim/meetings/meeting_m_cell.rb +1 -1
- data/app/cells/decidim/meetings/meeting_s_cell.rb +6 -0
- data/app/commands/decidim/meetings/admin/close_meeting.rb +1 -1
- data/app/commands/decidim/meetings/admin/copy_meeting.rb +5 -24
- data/app/commands/decidim/meetings/admin/create_agenda.rb +1 -1
- data/app/commands/decidim/meetings/admin/create_meeting.rb +1 -5
- data/app/commands/decidim/meetings/admin/destroy_meeting.rb +1 -1
- data/app/commands/decidim/meetings/admin/export_meeting_registrations.rb +1 -1
- data/app/commands/decidim/meetings/admin/invite_user_to_join_meeting.rb +9 -11
- data/app/commands/decidim/meetings/admin/publish_meeting.rb +2 -2
- data/app/commands/decidim/meetings/admin/unpublish_meeting.rb +1 -1
- data/app/commands/decidim/meetings/admin/update_agenda.rb +1 -1
- data/app/commands/decidim/meetings/admin/update_meeting.rb +1 -5
- data/app/commands/decidim/meetings/admin/update_question_status.rb +1 -1
- data/app/commands/decidim/meetings/admin/update_questionnaire.rb +10 -7
- data/app/commands/decidim/meetings/admin/update_registrations.rb +5 -3
- data/app/commands/decidim/meetings/admin/validate_registration_code.rb +1 -1
- data/app/commands/decidim/meetings/close_meeting.rb +1 -1
- data/app/commands/decidim/meetings/create_answer.rb +1 -1
- data/app/commands/decidim/meetings/create_meeting.rb +1 -1
- data/app/commands/decidim/meetings/decline_invitation.rb +1 -1
- data/app/commands/decidim/meetings/join_meeting.rb +6 -7
- data/app/commands/decidim/meetings/leave_meeting.rb +3 -3
- data/app/commands/decidim/meetings/update_meeting.rb +1 -1
- data/app/commands/decidim/meetings/withdraw_meeting.rb +1 -1
- data/app/controllers/concerns/decidim/meetings/admin/filterable.rb +4 -4
- data/app/controllers/concerns/decidim/meetings/filterable.rb +1 -7
- data/app/controllers/decidim/meetings/admin/meeting_copies_controller.rb +2 -2
- data/app/controllers/decidim/meetings/calendars_controller.rb +1 -1
- data/app/controllers/decidim/meetings/directory/meetings_controller.rb +17 -16
- data/app/controllers/decidim/meetings/meetings_controller.rb +21 -15
- data/app/events/decidim/meetings/meeting_registration_notification_event.rb +1 -1
- data/app/forms/decidim/meetings/admin/close_meeting_form.rb +1 -1
- data/app/forms/decidim/meetings/admin/meeting_copy_form.rb +51 -0
- data/app/forms/decidim/meetings/admin/meeting_form.rb +11 -15
- data/app/forms/decidim/meetings/admin/meeting_registration_invite_form.rb +1 -1
- data/app/forms/decidim/meetings/admin/meeting_registrations_form.rb +3 -0
- data/app/forms/decidim/meetings/answer_form.rb +0 -1
- data/app/forms/decidim/meetings/close_meeting_form.rb +1 -1
- data/app/forms/decidim/meetings/meeting_form.rb +2 -2
- data/app/helpers/decidim/meetings/application_helper.rb +10 -19
- data/app/helpers/decidim/meetings/directory/application_helper.rb +8 -6
- data/app/helpers/decidim/meetings/meetings_helper.rb +1 -3
- data/app/jobs/decidim/meetings/send_close_meeting_reminder_job.rb +17 -0
- data/app/mailers/decidim/meetings/close_meeting_reminder_mailer.rb +43 -0
- data/app/models/decidim/meetings/agenda_item.rb +1 -1
- data/app/models/decidim/meetings/answer.rb +2 -2
- data/app/models/decidim/meetings/invite.rb +2 -2
- data/app/models/decidim/meetings/meeting.rb +36 -21
- data/app/models/decidim/meetings/questionnaire.rb +6 -0
- data/app/models/decidim/meetings/registration.rb +2 -2
- data/app/packs/src/decidim/meetings/admin/meetings_form.js +0 -4
- data/app/packs/src/decidim/meetings/admin/registrations_form.js +2 -0
- data/app/presenters/decidim/meetings/admin_log/questionnaire_presenter.rb +39 -0
- data/app/presenters/decidim/meetings/meeting_presenter.rb +6 -1
- data/app/queries/decidim/meetings/admin/invites.rb +1 -1
- data/app/queries/decidim/meetings/filtered_meetings.rb +1 -1
- data/app/queries/decidim/meetings/questionnaire_user_answers.rb +1 -1
- data/app/serializers/decidim/meetings/{data_portability_invite_serializer.rb → download_your_data_invite_serializer.rb} +2 -2
- data/app/serializers/decidim/meetings/{data_portability_registration_serializer.rb → download_your_data_registration_serializer.rb} +2 -2
- data/app/services/decidim/meetings/calendar/base_calendar.rb +4 -3
- data/app/services/decidim/meetings/calendar/component_calendar.rb +7 -9
- data/app/services/decidim/meetings/calendar/organization_calendar.rb +1 -1
- data/app/services/decidim/meetings/calendar_renderer.rb +4 -4
- data/app/services/decidim/meetings/close_meeting_reminder_generator.rb +68 -0
- data/app/services/decidim/meetings/meeting_iframe_embedder.rb +10 -6
- data/app/services/decidim/meetings/meeting_search.rb +7 -53
- data/app/views/decidim/meetings/_calendar_modal.html.erb +19 -2
- data/app/views/decidim/meetings/admin/meeting_copies/_form.html.erb +64 -0
- data/app/views/decidim/meetings/admin/meeting_copies/new.html.erb +1 -1
- data/app/views/decidim/meetings/admin/meetings/_form.html.erb +5 -17
- data/app/views/decidim/meetings/admin/meetings/edit.html.erb +0 -1
- data/app/views/decidim/meetings/admin/meetings/index.html.erb +1 -2
- data/app/views/decidim/meetings/admin/meetings/new.html.erb +0 -1
- data/app/views/decidim/meetings/admin/registrations/_form.html.erb +10 -1
- data/app/views/decidim/meetings/close_meeting_reminder_mailer/close_meeting_reminder.html.erb +5 -0
- data/app/views/decidim/meetings/directory/meetings/_filters.html.erb +7 -7
- data/app/views/decidim/meetings/directory/meetings/_meetings.html.erb +6 -1
- data/app/views/decidim/meetings/directory/meetings/index.html.erb +1 -1
- data/app/views/decidim/meetings/directory/meetings/index.js.erb +7 -1
- data/app/views/decidim/meetings/layouts/live_event.html.erb +6 -2
- data/app/views/decidim/meetings/meetings/_count.html.erb +1 -1
- data/app/views/decidim/meetings/meetings/_filters.html.erb +7 -7
- data/app/views/decidim/meetings/meetings/_form.html.erb +4 -2
- data/app/views/decidim/meetings/meetings/_linked_meetings.html.erb +1 -1
- data/app/views/decidim/meetings/meetings/_meetings.html.erb +11 -6
- data/app/views/decidim/meetings/meetings/index.html.erb +3 -3
- data/app/views/decidim/meetings/meetings/index.js.erb +2 -2
- data/app/views/decidim/participatory_spaces/_conference_venues.html.erb +0 -3
- data/config/locales/am-ET.yml +1 -0
- data/config/locales/ar.yml +12 -258
- data/config/locales/bg.yml +7 -0
- data/config/locales/ca.yml +39 -34
- data/config/locales/cs.yml +40 -35
- data/config/locales/da.yml +1 -0
- data/config/locales/de.yml +24 -109
- data/config/locales/el.yml +12 -229
- data/config/locales/en.yml +33 -29
- data/config/locales/eo.yml +1 -0
- data/config/locales/es-MX.yml +42 -37
- data/config/locales/es-PY.yml +39 -34
- data/config/locales/es.yml +41 -36
- data/config/locales/et.yml +1 -0
- data/config/locales/eu.yml +208 -253
- data/config/locales/fi-plain.yml +42 -35
- data/config/locales/fi.yml +53 -46
- data/config/locales/fr-CA.yml +38 -33
- data/config/locales/fr.yml +37 -32
- data/config/locales/ga-IE.yml +8 -12
- data/config/locales/gl.yml +32 -6
- data/config/locales/hr.yml +1 -0
- data/config/locales/hu.yml +24 -149
- data/config/locales/id-ID.yml +12 -4
- data/config/locales/is-IS.yml +9 -10
- data/config/locales/it.yml +24 -20
- data/config/locales/ja.yml +43 -36
- data/config/locales/ko.yml +1 -0
- data/config/locales/lb.yml +21 -18
- data/config/locales/lt.yml +1 -681
- data/config/locales/lv.yml +12 -4
- data/config/locales/mt.yml +1 -0
- data/config/locales/nl.yml +68 -90
- data/config/locales/no.yml +21 -14
- data/config/locales/om-ET.yml +1 -0
- data/config/locales/pl.yml +16 -41
- data/config/locales/pt-BR.yml +17 -64
- data/config/locales/pt.yml +18 -16
- data/config/locales/ro-RO.yml +27 -44
- data/config/locales/ru.yml +13 -7
- data/config/locales/si-LK.yml +1 -0
- data/config/locales/sk.yml +13 -5
- data/config/locales/sl.yml +4 -3
- data/config/locales/so-SO.yml +1 -0
- data/config/locales/sr-CS.yml +1 -0
- data/config/locales/sv.yml +26 -25
- data/config/locales/sw-KE.yml +1 -0
- data/config/locales/ti-ER.yml +1 -0
- data/config/locales/tr-TR.yml +14 -18
- data/config/locales/uk.yml +13 -7
- data/config/locales/val-ES.yml +1 -0
- data/config/locales/vi.yml +1 -0
- data/config/locales/zh-CN.yml +12 -12
- data/config/locales/zh-TW.yml +1 -649
- data/db/migrate/20210512100333_drop_decidim_meetings_minutes_table.rb +2 -2
- data/db/migrate/20210518133236_merge_minutes_with_closing_report_in_meetings_table.rb +1 -1
- data/db/migrate/20211105115625_remove_not_null_on_customize_registration_email.rb +7 -0
- data/lib/decidim/api/meeting_type.rb +1 -1
- data/lib/decidim/meetings/component.rb +7 -7
- data/lib/decidim/meetings/{data_portability_user_answers_serializer.rb → download_your_data_user_answers_serializer.rb} +2 -2
- data/lib/decidim/meetings/engine.rb +17 -4
- data/lib/decidim/meetings/meeting_serializer.rb +2 -2
- data/lib/decidim/meetings/test/factories.rb +3 -1
- data/lib/decidim/meetings/test/notifications_handling.rb +1 -1
- data/lib/decidim/meetings/test/translated_event.rb +2 -2
- data/lib/decidim/meetings/user_answers_serializer.rb +1 -1
- data/lib/decidim/meetings/version.rb +1 -1
- data/lib/decidim/meetings.rb +5 -1
- metadata +29 -31
- data/app/services/decidim/meetings/directory/meeting_search.rb +0 -53
- data/config/environment.rb +0 -3
- data/config/locales/fa-IR.yml +0 -1
- data/config/locales/gn-PY.yml +0 -1
- data/config/locales/ka-GE.yml +0 -1
- data/config/locales/kaa.yml +0 -7
- data/config/locales/lo-LA.yml +0 -1
- data/config/locales/oc-FR.yml +0 -1
- data/config/locales/sq-AL.yml +0 -1
- data/config/locales/th-TH.yml +0 -1
@@ -4,6 +4,8 @@ module Decidim
|
|
4
4
|
module Meetings
|
5
5
|
# The data store for a Questionnaire in the Decidim::Meetings component.
|
6
6
|
class Questionnaire < Meetings::ApplicationRecord
|
7
|
+
include Decidim::Traceable
|
8
|
+
|
7
9
|
belongs_to :questionnaire_for, polymorphic: true
|
8
10
|
|
9
11
|
has_many :questions, -> { order(:position) }, class_name: "Question", foreign_key: "decidim_questionnaire_id", dependent: :destroy
|
@@ -18,6 +20,10 @@ module Decidim
|
|
18
20
|
def all_questions_unpublished?
|
19
21
|
questions.all?(&:unpublished?)
|
20
22
|
end
|
23
|
+
|
24
|
+
def self.log_presenter_class_for(_log)
|
25
|
+
Decidim::Meetings::AdminLog::QuestionnairePresenter
|
26
|
+
end
|
21
27
|
end
|
22
28
|
end
|
23
29
|
end
|
@@ -4,7 +4,7 @@ module Decidim
|
|
4
4
|
module Meetings
|
5
5
|
# The data store for a Registration in the Decidim::Meetings component.
|
6
6
|
class Registration < Meetings::ApplicationRecord
|
7
|
-
include Decidim::
|
7
|
+
include Decidim::DownloadYourData
|
8
8
|
|
9
9
|
belongs_to :meeting, foreign_key: "decidim_meeting_id", class_name: "Decidim::Meetings::Meeting"
|
10
10
|
belongs_to :user, foreign_key: "decidim_user_id", class_name: "Decidim::User"
|
@@ -23,7 +23,7 @@ module Decidim
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def self.export_serializer
|
26
|
-
Decidim::Meetings::
|
26
|
+
Decidim::Meetings::DownloadYourDataRegistrationSerializer
|
27
27
|
end
|
28
28
|
|
29
29
|
# Pluck all Decidim::UserGroup ID's
|
@@ -102,9 +102,7 @@ $(() => {
|
|
102
102
|
attachGeocoding($form.find("#meeting_address"));
|
103
103
|
|
104
104
|
const $meetingRegistrationType = $form.find("#meeting_registration_type");
|
105
|
-
const $meetingRegistrationTerms = $form.find("#meeting_registration_terms");
|
106
105
|
const $meetingRegistrationUrl = $form.find("#meeting_registration_url");
|
107
|
-
const $meetingAvailableSlots = $form.find("#meeting_available_slots");
|
108
106
|
|
109
107
|
const toggleDependsOnSelect = ($target, $showDiv, type) => {
|
110
108
|
const value = $target.val();
|
@@ -113,8 +111,6 @@ $(() => {
|
|
113
111
|
|
114
112
|
$meetingRegistrationType.on("change", (ev) => {
|
115
113
|
const $target = $(ev.target);
|
116
|
-
toggleDependsOnSelect($target, $meetingAvailableSlots, "on_this_platform");
|
117
|
-
toggleDependsOnSelect($target, $meetingRegistrationTerms, "on_this_platform");
|
118
114
|
toggleDependsOnSelect($target, $meetingRegistrationUrl, "on_different_platform");
|
119
115
|
});
|
120
116
|
|
@@ -5,11 +5,13 @@ $(() => {
|
|
5
5
|
const $registrationsEnabled = $form.find("#meeting_registrations_enabled");
|
6
6
|
const $availableSlots = $form.find("#meeting_available_slots");
|
7
7
|
const $reservedSlots = $form.find("#meeting_reserved_slots");
|
8
|
+
const $customizeRegistrationEmail = $form.find("#meeting_customize_registration_email");
|
8
9
|
|
9
10
|
const toggleDisabledFields = () => {
|
10
11
|
const enabled = $registrationsEnabled.prop("checked");
|
11
12
|
$availableSlots.attr("disabled", !enabled);
|
12
13
|
$reservedSlots.attr("disabled", !enabled);
|
14
|
+
$customizeRegistrationEmail.attr("disabled", !enabled);
|
13
15
|
|
14
16
|
$form.find(".editor-container").each((idx, node) => {
|
15
17
|
const quill = Quill.find(node);
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Meetings
|
5
|
+
module AdminLog
|
6
|
+
# This class holds the logic to present a `Decidim::Meetings::Questionnaire`
|
7
|
+
# for the `AdminLog` log.
|
8
|
+
#
|
9
|
+
# Usage should be automatic and you shouldn't need to call this class
|
10
|
+
# directly, but here's an example:
|
11
|
+
#
|
12
|
+
# action_log = Decidim::ActionLog.last
|
13
|
+
# view_helpers # => this comes from the views
|
14
|
+
# QuestionnairePresenter.new(action_log, view_helpers).present
|
15
|
+
class QuestionnairePresenter < Decidim::Log::BasePresenter
|
16
|
+
private
|
17
|
+
|
18
|
+
def action_string
|
19
|
+
case action
|
20
|
+
when "update"
|
21
|
+
"decidim.meetings.admin_log.questionnaire.#{action}"
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def resource_presenter
|
28
|
+
@resource_presenter ||= Decidim::Log::ResourcePresenter.new(action_log.resource.questionnaire_for.meeting, h, action_log.resource.questionnaire_for.meeting)
|
29
|
+
end
|
30
|
+
|
31
|
+
def i18n_params
|
32
|
+
super.merge(
|
33
|
+
meeting_name: resource_presenter.try(:present)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -31,7 +31,12 @@ module Decidim
|
|
31
31
|
def description(links: false, extras: true, strip_tags: false, all_locales: false)
|
32
32
|
return unless meeting
|
33
33
|
|
34
|
-
|
34
|
+
new_description = handle_locales(meeting.description, all_locales) do |content|
|
35
|
+
renderer = Decidim::ContentRenderers::HashtagRenderer.new(sanitized(content))
|
36
|
+
renderer.render(links: links).html_safe
|
37
|
+
end
|
38
|
+
|
39
|
+
content_handle_locale(new_description, all_locales, extras, links, strip_tags)
|
35
40
|
end
|
36
41
|
|
37
42
|
def location(all_locales: false)
|
@@ -4,7 +4,7 @@ module Decidim
|
|
4
4
|
module Meetings
|
5
5
|
module Admin
|
6
6
|
# A class used to find the Invites by their status status.
|
7
|
-
class Invites <
|
7
|
+
class Invites < Decidim::Query
|
8
8
|
# Syntactic sugar to initialize the class and return the queried objects.
|
9
9
|
#
|
10
10
|
# invites - the initial Invites relation that needs to be filtered.
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Decidim
|
4
4
|
module Meetings
|
5
5
|
# A class used to find meetings filtered by components and a date range
|
6
|
-
class FilteredMeetings <
|
6
|
+
class FilteredMeetings < Decidim::Query
|
7
7
|
# Syntactic sugar to initialize the class and return the queried objects.
|
8
8
|
#
|
9
9
|
# components - An array of Decidim::Component
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Decidim
|
4
4
|
module Meetings
|
5
5
|
# A class used to collect user answers for a questionnaire
|
6
|
-
class QuestionnaireUserAnswers <
|
6
|
+
class QuestionnaireUserAnswers < Decidim::Query
|
7
7
|
# Syntactic sugar to initialize the class and return the queried objects.
|
8
8
|
#
|
9
9
|
# questionnaire - a Questionnaire object
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Decidim
|
4
4
|
module Meetings
|
5
|
-
class
|
6
|
-
# Serializes an invite for data
|
5
|
+
class DownloadYourDataInviteSerializer < Decidim::Exporters::Serializer
|
6
|
+
# Serializes an invite for download your data
|
7
7
|
def serialize
|
8
8
|
{
|
9
9
|
id: resource.id,
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Decidim
|
4
4
|
module Meetings
|
5
|
-
class
|
6
|
-
# Serializes a registration for data
|
5
|
+
class DownloadYourDataRegistrationSerializer < Decidim::Exporters::Serializer
|
6
|
+
# Serializes a registration for download your data
|
7
7
|
def serialize
|
8
8
|
{
|
9
9
|
id: resource.id,
|
@@ -14,15 +14,16 @@ module Decidim
|
|
14
14
|
# resource - a resource that has meetings.
|
15
15
|
#
|
16
16
|
# Returns a String.
|
17
|
-
def self.for(resource)
|
18
|
-
new(resource).calendar
|
17
|
+
def self.for(resource, filters = nil)
|
18
|
+
new(resource, filters).calendar
|
19
19
|
end
|
20
20
|
|
21
21
|
# Initializes the class.
|
22
22
|
#
|
23
23
|
# resource - a resource that has meetings.
|
24
|
-
def initialize(resource)
|
24
|
+
def initialize(resource, filters = nil)
|
25
25
|
@resource = resource
|
26
|
+
@filters = filters
|
26
27
|
end
|
27
28
|
|
28
29
|
# Converts the resource meetings to the ICalendar format.
|
@@ -11,11 +11,9 @@ module Decidim
|
|
11
11
|
#
|
12
12
|
# Returns a String.
|
13
13
|
def events
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end.compact.join
|
18
|
-
end
|
14
|
+
filtered_meetings.map do |meeting|
|
15
|
+
MeetingCalendar.new(meeting).events
|
16
|
+
end.compact.join
|
19
17
|
end
|
20
18
|
|
21
19
|
private
|
@@ -29,11 +27,11 @@ module Decidim
|
|
29
27
|
Decidim::Meetings::Meeting.where(component: component)
|
30
28
|
end
|
31
29
|
|
32
|
-
#
|
30
|
+
# Finds the component meetings.
|
33
31
|
#
|
34
|
-
# Returns a
|
35
|
-
def
|
36
|
-
|
32
|
+
# Returns a collection of Meetings filtered based on provided params.
|
33
|
+
def filtered_meetings
|
34
|
+
meetings.not_hidden.published.except_withdrawn.ransack(@filters).result
|
37
35
|
end
|
38
36
|
end
|
39
37
|
end
|
@@ -3,14 +3,14 @@
|
|
3
3
|
module Decidim
|
4
4
|
module Meetings
|
5
5
|
class CalendarRenderer
|
6
|
-
def self.for(resource)
|
6
|
+
def self.for(resource, filters = nil)
|
7
7
|
case resource
|
8
8
|
when Decidim::Organization
|
9
|
-
Calendar::OrganizationCalendar.for(resource)
|
9
|
+
Calendar::OrganizationCalendar.for(resource, filters)
|
10
10
|
when Decidim::Component
|
11
|
-
Calendar::ComponentCalendar.for(resource)
|
11
|
+
Calendar::ComponentCalendar.for(resource, filters)
|
12
12
|
when Decidim::Meetings::Meeting
|
13
|
-
Calendar::MeetingCalendar.for(resource)
|
13
|
+
Calendar::MeetingCalendar.for(resource, filters)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Meetings
|
5
|
+
# This class is the generator class which creates and updates meetings related reminders,
|
6
|
+
# after reminder is generated it is send to user who have not closed past meetings.
|
7
|
+
class CloseMeetingReminderGenerator
|
8
|
+
attr_reader :reminder_jobs_queued
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@reminder_manifest = Decidim.reminders_registry.for(:close_meeting)
|
12
|
+
@reminder_jobs_queued = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
# Creates reminders and updates them if they already exists.
|
16
|
+
def generate
|
17
|
+
Decidim::Component.where(manifest_name: "meetings").published.each do |component|
|
18
|
+
send_reminders(component)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :reminder_manifest
|
25
|
+
|
26
|
+
def finder_query(component_id, interval)
|
27
|
+
Decidim::Meetings::Meeting
|
28
|
+
.published
|
29
|
+
.not_hidden
|
30
|
+
.except_withdrawn
|
31
|
+
.where(
|
32
|
+
"decidim_component_id = ? AND end_time >= ? AND end_time <= ? AND closed_at IS NULL",
|
33
|
+
component_id,
|
34
|
+
interval.ago.beginning_of_day,
|
35
|
+
interval.ago.end_of_day
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def send_reminders(component)
|
40
|
+
intervals = Array(reminder_manifest.settings.attributes[:reminder_times].default)
|
41
|
+
space_admins = Decidim::ParticipatoryProcessUserRole.where(decidim_participatory_process_id: component.participatory_space_id, role: "admin").collect(&:user)
|
42
|
+
space_admins = (global_admins + space_admins).uniq
|
43
|
+
intervals.each do |interval|
|
44
|
+
finder_query(component.id, interval).find_each do |meeting|
|
45
|
+
authors = meeting.official? ? space_admins : [meeting.author]
|
46
|
+
authors.each do |author|
|
47
|
+
send_notif = author.notification_settings.fetch("close_meeting_reminder", "1")
|
48
|
+
next unless send_notif == "1"
|
49
|
+
|
50
|
+
reminder = Decidim::Reminder.find_or_create_by(user: author, component: component)
|
51
|
+
record = Decidim::ReminderRecord.find_or_create_by(reminder: reminder, remindable: meeting)
|
52
|
+
record.update(state: "active") unless record.active?
|
53
|
+
reminder.records << record
|
54
|
+
reminder.save!
|
55
|
+
|
56
|
+
Decidim::Meetings::SendCloseMeetingReminderJob.perform_later(record)
|
57
|
+
@reminder_jobs_queued += 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def global_admins
|
64
|
+
@global_admins ||= Decidim::User.where(admin: true).all
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -30,28 +30,31 @@ module Decidim
|
|
30
30
|
def embeddable?
|
31
31
|
return nil if parsed_online_meeting_uri.nil?
|
32
32
|
|
33
|
-
|
33
|
+
embeddable_services.include?(parsed_online_meeting_uri.host)
|
34
34
|
end
|
35
35
|
|
36
36
|
def embed_code(request_host)
|
37
37
|
return nil if parsed_online_meeting_uri.nil?
|
38
38
|
|
39
39
|
%(
|
40
|
-
<
|
40
|
+
<div
|
41
|
+
class="disabled-iframe"
|
41
42
|
allow="camera; microphone; fullscreen; display-capture; autoplay"
|
42
43
|
loading="lazy"
|
43
44
|
src="#{embed_transformed_url(request_host)}"
|
44
45
|
style="height: 100%; width: 100%; border: 0px;"
|
45
|
-
></
|
46
|
+
></div>
|
46
47
|
)
|
47
48
|
end
|
48
49
|
|
49
50
|
private
|
50
51
|
|
51
|
-
EMBEDDABLE_SERVICES = %( www.youtube.com www.twitch.tv meet.jit.si )
|
52
|
-
|
53
52
|
attr_accessor :online_meeting_service_url
|
54
53
|
|
54
|
+
def embeddable_services
|
55
|
+
@embeddable_services ||= Meetings.embeddable_services
|
56
|
+
end
|
57
|
+
|
55
58
|
# Youtube transformation consists on:
|
56
59
|
# 1. extract the video id from the parameter v
|
57
60
|
# 2. Create a new URL using the domain youtube-nocookie.com, converting it to an embed
|
@@ -59,7 +62,8 @@ module Decidim
|
|
59
62
|
def transform_youtube_url(uri)
|
60
63
|
return online_meeting_service_url if uri.query.blank?
|
61
64
|
|
62
|
-
|
65
|
+
parsed_query = CGI.parse(uri.query)
|
66
|
+
video_id = parsed_query.has_key?("v") ? CGI.parse(uri.query).fetch("v")&.first : nil
|
63
67
|
|
64
68
|
return online_meeting_service_url if video_id.blank?
|
65
69
|
|
@@ -2,63 +2,17 @@
|
|
2
2
|
|
3
3
|
module Decidim
|
4
4
|
module Meetings
|
5
|
-
# This
|
6
|
-
#
|
7
|
-
# find the meetings.
|
5
|
+
# This service scopes the meeting searches with parameters that cannot be
|
6
|
+
# passed from the user interface.
|
8
7
|
class MeetingSearch < ResourceSearch
|
9
|
-
|
8
|
+
attr_reader :activity
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
# page - The page number to paginate the results.
|
14
|
-
# per_page - The number of meetings to return per page.
|
15
|
-
def initialize(options = {})
|
16
|
-
options[:scope] = options.fetch(:scope, Meeting.published)
|
17
|
-
options[:scope] = options[:state] == "withdrawn" ? options[:scope].withdrawn : options[:scope].except_withdrawn
|
18
|
-
options[:scope] = options[:scope].includes(:component, :attachments)
|
19
|
-
super(options[:scope], options)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Handle the date filter
|
23
|
-
def search_date
|
24
|
-
apply_scopes(%w(upcoming past), date)
|
25
|
-
end
|
26
|
-
|
27
|
-
def search_space
|
28
|
-
return query if options[:space].blank? || options[:space] == "all"
|
29
|
-
|
30
|
-
query.joins(:component).where(decidim_components: { participatory_space_type: options[:space].classify })
|
31
|
-
end
|
10
|
+
def build(params)
|
11
|
+
@activity = params[:activity]
|
32
12
|
|
33
|
-
|
34
|
-
fields = Decidim::Meetings::Meeting::TYPE_OF_MEETING
|
35
|
-
filtered = []
|
36
|
-
options[:type].each do |inquiry|
|
37
|
-
filtered.push(inquiry) if fields.include?(inquiry)
|
38
|
-
end
|
39
|
-
filtered.size.positive? ? query.where(decidim_meetings_meetings: { type_of_meeting: filtered }) : query
|
40
|
-
end
|
41
|
-
|
42
|
-
# Handle the activity filter
|
43
|
-
def search_activity
|
44
|
-
case activity
|
45
|
-
when "my_meetings"
|
46
|
-
query
|
47
|
-
.where(decidim_author_id: user.id)
|
48
|
-
else
|
49
|
-
query
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Handle the state filter
|
54
|
-
def search_state
|
55
|
-
return query.withdrawn if state == "withdrawn"
|
56
|
-
|
57
|
-
query.except_withdrawn
|
58
|
-
end
|
13
|
+
add_scope(:authored_by, user) if params[:activity] == "my_meetings" && user
|
59
14
|
|
60
|
-
|
61
|
-
super.includes(attachments: :file_attachment, component: { participatory_space: :organization })
|
15
|
+
super
|
62
16
|
end
|
63
17
|
end
|
64
18
|
end
|
@@ -2,12 +2,29 @@
|
|
2
2
|
<%= t(".export_calendar") %>
|
3
3
|
<%= icon "share", class: "icon--after", role: "img", "aria-hidden": true %>
|
4
4
|
</button>
|
5
|
+
|
5
6
|
<div class="reveal" id="calendarShare" data-reveal>
|
6
7
|
<div class="reveal__header">
|
7
|
-
<
|
8
|
+
<h3 class="reveal__title"><%= t(".calendar_url") %>:</h3>
|
8
9
|
<button class="close-button" data-close aria-label="<%= t(".close_window") %>" type="button">
|
9
10
|
<span aria-hidden="true">×</span>
|
10
11
|
</button>
|
11
12
|
</div>
|
12
|
-
|
13
|
+
|
14
|
+
<div class="calendar-url-description"><%= t(".copy_calendar_url_description") %></div>
|
15
|
+
<div class="calendar-url-explanation"><%= t(".copy_calendar_url_explanation") %></div>
|
16
|
+
|
17
|
+
<div class="input-group calendar_url_input">
|
18
|
+
<input id="urlCalendarUrl" class="input-group-field" type="text" title="<%= t(".calendar_url") %>" value="<%= "#{path}" %>" readonly>
|
19
|
+
<div class="input-group-button">
|
20
|
+
<button class="button primary"
|
21
|
+
data-clipboard-copy="#urlCalendarUrl"
|
22
|
+
data-clipboard-copy-label="<%= t(".copy_calendar_url_copied") %>"
|
23
|
+
data-clipboard-copy-message="<%= t(".copy_calendar_url_message") %>"
|
24
|
+
aria-label="<%= t(".copy_calendar_url_clarification") %>">
|
25
|
+
<%= icon "clipboard", role: "img", "aria-hidden": true %>
|
26
|
+
<%= t(".copy_calendar_url") %>
|
27
|
+
</button>
|
28
|
+
</div>
|
29
|
+
</div>
|
13
30
|
</div>
|
@@ -0,0 +1,64 @@
|
|
1
|
+
<div class="card" id="meetings">
|
2
|
+
<div class="card-divider">
|
3
|
+
<h2 class="card-title"><%= title %></h2>
|
4
|
+
</div>
|
5
|
+
|
6
|
+
<div class="card-section">
|
7
|
+
<div class="row column hashtags__container">
|
8
|
+
<%= form.translated :text_field, :title, autofocus: true, class: "js-hashtags", hashtaggable: true, value: @meeting.present? ? present(@meeting).title(all_locales: true) : @form.title.with_indifferent_access %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="row column hashtags__container">
|
12
|
+
<%= form.translated :editor, :description, hashtaggable: true, value: @meeting.present? ? present(@meeting).description(all_locales: true) : @form.description.with_indifferent_access %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class="row column">
|
16
|
+
<%= form.select :type_of_meeting,
|
17
|
+
@form.type_of_meeting_select,
|
18
|
+
{ include_blank: t(".select_a_meeting_type") },
|
19
|
+
{ multiple: false } %>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<div class="row column field" data-meeting-type="in_person">
|
23
|
+
<%= form.geocoding_field :address %>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
<div class="row column field" data-meeting-type="in_person">
|
27
|
+
<%= form.translated :text_area, :location %>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<div class="row column">
|
31
|
+
<%= form.translated :text_area, :location_hints %>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<div class="row column field" data-meeting-type="online">
|
35
|
+
<%= form.text_field :online_meeting_url %>
|
36
|
+
</div>
|
37
|
+
|
38
|
+
<div class="row column field" data-meeting-type="online">
|
39
|
+
<%= form.check_box :show_embedded_iframe %>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
<div class="row">
|
43
|
+
<div class="columns xlarge-6">
|
44
|
+
<%= form.datetime_field :start_time %>
|
45
|
+
</div>
|
46
|
+
|
47
|
+
<div class="columns xlarge-6">
|
48
|
+
<%= form.datetime_field :end_time %>
|
49
|
+
</div>
|
50
|
+
</div>
|
51
|
+
|
52
|
+
<div class="row column" id="private_meeting">
|
53
|
+
<%= form.check_box :private_meeting %>
|
54
|
+
</div>
|
55
|
+
|
56
|
+
<div class="row column" id="transparent">
|
57
|
+
<%= form.check_box :transparent %>
|
58
|
+
</div>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
|
62
|
+
<%= render "decidim/meetings/admin/meetings/services", form: form %>
|
63
|
+
|
64
|
+
<%= javascript_pack_tag "decidim_meetings_admin" %>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<%= decidim_form_for(@form, url: meeting_copies_path(meeting), method: :post, html: { class: "form copy_meetings " }) do |f| %>
|
2
|
-
<%= render partial: "
|
2
|
+
<%= render partial: "form", object: f, locals: { title: t("meeting_copies.new.title", scope: "decidim.admin"), select: t("meeting_copies.new.select", scope: "decidim.admin") } %>
|
3
3
|
|
4
4
|
<div class="button--double form-general-submit">
|
5
5
|
<%= f.submit t("meeting_copies.new.copy", scope: "decidim.admin") %>
|
@@ -43,7 +43,7 @@
|
|
43
43
|
<%= form.select :iframe_embed_type,
|
44
44
|
@form.iframe_embed_type_select,
|
45
45
|
{ multiple: false } %>
|
46
|
-
<p class="help-text"><%= t(".show_embedded_iframe_help") %></p>
|
46
|
+
<p class="help-text"><%= t(".show_embedded_iframe_help", domains: Decidim::Meetings.embeddable_services&.join(" ")) %></p>
|
47
47
|
</div>
|
48
48
|
|
49
49
|
<div class="row column field iframe-fields--access-level" data-meeting-type="online-access-level">
|
@@ -82,15 +82,12 @@
|
|
82
82
|
{ multiple: false } %>
|
83
83
|
</div>
|
84
84
|
|
85
|
-
<div class="row column" id="meeting_available_slots">
|
86
|
-
<%= form.number_field :available_slots %>
|
87
|
-
<p class="help-text"><%= t(".available_slots_help") %></p>
|
88
|
-
</div>
|
89
|
-
|
90
85
|
<div class="field" id="meeting_registration_url">
|
91
86
|
<%= form.text_field :registration_url %>
|
92
87
|
<p class="help-text"><%= t(".registration_url_help") %></p>
|
93
|
-
<
|
88
|
+
<div class="callout alert">
|
89
|
+
<%= t(".disclaimer", organization: current_component.organization.name) %>
|
90
|
+
</div>
|
94
91
|
</div>
|
95
92
|
|
96
93
|
<div class="row column" id="private_meeting">
|
@@ -101,19 +98,10 @@
|
|
101
98
|
<%= form.check_box :transparent %>
|
102
99
|
</div>
|
103
100
|
|
104
|
-
<div class="row column">
|
105
|
-
<%= form.check_box :customize_registration_email, :"data-toggle" => "customize_registration_email-div" %>
|
106
|
-
</div>
|
107
|
-
|
108
|
-
<div id="customize_registration_email-div" data-toggler=".hide" class="row column <%= @form.customize_registration_email? ? nil : "hide" %>">
|
109
|
-
<%= form.translated :editor, :registration_email_custom_content, lines: 10 %>
|
110
|
-
<p class="help-text"><%= t(".registration_email_help") %></p>
|
111
|
-
</div>
|
112
|
-
|
113
101
|
<%= render partial: "decidim/comments/admin/shared/availability_fields", locals: { form: form } %>
|
114
102
|
</div>
|
115
103
|
</div>
|
116
104
|
|
117
|
-
<%= render "
|
105
|
+
<%= render "services", form: form, id: tabs_id_for_service(blank_service) %>
|
118
106
|
|
119
107
|
<%= javascript_pack_tag "decidim_meetings_admin" %>
|
@@ -1,4 +1,3 @@
|
|
1
|
-
<% add_decidim_page_title(t(".title")) %>
|
2
1
|
<div class="card">
|
3
2
|
<div class="card-divider">
|
4
3
|
<h2 class="card-title">
|
@@ -49,7 +48,7 @@
|
|
49
48
|
<%= meeting.id %><br>
|
50
49
|
</td>
|
51
50
|
<td>
|
52
|
-
<%= present(meeting).title
|
51
|
+
<%= present(meeting).title %><br>
|
53
52
|
</td>
|
54
53
|
<td>
|
55
54
|
<% if meeting.start_time %>
|
@@ -42,7 +42,16 @@
|
|
42
42
|
</div>
|
43
43
|
|
44
44
|
<div class="row column">
|
45
|
-
<%= form.
|
45
|
+
<%= form.check_box :customize_registration_email, :"data-toggle" => "customize_registration_email-div" %>
|
46
|
+
</div>
|
47
|
+
|
48
|
+
<div id="customize_registration_email-div" data-toggler=".hide" class="row column <%= @form.customize_registration_email? ? nil : "hide" %>">
|
49
|
+
<%= form.translated :editor, :registration_email_custom_content, lines: 10 %>
|
50
|
+
<p class="help-text"><%= t(".registration_email_help") %></p>
|
51
|
+
</div>
|
52
|
+
|
53
|
+
<div class="row column">
|
54
|
+
<%= form.translated :editor, :registration_terms %>
|
46
55
|
</div>
|
47
56
|
</div>
|
48
57
|
</div>
|