decidim-meetings 0.26.5 → 0.27.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/meetings/content_blocks/highlighted_meetings_cell.rb +1 -1
  3. data/app/cells/decidim/meetings/content_blocks/upcoming_meetings/show.erb +1 -1
  4. data/app/cells/decidim/meetings/content_blocks/upcoming_meetings_cell.rb +2 -2
  5. data/app/cells/decidim/meetings/highlighted_meetings_for_component_cell.rb +10 -1
  6. data/app/cells/decidim/meetings/meeting_list_item_cell.rb +1 -1
  7. data/app/cells/decidim/meetings/meeting_m_cell.rb +1 -1
  8. data/app/cells/decidim/meetings/meeting_s_cell.rb +6 -0
  9. data/app/commands/decidim/meetings/admin/close_meeting.rb +1 -1
  10. data/app/commands/decidim/meetings/admin/copy_meeting.rb +5 -24
  11. data/app/commands/decidim/meetings/admin/create_agenda.rb +1 -1
  12. data/app/commands/decidim/meetings/admin/create_meeting.rb +1 -4
  13. data/app/commands/decidim/meetings/admin/destroy_meeting.rb +1 -1
  14. data/app/commands/decidim/meetings/admin/export_meeting_registrations.rb +1 -1
  15. data/app/commands/decidim/meetings/admin/invite_user_to_join_meeting.rb +9 -11
  16. data/app/commands/decidim/meetings/admin/publish_meeting.rb +1 -1
  17. data/app/commands/decidim/meetings/admin/unpublish_meeting.rb +1 -1
  18. data/app/commands/decidim/meetings/admin/update_agenda.rb +1 -1
  19. data/app/commands/decidim/meetings/admin/update_meeting.rb +1 -4
  20. data/app/commands/decidim/meetings/admin/update_question_status.rb +1 -1
  21. data/app/commands/decidim/meetings/admin/update_questionnaire.rb +10 -7
  22. data/app/commands/decidim/meetings/admin/update_registrations.rb +5 -3
  23. data/app/commands/decidim/meetings/admin/validate_registration_code.rb +1 -1
  24. data/app/commands/decidim/meetings/close_meeting.rb +1 -1
  25. data/app/commands/decidim/meetings/create_answer.rb +1 -1
  26. data/app/commands/decidim/meetings/create_meeting.rb +1 -1
  27. data/app/commands/decidim/meetings/decline_invitation.rb +1 -1
  28. data/app/commands/decidim/meetings/join_meeting.rb +6 -7
  29. data/app/commands/decidim/meetings/leave_meeting.rb +3 -3
  30. data/app/commands/decidim/meetings/update_meeting.rb +1 -1
  31. data/app/commands/decidim/meetings/withdraw_meeting.rb +1 -1
  32. data/app/controllers/concerns/decidim/meetings/admin/filterable.rb +4 -4
  33. data/app/controllers/concerns/decidim/meetings/filterable.rb +1 -7
  34. data/app/controllers/decidim/meetings/admin/meeting_copies_controller.rb +2 -2
  35. data/app/controllers/decidim/meetings/calendars_controller.rb +1 -1
  36. data/app/controllers/decidim/meetings/directory/meetings_controller.rb +17 -16
  37. data/app/controllers/decidim/meetings/meetings_controller.rb +21 -15
  38. data/app/events/decidim/meetings/meeting_registration_notification_event.rb +1 -1
  39. data/app/forms/decidim/meetings/admin/close_meeting_form.rb +1 -1
  40. data/app/forms/decidim/meetings/admin/meeting_copy_form.rb +51 -0
  41. data/app/forms/decidim/meetings/admin/meeting_form.rb +11 -10
  42. data/app/forms/decidim/meetings/admin/meeting_registration_invite_form.rb +1 -1
  43. data/app/forms/decidim/meetings/admin/meeting_registrations_form.rb +3 -0
  44. data/app/forms/decidim/meetings/answer_form.rb +0 -1
  45. data/app/forms/decidim/meetings/close_meeting_form.rb +1 -1
  46. data/app/forms/decidim/meetings/meeting_form.rb +2 -2
  47. data/app/helpers/decidim/meetings/application_helper.rb +8 -6
  48. data/app/helpers/decidim/meetings/directory/application_helper.rb +8 -6
  49. data/app/helpers/decidim/meetings/meetings_helper.rb +1 -3
  50. data/app/jobs/decidim/meetings/send_close_meeting_reminder_job.rb +17 -0
  51. data/app/mailers/decidim/meetings/close_meeting_reminder_mailer.rb +43 -0
  52. data/app/models/decidim/meetings/agenda_item.rb +1 -1
  53. data/app/models/decidim/meetings/answer.rb +2 -2
  54. data/app/models/decidim/meetings/invite.rb +2 -2
  55. data/app/models/decidim/meetings/meeting.rb +36 -21
  56. data/app/models/decidim/meetings/questionnaire.rb +6 -0
  57. data/app/models/decidim/meetings/registration.rb +2 -2
  58. data/app/packs/src/decidim/meetings/admin/meetings_form.js +0 -4
  59. data/app/packs/src/decidim/meetings/admin/registrations_form.js +2 -0
  60. data/app/presenters/decidim/meetings/admin_log/questionnaire_presenter.rb +39 -0
  61. data/app/queries/decidim/meetings/admin/invites.rb +1 -1
  62. data/app/queries/decidim/meetings/filtered_meetings.rb +1 -1
  63. data/app/queries/decidim/meetings/questionnaire_user_answers.rb +1 -1
  64. data/app/serializers/decidim/meetings/{data_portability_invite_serializer.rb → download_your_data_invite_serializer.rb} +2 -2
  65. data/app/serializers/decidim/meetings/{data_portability_registration_serializer.rb → download_your_data_registration_serializer.rb} +2 -2
  66. data/app/services/decidim/meetings/calendar/base_calendar.rb +4 -3
  67. data/app/services/decidim/meetings/calendar/component_calendar.rb +7 -9
  68. data/app/services/decidim/meetings/calendar/organization_calendar.rb +1 -1
  69. data/app/services/decidim/meetings/calendar_renderer.rb +4 -4
  70. data/app/services/decidim/meetings/close_meeting_reminder_generator.rb +68 -0
  71. data/app/services/decidim/meetings/meeting_iframe_embedder.rb +10 -6
  72. data/app/services/decidim/meetings/meeting_search.rb +7 -53
  73. data/app/views/decidim/meetings/_calendar_modal.html.erb +19 -2
  74. data/app/views/decidim/meetings/admin/meeting_copies/_form.html.erb +64 -0
  75. data/app/views/decidim/meetings/admin/meeting_copies/new.html.erb +1 -1
  76. data/app/views/decidim/meetings/admin/meetings/_form.html.erb +5 -17
  77. data/app/views/decidim/meetings/admin/meetings/index.html.erb +1 -1
  78. data/app/views/decidim/meetings/admin/registrations/_form.html.erb +9 -0
  79. data/app/views/decidim/meetings/close_meeting_reminder_mailer/close_meeting_reminder.html.erb +5 -0
  80. data/app/views/decidim/meetings/directory/meetings/_filters.html.erb +7 -7
  81. data/app/views/decidim/meetings/directory/meetings/_meetings.html.erb +6 -1
  82. data/app/views/decidim/meetings/directory/meetings/index.html.erb +1 -1
  83. data/app/views/decidim/meetings/directory/meetings/index.js.erb +7 -1
  84. data/app/views/decidim/meetings/layouts/live_event.html.erb +6 -2
  85. data/app/views/decidim/meetings/meetings/_count.html.erb +1 -1
  86. data/app/views/decidim/meetings/meetings/_filters.html.erb +7 -7
  87. data/app/views/decidim/meetings/meetings/_form.html.erb +4 -2
  88. data/app/views/decidim/meetings/meetings/_meetings.html.erb +11 -6
  89. data/app/views/decidim/meetings/meetings/index.html.erb +2 -2
  90. data/app/views/decidim/meetings/meetings/index.js.erb +2 -2
  91. data/config/locales/am-ET.yml +1 -0
  92. data/config/locales/ar.yml +10 -7
  93. data/config/locales/bg.yml +7 -0
  94. data/config/locales/ca.yml +34 -27
  95. data/config/locales/cs.yml +35 -28
  96. data/config/locales/da.yml +1 -0
  97. data/config/locales/de.yml +16 -77
  98. data/config/locales/el.yml +7 -0
  99. data/config/locales/en.yml +33 -27
  100. data/config/locales/eo.yml +1 -0
  101. data/config/locales/es-MX.yml +34 -27
  102. data/config/locales/es-PY.yml +34 -27
  103. data/config/locales/es.yml +34 -27
  104. data/config/locales/et.yml +1 -0
  105. data/config/locales/eu.yml +164 -204
  106. data/config/locales/fi-plain.yml +34 -27
  107. data/config/locales/fi.yml +34 -27
  108. data/config/locales/fr-CA.yml +31 -26
  109. data/config/locales/fr.yml +31 -26
  110. data/config/locales/ga-IE.yml +5 -9
  111. data/config/locales/gl.yml +23 -2
  112. data/config/locales/hr.yml +1 -0
  113. data/config/locales/hu.yml +20 -147
  114. data/config/locales/id-ID.yml +7 -0
  115. data/config/locales/is-IS.yml +4 -1
  116. data/config/locales/it.yml +14 -11
  117. data/config/locales/ja.yml +36 -29
  118. data/config/locales/ko.yml +1 -0
  119. data/config/locales/lb.yml +12 -6
  120. data/config/locales/lt.yml +1 -664
  121. data/config/locales/lv.yml +7 -0
  122. data/config/locales/mt.yml +1 -0
  123. data/config/locales/nl.yml +64 -91
  124. data/config/locales/no.yml +17 -12
  125. data/config/locales/om-ET.yml +1 -0
  126. data/config/locales/pl.yml +9 -14
  127. data/config/locales/pt-BR.yml +9 -13
  128. data/config/locales/pt.yml +13 -11
  129. data/config/locales/ro-RO.yml +18 -28
  130. data/config/locales/ru.yml +7 -0
  131. data/config/locales/si-LK.yml +1 -0
  132. data/config/locales/sk.yml +7 -0
  133. data/config/locales/sl.yml +4 -0
  134. data/config/locales/so-SO.yml +1 -0
  135. data/config/locales/sr-CS.yml +1 -0
  136. data/config/locales/sv.yml +20 -22
  137. data/config/locales/sw-KE.yml +1 -0
  138. data/config/locales/ti-ER.yml +1 -0
  139. data/config/locales/tr-TR.yml +7 -11
  140. data/config/locales/uk.yml +7 -0
  141. data/config/locales/val-ES.yml +1 -0
  142. data/config/locales/vi.yml +1 -0
  143. data/config/locales/zh-CN.yml +7 -7
  144. data/config/locales/zh-TW.yml +1 -0
  145. data/db/migrate/20210512100333_drop_decidim_meetings_minutes_table.rb +2 -2
  146. data/db/migrate/20210518133236_merge_minutes_with_closing_report_in_meetings_table.rb +1 -1
  147. data/db/migrate/20211105115625_remove_not_null_on_customize_registration_email.rb +7 -0
  148. data/lib/decidim/api/meeting_type.rb +1 -1
  149. data/lib/decidim/meetings/component.rb +7 -7
  150. data/lib/decidim/meetings/{data_portability_user_answers_serializer.rb → download_your_data_user_answers_serializer.rb} +2 -2
  151. data/lib/decidim/meetings/engine.rb +15 -1
  152. data/lib/decidim/meetings/test/factories.rb +3 -1
  153. data/lib/decidim/meetings/test/notifications_handling.rb +1 -1
  154. data/lib/decidim/meetings/test/translated_event.rb +2 -2
  155. data/lib/decidim/meetings/version.rb +1 -1
  156. data/lib/decidim/meetings.rb +5 -1
  157. metadata +29 -26
  158. data/app/services/decidim/meetings/directory/meeting_search.rb +0 -53
  159. data/config/locales/gn-PY.yml +0 -1
  160. data/config/locales/ka-GE.yml +0 -1
  161. data/config/locales/lo-LA.yml +0 -1
  162. data/config/locales/oc-FR.yml +0 -1
