decidim-meetings 0.26.2 → 0.27.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) 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/commands/decidim/meetings/admin/close_meeting.rb +1 -1
  7. data/app/commands/decidim/meetings/admin/copy_meeting.rb +1 -1
  8. data/app/commands/decidim/meetings/admin/create_agenda.rb +1 -1
  9. data/app/commands/decidim/meetings/admin/create_meeting.rb +1 -4
  10. data/app/commands/decidim/meetings/admin/destroy_meeting.rb +1 -1
  11. data/app/commands/decidim/meetings/admin/export_meeting_registrations.rb +1 -1
  12. data/app/commands/decidim/meetings/admin/invite_user_to_join_meeting.rb +9 -11
  13. data/app/commands/decidim/meetings/admin/publish_meeting.rb +1 -1
  14. data/app/commands/decidim/meetings/admin/unpublish_meeting.rb +1 -1
  15. data/app/commands/decidim/meetings/admin/update_agenda.rb +1 -1
  16. data/app/commands/decidim/meetings/admin/update_meeting.rb +1 -4
  17. data/app/commands/decidim/meetings/admin/update_question_status.rb +1 -1
  18. data/app/commands/decidim/meetings/admin/update_questionnaire.rb +10 -7
  19. data/app/commands/decidim/meetings/admin/update_registrations.rb +5 -3
  20. data/app/commands/decidim/meetings/admin/validate_registration_code.rb +1 -1
  21. data/app/commands/decidim/meetings/close_meeting.rb +1 -1
  22. data/app/commands/decidim/meetings/create_answer.rb +1 -1
  23. data/app/commands/decidim/meetings/create_meeting.rb +1 -1
  24. data/app/commands/decidim/meetings/decline_invitation.rb +1 -1
  25. data/app/commands/decidim/meetings/join_meeting.rb +15 -7
  26. data/app/commands/decidim/meetings/leave_meeting.rb +3 -3
  27. data/app/commands/decidim/meetings/update_meeting.rb +1 -1
  28. data/app/commands/decidim/meetings/withdraw_meeting.rb +1 -1
  29. data/app/controllers/concerns/decidim/meetings/admin/filterable.rb +4 -4
  30. data/app/controllers/concerns/decidim/meetings/filterable.rb +1 -7
  31. data/app/controllers/decidim/meetings/calendars_controller.rb +1 -1
  32. data/app/controllers/decidim/meetings/directory/meetings_controller.rb +17 -15
  33. data/app/controllers/decidim/meetings/meetings_controller.rb +21 -14
  34. data/app/events/decidim/meetings/meeting_registration_notification_event.rb +1 -1
  35. data/app/forms/decidim/meetings/admin/close_meeting_form.rb +1 -1
  36. data/app/forms/decidim/meetings/admin/meeting_form.rb +2 -5
  37. data/app/forms/decidim/meetings/admin/meeting_registration_invite_form.rb +1 -1
  38. data/app/forms/decidim/meetings/admin/meeting_registrations_form.rb +3 -0
  39. data/app/forms/decidim/meetings/answer_form.rb +0 -1
  40. data/app/forms/decidim/meetings/close_meeting_form.rb +1 -1
  41. data/app/forms/decidim/meetings/meeting_form.rb +2 -2
  42. data/app/helpers/decidim/meetings/application_helper.rb +1 -1
  43. data/app/helpers/decidim/meetings/directory/application_helper.rb +1 -1
  44. data/app/helpers/decidim/meetings/meetings_helper.rb +1 -3
  45. data/app/jobs/decidim/meetings/send_close_meeting_reminder_job.rb +17 -0
  46. data/app/mailers/decidim/meetings/close_meeting_reminder_mailer.rb +43 -0
  47. data/app/models/decidim/meetings/answer.rb +2 -2
  48. data/app/models/decidim/meetings/invite.rb +2 -2
  49. data/app/models/decidim/meetings/meeting.rb +34 -16
  50. data/app/models/decidim/meetings/questionnaire.rb +6 -0
  51. data/app/models/decidim/meetings/registration.rb +2 -2
  52. data/app/packs/src/decidim/meetings/admin/meetings_form.js +0 -4
  53. data/app/packs/src/decidim/meetings/admin/registrations_form.js +2 -0
  54. data/app/presenters/decidim/meetings/admin_log/questionnaire_presenter.rb +39 -0
  55. data/app/queries/decidim/meetings/admin/invites.rb +1 -1
  56. data/app/queries/decidim/meetings/filtered_meetings.rb +1 -1
  57. data/app/queries/decidim/meetings/questionnaire_user_answers.rb +1 -1
  58. data/app/serializers/decidim/meetings/{data_portability_invite_serializer.rb → download_your_data_invite_serializer.rb} +2 -2
  59. data/app/serializers/decidim/meetings/{data_portability_registration_serializer.rb → download_your_data_registration_serializer.rb} +2 -2
  60. data/app/services/decidim/meetings/calendar/base_calendar.rb +4 -3
  61. data/app/services/decidim/meetings/calendar/component_calendar.rb +7 -9
  62. data/app/services/decidim/meetings/calendar/organization_calendar.rb +1 -1
  63. data/app/services/decidim/meetings/calendar_renderer.rb +4 -4
  64. data/app/services/decidim/meetings/close_meeting_reminder_generator.rb +68 -0
  65. data/app/services/decidim/meetings/meeting_iframe_embedder.rb +10 -6
  66. data/app/services/decidim/meetings/meeting_search.rb +7 -53
  67. data/app/views/decidim/meetings/_calendar_modal.html.erb +19 -2
  68. data/app/views/decidim/meetings/admin/meetings/_form.html.erb +4 -16
  69. data/app/views/decidim/meetings/admin/registrations/_form.html.erb +9 -0
  70. data/app/views/decidim/meetings/close_meeting_reminder_mailer/close_meeting_reminder.html.erb +5 -0
  71. data/app/views/decidim/meetings/directory/meetings/_filters.html.erb +7 -7
  72. data/app/views/decidim/meetings/directory/meetings/_meetings.html.erb +6 -1
  73. data/app/views/decidim/meetings/directory/meetings/index.html.erb +1 -1
  74. data/app/views/decidim/meetings/directory/meetings/index.js.erb +7 -1
  75. data/app/views/decidim/meetings/layouts/live_event.html.erb +6 -2
  76. data/app/views/decidim/meetings/meetings/_count.html.erb +1 -1
  77. data/app/views/decidim/meetings/meetings/_filters.html.erb +7 -7
  78. data/app/views/decidim/meetings/meetings/_form.html.erb +4 -2
  79. data/app/views/decidim/meetings/meetings/_meetings.html.erb +11 -6
  80. data/app/views/decidim/meetings/meetings/index.html.erb +2 -2
  81. data/app/views/decidim/meetings/meetings/index.js.erb +7 -1
  82. data/config/locales/am-ET.yml +1 -0
  83. data/config/locales/ar.yml +4 -7
  84. data/config/locales/bg.yml +1 -0
  85. data/config/locales/ca.yml +24 -10
  86. data/config/locales/cs.yml +24 -10
  87. data/config/locales/da.yml +1 -0
  88. data/config/locales/de.yml +10 -13
  89. data/config/locales/el.yml +1 -0
  90. data/config/locales/en.yml +23 -10
  91. data/config/locales/eo.yml +1 -0
  92. data/config/locales/es-MX.yml +25 -11
  93. data/config/locales/es-PY.yml +25 -11
  94. data/config/locales/es.yml +25 -11
  95. data/config/locales/et.yml +1 -0
  96. data/config/locales/eu.yml +10 -11
  97. data/config/locales/fi-plain.yml +24 -10
  98. data/config/locales/fi.yml +24 -10
  99. data/config/locales/fr-CA.yml +22 -10
  100. data/config/locales/fr.yml +22 -10
  101. data/config/locales/ga-IE.yml +1 -9
  102. data/config/locales/gl.yml +14 -2
  103. data/config/locales/hr.yml +1 -0
  104. data/config/locales/hu.yml +16 -8
  105. data/config/locales/id-ID.yml +1 -0
  106. data/config/locales/is-IS.yml +2 -1
  107. data/config/locales/it.yml +7 -11
  108. data/config/locales/ja.yml +26 -12
  109. data/config/locales/ko.yml +1 -0
  110. data/config/locales/lb.yml +6 -6
  111. data/config/locales/lt.yml +1 -0
  112. data/config/locales/lv.yml +1 -0
  113. data/config/locales/mt.yml +1 -0
  114. data/config/locales/nl.yml +7 -11
  115. data/config/locales/no.yml +7 -12
  116. data/config/locales/om-ET.yml +1 -0
  117. data/config/locales/pl.yml +2 -10
  118. data/config/locales/pt-BR.yml +3 -13
  119. data/config/locales/pt.yml +6 -11
  120. data/config/locales/ro-RO.yml +8 -8
  121. data/config/locales/ru.yml +1 -0
  122. data/config/locales/si-LK.yml +1 -0
  123. data/config/locales/sk.yml +1 -0
  124. data/config/locales/sl.yml +1 -0
  125. data/config/locales/so-SO.yml +1 -0
  126. data/config/locales/sr-CS.yml +1 -0
  127. data/config/locales/sv.yml +15 -11
  128. data/config/locales/sw-KE.yml +1 -0
  129. data/config/locales/ti-ER.yml +1 -0
  130. data/config/locales/tr-TR.yml +1 -11
  131. data/config/locales/uk.yml +1 -0
  132. data/config/locales/val-ES.yml +1 -0
  133. data/config/locales/vi.yml +1 -0
  134. data/config/locales/zh-CN.yml +1 -7
  135. data/config/locales/zh-TW.yml +1 -0
  136. data/db/migrate/20210512100333_drop_decidim_meetings_minutes_table.rb +2 -2
  137. data/db/migrate/20210518133236_merge_minutes_with_closing_report_in_meetings_table.rb +1 -1
  138. data/db/migrate/20211105115625_remove_not_null_on_customize_registration_email.rb +7 -0
  139. data/lib/decidim/api/meeting_type.rb +1 -1
  140. data/lib/decidim/meetings/component.rb +5 -5
  141. data/lib/decidim/meetings/{data_portability_user_answers_serializer.rb → download_your_data_user_answers_serializer.rb} +2 -2
  142. data/lib/decidim/meetings/engine.rb +14 -0
  143. data/lib/decidim/meetings/test/factories.rb +3 -1
  144. data/lib/decidim/meetings/test/notifications_handling.rb +1 -1
  145. data/lib/decidim/meetings/test/translated_event.rb +2 -2
  146. data/lib/decidim/meetings/version.rb +1 -1
  147. data/lib/decidim/meetings.rb +5 -1
  148. metadata +27 -22
  149. data/app/services/decidim/meetings/directory/meeting_search.rb +0 -53