@@ -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
@@ -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 < Rectify::Query
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 < Rectify::Query
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 < Rectify::Query
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 DataPortabilityInviteSerializer < Decidim::Exporters::Serializer
6
- # Serializes an invite for data portability
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 DataPortabilityRegistrationSerializer < Decidim::Exporters::Serializer
6
- # Serializes a registration for data portability
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
- Rails.cache.fetch(cache_key) do
15
- meetings.map do |meeting|
16
- MeetingCalendar.new(meeting).events
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
- # Defines the cache key for the given component.
30
+ # Finds the component meetings.
33
31
  #
34
- # Returns a String.
35
- def cache_key
36
- "meetings-calendar-component-#{component.id}-#{component.updated_at.to_i}"
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
@@ -13,7 +13,7 @@ module Decidim
13
13
  # Returns a String.
14
14
  def events
15
15
  @events ||= components.map do |component|
16
- ComponentCalendar.new(component).events
16
+ ComponentCalendar.new(component, @filters).events
17
17
  end.compact.join
18
18
  end
19
19
 
@@ -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
- EMBEDDABLE_SERVICES.include?(parsed_online_meeting_uri.host)
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
- <iframe
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
- ></iframe>
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
- video_id = CGI.parse(uri.query).fetch("v")&.first
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 class handles search and filtering of meetings. Needs a
6
- # `current_component` param with a `Decidim::Component` in order to
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
- text_search_fields :title, :description
8
+ attr_reader :activity
10
9
 