@@ -6,7 +6,7 @@ module Decidim
6
6
  include Decidim::Events::NotificationEvent
7
7
 
8
8
  def notification_title
9
- I18n.t("notification_title", i18n_options).html_safe
9
+ I18n.t("notification_title", **i18n_options).html_safe
10
10
  end
11
11
 
12
12
  def i18n_options
@@ -16,7 +16,7 @@ module Decidim
16
16
  attribute :attending_organizations, String
17
17
  attribute :proposal_ids, Array[Integer]
18
18
  attribute :proposals
19
- attribute :closed_at, Decidim::Attributes::TimeWithZone, default: ->(_form, _attribute) { Time.current }
19
+ attribute :closed_at, Decidim::Attributes::TimeWithZone, default: -> { Time.current }
20
20
 
21
21
  validates :closing_report, translatable_presence: true
22
22
  validates :attendees_count, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 999, only_integer: true }
@@ -14,7 +14,6 @@ module Decidim
14
14
  attribute :transparent, Boolean
15
15
  attribute :registration_type, String
16
16
  attribute :registration_url, String
17
- attribute :available_slots, Integer, default: 0
18
17
  attribute :customize_registration_email, Boolean
19
18
  attribute :iframe_embed_type, String, default: "none"
20
19
  attribute :comments_enabled, Boolean, default: true