11
- # Public: Initializes the service.
12
- # component - A Decidim::Component to get the meetings from.
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
- def search_type
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
- def results
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
- <h2 class="reveal__title"><%= t(".calendar_url") %>:</h2>
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">&times;</span>
10
11
  </button>
11
12
  </div>
12
- <input type="text" value="<%= "#{path}" %>" readonly title="<%= t(".calendar_url") %>">
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: "decidim/meetings/admin/meetings/form", object: f, locals: { title: t("meeting_copies.new.title", scope: "decidim.admin"), select: t("meeting_copies.new.select", scope: "decidim.admin") } %>
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
- <label><%= t(".disclaimer", organization: current_component.organization.name) %></label><br>
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 "decidim/meetings/admin/meetings/services", form: form, id: tabs_id_for_service(blank_service) %>
105
+ <%= render "services", form: form, id: tabs_id_for_service(blank_service) %>
118
106
 
119
107
  <%= javascript_pack_tag "decidim_meetings_admin" %>
@@ -48,7 +48,7 @@
48
48
  <%= meeting.id %><br>
49
49
  </td>
50
50
  <td>
51
- <%= present(meeting).title(html_escape: true) %><br>
51
+ <%= present(meeting).title %><br>
52
52
  </td>
53
53
  <td>
54
54
  <% if meeting.start_time %>