@@ -26,13 +25,11 @@ module Decidim
26
25
  translatable_attribute :description, String
27
26
  translatable_attribute :location, String
28
27
  translatable_attribute :location_hints, String
29
- translatable_attribute :registration_email_custom_content, String
30
28
 
31
29
  validates :iframe_embed_type, inclusion: { in: Decidim::Meetings::Meeting.iframe_embed_types }
32
30
  validates :title, translatable_presence: true
33
31
  validates :description, translatable_presence: true
34
32
  validates :registration_type, presence: true
35
- validates :available_slots, numericality: { greater_than_or_equal_to: 0 }, presence: true, if: ->(form) { form.on_this_platform? }
36
33
  validates :registration_url, presence: true, url: true, if: ->(form) { form.on_different_platform? }
37
34
  validates :type_of_meeting, presence: true
38
35
  validates :location, translatable_presence: true, if: ->(form) { form.in_person_meeting? || form.hybrid_meeting? }
@@ -75,14 +72,14 @@ module Decidim
75
72
  #
76
73
  # Returns a Decidim::Scope
77
74
  def scope
78
- @scope ||= @decidim_scope_id ? current_component.scopes.find_by(id: @decidim_scope_id) : current_component.scope
75
+ @scope ||= @attributes["decidim_scope_id"].value ? current_component.scopes.find_by(id: @attributes["decidim_scope_id"].value) : current_component.scope
79
76
  end
80
77
 
81
78
  # Scope identifier
82
79
  #
83
80
  # Returns the scope identifier related to the meeting
84
81
  def decidim_scope_id
85
- @decidim_scope_id || scope&.id
82
+ super || scope&.id
86
83
  end
87
84
 
88
85
  def category
@@ -12,7 +12,7 @@ module Decidim
12
12
  attribute :existing_user, Boolean, default: false
13
13
 
14
14
  validates :name, presence: true, unless: proc { |object| object.existing_user }
15
- validates :email, presence: true, 'valid_email_2/email': { disposable: true }, unless: proc { |object| object.existing_user }
15
+ validates :email, presence: true, "valid_email_2/email": { disposable: true }, unless: proc { |object| object.existing_user }
16
16
  validates :user, presence: true, if: proc { |object| object.existing_user }
17
17
 
18
18
  def user
@@ -11,9 +11,12 @@ module Decidim
11
11
 
12
12
  attribute :registrations_enabled, Boolean
13
13
  attribute :registration_form_enabled, Boolean
14
+ attribute :customize_registration_email, Boolean
14
15
  attribute :available_slots, Integer
15
16
  attribute :reserved_slots, Integer
17
+
16
18
  translatable_attribute :registration_terms, String
19
+ translatable_attribute :registration_email_custom_content, String
17
20
 
18
21
  validates :registration_terms, translatable_presence: true, if: ->(form) { form.registrations_enabled? }
19
22
  validates :available_slots, :reserved_slots, presence: true, if: ->(form) { form.registrations_enabled? }
@@ -10,7 +10,6 @@ module Decidim
10
10
  attribute :body, String
11
11
  attribute :choices, Array[AnswerChoiceForm]