@@ -41,6 +41,15 @@
41
41
  <p class="help-text"><%= t(".reserved_slots_help") %></p>
42
42
  </div>
43
43
 
44
+ <div class="row column">
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
+
44
53
  <div class="row column">
45
54
  <%= form.translated :editor, :registration_terms %>
46
55
  </div>
@@ -0,0 +1,5 @@
1
+ <p class="email-greeting"><%= t "decidim.meetings.close_meeting_reminder_mailer.close_meeting_reminder.hello", username: @user.name %></p>
2
+
3
+ <p class="email-instructions"><%= t("decidim.meetings.close_meeting_reminder_mailer.close_meeting_reminder.body", meeting_title: translated_attribute(@meeting.title), meeting_path: @meeting.reported_content_url).html_safe %></p>
4
+
5
+ <p class="email-closing"><%= t("decidim.meetings.close_meeting_reminder_mailer.close_meeting_reminder.greetings", organization_name: h(@organization.name), organization_url: decidim.root_url(host: @organization.host)).html_safe %></p>
@@ -4,7 +4,7 @@
4
4
  <div class="filters__section">
5
5
  <div class="filters__search">
6
6
  <div class="input-group">
7
- <%= form.search_field :search_text, label: false, class: "input-group-field", placeholder: t("decidim.meetings.meetings.filters.search"), title: t("decidim.meetings.meetings.filters.search"), "aria-label": t("decidim.meetings.meetings.filters.search"), data: { disable_dynamic_change: true } %>
7
+ <%= form.search_field :title_or_description_cont, label: false, class: "input-group-field", placeholder: t("decidim.meetings.meetings.filters.search"), title: t("decidim.meetings.meetings.filters.search"), "aria-label": t("decidim.meetings.meetings.filters.search"), data: { disable_dynamic_change: true } %>
8
8
  <div class="input-group-button">
9
9
  <button type="submit" class="button" aria-controls="meetings">
10
10
  <%= icon "magnifying-glass", aria_label: t("decidim.meetings.meetings.filters.search"), role: "img" %>
@@ -15,18 +15,18 @@
15
15
  </div>
16
16
 
17
17
  <% unless @forced_past_meetings %>
18
- <%= form.collection_radio_buttons :date, filter_date_values, :first, :last, legend_title: t("decidim.meetings.meetings.filters.date") %>
18
+ <%= form.check_boxes_tree :with_any_date, filter_date_values, legend_title: t("decidim.meetings.meetings.filters.date") %>
19
19
  <% end %>
20
20
 
21
- <%= form.check_boxes_tree :type, filter_type_values, legend_title: t("decidim.meetings.meetings.filters.type") %>
21
+ <%= form.check_boxes_tree :with_any_type, filter_type_values, legend_title: t("decidim.meetings.meetings.filters.type") %>
22
22
 
23
- <%= form.check_boxes_tree :scope_id, directory_filter_scopes_values, legend_title: t("decidim.meetings.meetings.filters.scope") %>
23
+ <%= form.check_boxes_tree :with_any_scope, directory_filter_scopes_values, legend_title: t("decidim.meetings.meetings.filters.scope") %>
24
24
 
25
- <%= form.check_boxes_tree :category_id, directory_filter_categories_values, legend_title: t("decidim.meetings.meetings.filters.category") %>
25
+ <%= form.check_boxes_tree :with_any_global_category, directory_filter_categories_values, legend_title: t("decidim.meetings.meetings.filters.category") %>
26
26
 
27
- <%= form.check_boxes_tree :origin, directory_filter_origin_values, legend_title: t("decidim.meetings.meetings.filters.origin") %>
27
+ <%= form.check_boxes_tree :with_any_origin, directory_filter_origin_values, legend_title: t("decidim.meetings.meetings.filters.origin") %>
28
28
 
29
- <%= form.check_boxes_tree :space, directory_meeting_spaces_values, legend_title: t("decidim.meetings.directory.meetings.index.space_type") %>
29
+ <%= form.check_boxes_tree :with_any_space, directory_meeting_spaces_values, legend_title: t("decidim.meetings.directory.meetings.index.space_type") %>
30
30
 
31
31
  <% if current_user %>
32
32
  <%= form.collection_radio_buttons :activity, activity_filter_values, :first, :last, { legend_title: t("decidim.meetings.meetings.filters.activity") }, "aria-controls": "meetings" %>
@@ -8,7 +8,12 @@
8
8
  <%= render partial: "decidim/shared/results_per_page" %>
9
9
  </div>
10
10
  <div class="column">
11
- <%= render partial: "decidim/meetings/calendar_modal", locals: { path: calendar_url } %>
11
+ <%= render partial: "decidim/meetings/calendar_modal", locals: {
12
+ path: short_url(
13
+ route_name: "calendar",
14
+ params: { filter: params.fetch(:filter, {}).try(:to_unsafe_hash) }
15
+ )
16
+ } %>
12
17
  </div>
13
18
  </div>
14
19
 
@@ -6,7 +6,7 @@
6
6
  <%= render partial: "decidim/meetings/meetings/count" %>
7
7
  </h1>
8
8
 
9
- <%= cell "decidim/meetings/meetings_map", search.results %>
9
+ <%= cell "decidim/meetings/meetings_map", search.result %>
10
10
 
11
11
  <div class="columns mediumlarge-4 large-3">
12
12
  <div class="card card--secondary show-for-mediumlarge">