12
12
  attribute :current_user, Decidim::User
13
- attribute :answer, Decidim::Meetings::Answer
14
13
 
15
14
  validates :selected_choices, presence: true
16
15
  validate :max_choices, if: -> { question.max_choices }
@@ -7,7 +7,7 @@ module Decidim
7
7
  attribute :closing_report, String
8
8
  attribute :proposal_ids, Array[Integer]
9
9
  attribute :proposals
10
- attribute :closed_at, Decidim::Attributes::TimeWithZone, default: ->(_form, _attribute) { Time.current }
10
+ attribute :closed_at, Decidim::Attributes::TimeWithZone, default: -> { Time.current }
11
11
  attribute :attendees_count, Integer, default: 0
12
12
 
13
13
  validates :closing_report, presence: true
@@ -60,14 +60,14 @@ module Decidim
60
60
  #
61
61
  # Returns a Decidim::Scope
62
62
  def scope
63
- @scope ||= @decidim_scope_id ? current_component.scopes.find_by(id: @decidim_scope_id) : current_component.scope
63
+ @scope ||= @attributes["decidim_scope_id"].value ? current_component.scopes.find_by(id: @attributes["decidim_scope_id"].value) : current_component.scope
64
64
  end
65
65
 
66
66
  # Scope identifier
67
67
  #
68
68
  # Returns the scope identifier related to the meeting
69
69
  def decidim_scope_id
70
- @decidim_scope_id || scope&.id
70
+ super || scope&.id
71
71
  end
72
72
 
73
73
  def category
@@ -16,7 +16,7 @@ module Decidim
16
16
  def filter_origin_values
17
17
  origin_values = []
18
18
  origin_values << TreePoint.new("official", t("decidim.meetings.meetings.filters.origin_values.official"))
19
- origin_values << TreePoint.new("citizens", t("decidim.meetings.meetings.filters.origin_values.citizens")) # todo
19
+ origin_values << TreePoint.new("participants", t("decidim.meetings.meetings.filters.origin_values.participants")) # todo
20
20
  if current_organization.user_groups_enabled?
21
21
  origin_values << TreePoint.new("user_group", t("decidim.meetings.meetings.filters.origin_values.user_groups")) # todo
22
22
  end
@@ -109,7 +109,7 @@ module Decidim
109
109
  def directory_filter_origin_values
110
110
  origin_values = []
111
111
  origin_values << TreePoint.new("official", t("decidim.meetings.meetings.filters.origin_values.official"))
112
- origin_values << TreePoint.new("citizens", t("decidim.meetings.meetings.filters.origin_values.citizens"))
112
+ origin_values << TreePoint.new("participants", t("decidim.meetings.meetings.filters.origin_values.participants"))
113
113
  origin_values << TreePoint.new("user_group", t("decidim.meetings.meetings.filters.origin_values.user_groups")) if current_organization.user_groups_enabled?
114
114
 
115
115
  TreeNode.new(
@@ -30,12 +30,10 @@ module Decidim
30
30
  # Returns a String.
31
31
  def meeting_type_badge_css_class(type)
32
32
  case type
33
- when "private"
33
+ when "private", "withdraw"
34
34
  "alert"
35
35
  when "transparent"
36
36
  "secondary"
37
- when "withdraw"
38
- "alert"
39
37
  end
40
38
  end
41
39
 
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ class SendCloseMeetingReminderJob < ApplicationJob
6
+ queue_as :close_meeting_reminder
7
+
8
+ def perform(record)
9
+ return if record.remindable.closed?
10
+
11
+ ::Decidim::ReminderDelivery.create(reminder: record.reminder)
12
+ ::Decidim::Meetings::CloseMeetingReminderMailer.close_meeting_reminder(record).deliver_now
13
+ record.update(state: "completed")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ # A custom mailer for sending notifications for overdue meetings
6
+ class CloseMeetingReminderMailer < Decidim::ApplicationMailer
7
+ include Decidim::TranslationsHelper
8
+ include ActionView::Helpers::SanitizeHelper
9
+ include Decidim::ApplicationHelper
10
+
11
+ helper Decidim::ResourceHelper
12
+ helper Decidim::TranslationsHelper
13
+ helper Decidim::ApplicationHelper
14
+
15
+ helper_method :routes
16
+
17
+ # Send the user an email reminder to close the meetings
18
+ #
19
+ # record - the reminder record specific to a past meeting.
20
+ def close_meeting_reminder(record)
21
+ @reminder = record.reminder
22
+ @user = record.reminder.user
23
+ with_user(@user) do
24
+ @meeting = record.remindable
25
+ @organization = @user.organization
26
+ mail(
27
+ to: @user.email,
28
+ subject: I18n.t(
29
+ "decidim.meetings.close_meeting_reminder_mailer.close_meeting_reminder.subject",
30
+ organization_name: @organization.name
31
+ )
32
+ )
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def routes
39
+ @routes ||= Decidim::EngineRouter.main_proxy(@reminder.component)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -4,7 +4,7 @@ module Decidim
4
4
  module Meetings
5
5
  # The data store for an Answer in the Decidim::Meetings
6
6
  class Answer < Meetings::ApplicationRecord
7
- include Decidim::DataPortability
7
+ include Decidim::DownloadYourData
8
8
 
9
9
  belongs_to :user, class_name: "Decidim::User", foreign_key: "decidim_user_id", optional: true
10
10
  belongs_to :questionnaire, class_name: "Decidim::Meetings::Questionnaire", foreign_key: "decidim_questionnaire_id"
@@ -24,7 +24,7 @@ module Decidim
24
24
  end
25
25
 
26
26
  def self.export_serializer
27
- Decidim::Meetings::DataPortabilityUserAnswersSerializer
27
+ Decidim::Meetings::DownloadYourDataUserAnswersSerializer
28
28
  end
29
29
 
30
30
  def organization
@@ -6,7 +6,7 @@ module Decidim
6
6
  class Invite < Meetings::ApplicationRecord
7
7
  include Decidim::Traceable
8
8
  include Decidim::Loggable
9
- include Decidim::DataPortability
9
+ include Decidim::DownloadYourData
10
10
 
11
11
  belongs_to :meeting, foreign_key: "decidim_meeting_id", class_name: "Decidim::Meetings::Meeting"
12
12
  belongs_to :user, foreign_key: "decidim_user_id", class_name: "Decidim::User"
@@ -14,7 +14,7 @@ module Decidim
14
14
  validates :user, uniqueness: { scope: :meeting }
15
15
 
16
16
  def self.export_serializer
17
- Decidim::Meetings::DataPortabilityInviteSerializer
17
+ Decidim::Meetings::DownloadYourDataInviteSerializer
18
18
  end
19
19
 
20
20
  def self.log_presenter_class_for(_log)
@@ -25,6 +25,7 @@ module Decidim
25
25
  include Decidim::Authorable
26
26
  include Decidim::TranslatableResource
27
27
  include Decidim::Publicable
28
+ include Decidim::FilterableResource
28
29
 
29
30
  TYPE_OF_MEETING = %w(in_person online hybrid).freeze
30
31
  REGISTRATION_TYPE = %w(registration_disabled on_this_platform on_different_platform).freeze
@@ -59,8 +60,26 @@ module Decidim
59
60
  scope :upcoming, -> { where(arel_table[:end_time].gteq(Time.current)) }
60
61
  scope :withdrawn, -> { where(state: "withdrawn") }
61
62
  scope :except_withdrawn, -> { where.not(state: "withdrawn").or(where(state: nil)) }
63
+ scope :with_availability, lambda { |state_key|
64
+ case state_key
65
+ when "withdrawn"
66
+ withdrawn
67
+ else
68
+ except_withdrawn
69
+ end
70
+ }
71
+ scope_search_multi :with_any_date, [:upcoming, :past]
72
+ scope :with_any_space, lambda { |*target_space|
73
+ target_spaces = target_space.compact.compact_blank
74
+
75
+ return self if target_spaces.blank? || target_spaces.include?("all")
62
76
 
63
- scope :visible_meeting_for, lambda { |user|
77
+ joins(:component).where(
78
+ decidim_components: { participatory_space_type: target_spaces.map(&:classify) }
79
+ )
80
+ }
81
+
82
+ scope :visible_for, lambda { |user|
64
83
  (all.distinct if user&.admin?) ||
65
84
  if user.present?
66
85
  spaces = Decidim.participatory_space_registry.manifests.map do |manifest|
@@ -109,6 +128,10 @@ module Decidim
109
128
 
110
129
  scope :visible, -> { where("decidim_meetings_meetings.private_meeting != ? OR decidim_meetings_meetings.transparent = ?", true, true) }
111
130
 
131
+ scope :authored_by, ->(author) { where(decidim_author_id: author) }
132
+
133
+ scope_search_multi :with_any_type, TYPE_OF_MEETING.map(&:to_sym)
134
+
112
135
  TYPE_OF_MEETING.each do |type|
113
136
  scope type.to_sym, -> { where(type_of_meeting: type.to_sym) }
114
137
  scope "not_#{type}".to_sym, -> { where.not(type_of_meeting: type.to_sym) }
@@ -215,7 +238,7 @@ module Decidim
215
238
  end
216
239
 
217
240
  def current_user_can_visit_meeting?(user)
218
- Decidim::Meetings::Meeting.visible_meeting_for(user).exists?(id: id)
241
+ Decidim::Meetings::Meeting.visible_for(user).exists?(id: id)
219
242
  end
220
243
 
221
244
  def iframe_access_level_allowed_for_user?(user)
@@ -342,13 +365,9 @@ module Decidim
342
365
  order(Arel::Nodes::InfixOperation.new("", field, Arel.sql("DESC")))
343
366
  end
344
367
 
345
- ransacker :type do
346
- Arel.sql(%("decidim_meetings_meetings"."type_of_meeting"))
347
- end
348
-
349
- ransacker :title do
350
- Arel.sql(%{cast("decidim_meetings_meetings"."title" as text)})
351
- end
368
+ # Create i18n ransackers for :title and :description.
369
+ # Create the :search_text ransacker alias for searching from both of these.
370
+ ransacker_i18n_multi :search_text, [:title, :description]
352
371
 
353
372
  ransacker :id_string do
354
373
  Arel.sql(%{cast("decidim_meetings_meetings"."id" as text)})
@@ -358,13 +377,12 @@ module Decidim
358
377
  Arel.sql("(start_time > NOW())")
359
378
  end
360
379
 
361
- ransacker :origin do
362
- Arel.sql("CASE
363
- WHEN decidim_author_type = 'Decidim::Organization' THEN 'official'
364
- WHEN decidim_author_type = 'Decidim::UserBaseEntity' AND decidim_user_group_id IS NOT NULL THEN 'user_group'
365
- WHEN decidim_author_type = 'Decidim::UserBaseEntity' AND decidim_user_group_id IS NULL THEN 'citizen'
366
- ELSE 'unknown' END
367
- ")
380
+ def self.ransackable_scopes(_auth_object = nil)
381
+ [:with_any_type, :with_any_date, :with_any_space, :with_any_origin, :with_any_scope, :with_any_category, :with_any_global_category]
382
+ end
383
+
384
+ def self.ransack(params = {}, options = {})
385
+ MeetingSearch.new(self, params, options)
368
386
  end
369
387
 
370
388
  private
@@ -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::DataPortability
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::DataPortabilityRegistrationSerializer
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
@@ -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