decidim-meetings 0.21.0 → 0.23.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/decidim_meetings_manifest.js +2 -0
  3. data/app/assets/images/decidim/gamification/badges/attended_meetings.svg +1 -106
  4. data/app/assets/images/decidim/meetings/icon.svg +1 -5
  5. data/app/assets/javascripts/decidim/meetings/admin/destroy_meeting_alert.js.es6 +16 -0
  6. data/app/assets/javascripts/decidim/meetings/admin/meetings_form.js.es6 +3 -0
  7. data/app/assets/javascripts/decidim/meetings/meetings_form.js.es6 +9 -0
  8. data/app/cells/decidim/meetings/content_blocks/upcoming_events_cell.rb +2 -1
  9. data/app/cells/decidim/meetings/highlighted_meetings_for_component/show.erb +7 -7
  10. data/app/cells/decidim/meetings/highlighted_meetings_for_component_cell.rb +1 -1
  11. data/app/cells/decidim/meetings/join_meeting_button/show.erb +2 -2
  12. data/app/cells/decidim/meetings/meeting_cell.rb +1 -0
  13. data/app/cells/decidim/meetings/meeting_list_item/show.erb +3 -3
  14. data/app/cells/decidim/meetings/meeting_list_item_cell.rb +1 -1
  15. data/app/cells/decidim/meetings/meeting_m/date.erb +1 -1
  16. data/app/cells/decidim/meetings/meeting_m/footer.erb +1 -1
  17. data/app/cells/decidim/meetings/meeting_m/multiple_dates.erb +1 -1
  18. data/app/cells/decidim/meetings/meeting_m_cell.rb +9 -1
  19. data/app/cells/decidim/meetings/meeting_s/show.erb +6 -6
  20. data/app/cells/decidim/meetings/meetings_map/show.erb +0 -2
  21. data/app/cells/decidim/meetings/meetings_map_cell.rb +3 -1
  22. data/app/commands/decidim/meetings/admin/close_meeting.rb +1 -2
  23. data/app/commands/decidim/meetings/admin/copy_meeting.rb +38 -28
  24. data/app/commands/decidim/meetings/admin/create_meeting.rb +36 -24
  25. data/app/commands/decidim/meetings/admin/destroy_meeting.rb +6 -1
  26. data/app/commands/decidim/meetings/admin/invite_user_to_join_meeting.rb +2 -1
  27. data/app/commands/decidim/meetings/admin/update_meeting.rb +9 -3
  28. data/app/commands/decidim/meetings/create_meeting.rb +78 -0
  29. data/app/commands/decidim/meetings/update_meeting.rb +94 -0
  30. data/app/controllers/decidim/meetings/admin/application_controller.rb +1 -1
  31. data/app/controllers/decidim/meetings/admin/meeting_closes_controller.rb +2 -0
  32. data/app/controllers/decidim/meetings/admin/meetings_controller.rb +21 -7
  33. data/app/controllers/decidim/meetings/admin/registration_form_controller.rb +4 -0
  34. data/app/controllers/decidim/meetings/meetings_controller.rb +76 -13
  35. data/app/controllers/decidim/meetings/registrations_controller.rb +1 -1
  36. data/app/controllers/decidim/meetings/versions_controller.rb +14 -0
  37. data/app/controllers/decidim/meetings/{meeting_widgets_controller.rb → widgets_controller.rb} +2 -2
  38. data/app/forms/decidim/meetings/admin/close_meeting_form.rb +7 -1
  39. data/app/forms/decidim/meetings/admin/meeting_copy_form.rb +2 -8
  40. data/app/forms/decidim/meetings/admin/meeting_form.rb +24 -23
  41. data/app/forms/decidim/meetings/meeting_form.rb +78 -0
  42. data/app/helpers/decidim/meetings/admin/application_helper.rb +1 -6
  43. data/app/helpers/decidim/meetings/application_helper.rb +26 -0
  44. data/app/helpers/decidim/meetings/map_helper.rb +2 -1
  45. data/app/helpers/decidim/meetings/meetings_helper.rb +13 -1
  46. data/app/models/decidim/meetings/agenda.rb +3 -0
  47. data/app/models/decidim/meetings/agenda_item.rb +3 -0
  48. data/app/models/decidim/meetings/meeting.rb +79 -23
  49. data/app/models/decidim/meetings/minutes.rb +3 -0
  50. data/app/models/decidim/meetings/service.rb +13 -0
  51. data/app/permissions/decidim/meetings/admin/permissions.rb +2 -0
  52. data/app/permissions/decidim/meetings/permissions.rb +20 -0
  53. data/app/presenters/decidim/meetings/admin_log/invite_presenter.rb +5 -1
  54. data/app/presenters/decidim/meetings/admin_log/meeting_presenter.rb +3 -4
  55. data/app/presenters/decidim/meetings/meeting_presenter.rb +21 -6
  56. data/app/presenters/decidim/meetings/official_author_presenter.rb +14 -0
  57. data/app/queries/decidim/meetings/filtered_meetings.rb +1 -1
  58. data/app/queries/decidim/meetings/metrics/meetings_metric_manage.rb +2 -8
  59. data/app/services/decidim/meetings/calendar/meeting_to_event.rb +1 -1
  60. data/app/services/decidim/meetings/diff_renderer.rb +21 -0
  61. data/app/services/decidim/meetings/meeting_search.rb +3 -25
  62. data/app/types/decidim/meetings/meeting_type.rb +1 -1
  63. data/app/views/decidim/meetings/_calendar_modal.html.erb +4 -4
  64. data/app/views/decidim/meetings/admin/invites/index.html.erb +2 -2
  65. data/app/views/decidim/meetings/admin/meeting_closes/_form.html.erb +1 -6
  66. data/app/views/decidim/meetings/admin/meeting_closes/proposals_picker.html.erb +1 -0
  67. data/app/views/decidim/meetings/admin/meeting_copies/_form.html.erb +2 -9
  68. data/app/views/decidim/meetings/admin/meetings/_form.html.erb +5 -12
  69. data/app/views/decidim/meetings/admin/meetings/edit.html.erb +1 -1
  70. data/app/views/decidim/meetings/admin/meetings/index.html.erb +22 -3
  71. data/app/views/decidim/meetings/admin/registrations/_form.html.erb +4 -0
  72. data/app/views/decidim/meetings/directory/meetings/index.html.erb +5 -3
  73. data/app/views/decidim/meetings/directory/meetings/index.js.erb +11 -4
  74. data/app/views/decidim/meetings/meetings/_count.html.erb +1 -0
  75. data/app/views/decidim/meetings/meetings/_filters.html.erb +13 -7
  76. data/app/views/decidim/meetings/meetings/_form.html.erb +51 -0
  77. data/app/views/decidim/meetings/meetings/_linked_meetings.html.erb +2 -2
  78. data/app/views/decidim/meetings/meetings/_meeting_agenda.html.erb +2 -2
  79. data/app/views/decidim/meetings/meetings/_meeting_minutes.html.erb +8 -8
  80. data/app/views/decidim/meetings/meetings/edit.html.erb +25 -0
  81. data/app/views/decidim/meetings/meetings/index.html.erb +16 -1
  82. data/app/views/decidim/meetings/meetings/index.js.erb +13 -4
  83. data/app/views/decidim/meetings/meetings/new.html.erb +25 -0
  84. data/app/views/decidim/meetings/meetings/show.html.erb +32 -8
  85. data/app/views/decidim/meetings/versions/index.html.erb +8 -0
  86. data/app/views/decidim/meetings/versions/show.html.erb +10 -0
  87. data/app/views/decidim/participatory_processes/participatory_process_groups/_meeting.html.erb +2 -2
  88. data/app/views/decidim/participatory_spaces/_conference_venues.html.erb +1 -1
  89. data/app/views/decidim/participatory_spaces/_upcoming_meeting_for_card.html.erb +1 -3
  90. data/config/locales/am-ET.yml +1 -0
  91. data/config/locales/ar.yml +0 -8
  92. data/config/locales/bg-BG.yml +21 -0
  93. data/config/locales/bg.yml +21 -0
  94. data/config/locales/ca.yml +60 -7
  95. data/config/locales/cs.yml +68 -9
  96. data/config/locales/da-DK.yml +1 -0
  97. data/config/locales/da.yml +1 -0
  98. data/config/locales/de.yml +128 -71
  99. data/config/locales/el.yml +448 -0
  100. data/config/locales/en.yml +61 -8
  101. data/config/locales/eo.yml +1 -0
  102. data/config/locales/es-MX.yml +60 -7
  103. data/config/locales/es-PY.yml +61 -8
  104. data/config/locales/es.yml +61 -8
  105. data/config/locales/et-EE.yml +1 -0
  106. data/config/locales/et.yml +1 -0
  107. data/config/locales/eu.yml +0 -8
  108. data/config/locales/fi-plain.yml +60 -7
  109. data/config/locales/fi.yml +183 -130
  110. data/config/locales/fr-CA.yml +504 -0
  111. data/config/locales/fr.yml +60 -7
  112. data/config/locales/ga-IE.yml +1 -0
  113. data/config/locales/gl.yml +3 -7
  114. data/config/locales/hr-HR.yml +1 -0
  115. data/config/locales/hr.yml +1 -0
  116. data/config/locales/hu.yml +11 -7
  117. data/config/locales/id-ID.yml +0 -8
  118. data/config/locales/is-IS.yml +0 -9
  119. data/config/locales/is.yml +228 -0
  120. data/config/locales/it.yml +58 -7
  121. data/config/locales/ja-JP.yml +494 -0
  122. data/config/locales/ja.yml +496 -0
  123. data/config/locales/ko-KR.yml +1 -0
  124. data/config/locales/ko.yml +1 -0
  125. data/config/locales/lt-LT.yml +1 -0
  126. data/config/locales/lt.yml +1 -0
  127. data/config/locales/lv.yml +452 -0
  128. data/config/locales/mt-MT.yml +1 -0
  129. data/config/locales/mt.yml +1 -0
  130. data/config/locales/nl.yml +52 -7
  131. data/config/locales/no.yml +35 -9
  132. data/config/locales/om-ET.yml +1 -0
  133. data/config/locales/pl.yml +210 -147
  134. data/config/locales/pt-BR.yml +2 -10
  135. data/config/locales/pt.yml +232 -177
  136. data/config/locales/ro-RO.yml +500 -0
  137. data/config/locales/ru.yml +0 -8
  138. data/config/locales/si-LK.yml +1 -0
  139. data/config/locales/sk-SK.yml +463 -0
  140. data/config/locales/sk.yml +458 -0
  141. data/config/locales/sl.yml +33 -0
  142. data/config/locales/so-SO.yml +1 -0
  143. data/config/locales/sr-CS.yml +13 -0
  144. data/config/locales/sv.yml +67 -13
  145. data/config/locales/sw-KE.yml +1 -0
  146. data/config/locales/ti-ER.yml +1 -0
  147. data/config/locales/tr-TR.yml +154 -98
  148. data/config/locales/uk.yml +0 -9
  149. data/config/locales/vi-VN.yml +1 -0
  150. data/config/locales/vi.yml +1 -0
  151. data/config/locales/zh-CN.yml +496 -0
  152. data/config/locales/zh-TW.yml +1 -0
  153. data/db/migrate/20200320105922_index_foreign_keys_in_decidim_meetings_registrations.rb +7 -0
  154. data/db/migrate/20200526110940_add_author_to_meetings.rb +30 -0
  155. data/db/migrate/20200702123209_create_meeting_services_table.rb +13 -0
  156. data/db/migrate/20200702123210_move_meeting_services_to_own_model.rb +31 -0
  157. data/db/migrate/20200827153856_add_commentable_counter_cache_to_meetings.rb +9 -0
  158. data/db/migrate/20201016065302_fix_meetings_registration_terms.rb +29 -0
  159. data/db/migrate/20201111133246_add_salt_to_decidim_meetings.rb +8 -0
  160. data/lib/decidim/api/services_interface.rb +1 -7
  161. data/lib/decidim/meetings/admin_engine.rb +5 -1
  162. data/lib/decidim/meetings/component.rb +63 -11
  163. data/lib/decidim/meetings/engine.rb +3 -6
  164. data/lib/decidim/meetings/meeting_serializer.rb +1 -1
  165. data/lib/decidim/meetings/seeds/city.jpeg +0 -0
  166. data/lib/decidim/meetings/test/factories.rb +46 -8
  167. data/lib/decidim/meetings/version.rb +1 -1
  168. data/lib/tasks/decidim_meetings.rake +16 -0
  169. metadata +88 -23
  170. data/app/presenters/decidim/meetings/admin_log/value_types/organizer_presenter.rb +0 -70
@@ -30,7 +30,7 @@ module Decidim
30
30
  end
31
31
 
32
32
  def create
33
- enforce_permission_to :join, :meeting, meeting: meeting
33
+ enforce_permission_to :register, :meeting, meeting: meeting
34
34
 
35
35
  @form = JoinMeetingForm.from_params(params)
36
36
 
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ # Exposes the meeting resource so users can view them
6
+ class VersionsController < Decidim::Meetings::ApplicationController
7
+ include Decidim::ResourceVersionsConcern
8
+
9
+ def versioned_resource
10
+ @versioned_resource ||= Meeting.not_hidden.where(component: current_component).find(params[:meeting_id])
11
+ end
12
+ end
13
+ end
14
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Decidim
4
4
  module Meetings
5
- class MeetingWidgetsController < Decidim::WidgetsController
5
+ class WidgetsController < Decidim::WidgetsController
6
6
  helper MeetingsHelper
7
7
  helper Decidim::SanitizeHelper
8
8
 
@@ -13,7 +13,7 @@ module Decidim
13
13
  end
14
14
 
15
15
  def iframe_url
16
- @iframe_url ||= meeting_meeting_widget_url(model)
16
+ @iframe_url ||= meeting_widget_url(model)
17
17
  end
18
18
  end
19
19
  end
@@ -25,7 +25,13 @@ module Decidim
25
25
  # Returns nothing.
26
26
  def map_model(model)
27
27
  self.proposal_ids = model.linked_resources(:proposals, "proposals_from_meeting").pluck(:id)
28
- self.proposals = model.sibling_scope(:proposals)
28
+ end
29
+
30
+ def proposals
31
+ @proposals ||= Decidim.find_resource_manifest(:proposals)
32
+ .try(:resource_scope, current_component)
33
+ &.where(id: proposal_ids)
34
+ &.order(title: :asc)
29
35
  end
30
36
  end
31
37
  end
@@ -21,7 +21,6 @@ module Decidim
21
21
  attribute :end_time, Decidim::Attributes::TimeWithZone
22
22
  attribute :private_meeting, Boolean
23
23
  attribute :transparent, Boolean
24
- attribute :organizer_id, Integer
25
24
  attribute :services, Array[MeetingServiceForm]
26
25
 
27
26
  mimic :meeting
@@ -32,14 +31,13 @@ module Decidim
32
31
  validates :description, translatable_presence: true
33
32
  validates :location, translatable_presence: true
34
33
  validates :address, presence: true
35
- validates :address, geocoding: true, if: -> { Decidim.geocoder.present? }
34
+ validates :address, geocoding: true, if: -> { Decidim::Map.available?(:geocoding) }
36
35
  validates :start_time, presence: true, date: { before: :end_time }
37
36
  validates :end_time, presence: true, date: { after: :start_time }
38
- validates :organizer, presence: true, if: ->(form) { form.organizer_id.present? }
39
37
 
40
38
  def map_model(model)
41
39
  self.services = model.services.map do |service|
42
- MeetingServiceForm.new(service)
40
+ MeetingServiceForm.new(service.attributes)
43
41
  end
44
42
  end
45
43
 
@@ -53,10 +51,6 @@ module Decidim
53
51
 
54
52
  alias component current_component
55
53
 
56
- def organizer
57
- @organizer ||= current_organization.users.find_by(id: organizer_id)
58
- end
59
-
60
54
  def questionnaire
61
55
  Decidim::Forms::Questionnaire.new
62
56
  end
@@ -3,15 +3,10 @@
3
3
  module Decidim
4
4
  module Meetings
5
5
  module Admin
6
- # This class holds a Form to create/update meetings from Decidim's admin panel.
6
+ # This class holds a Form to create/update translatable meetings from Decidim's admin panel.
7
7
  class MeetingForm < Decidim::Form
8
8
  include TranslatableAttributes
9
9
 
10
- translatable_attribute :title, String
11
- translatable_attribute :description, String
12
- translatable_attribute :location, String
13
- translatable_attribute :location_hints, String
14
-
15
10
  attribute :address, String
16
11
  attribute :latitude, Float
17
12
  attribute :longitude, Float
@@ -22,34 +17,38 @@ module Decidim
22
17
  attribute :decidim_category_id, Integer
23
18
  attribute :private_meeting, Boolean
24
19
  attribute :transparent, Boolean
25
- attribute :organizer_id, Integer
20
+
21
+ translatable_attribute :title, String
22
+ translatable_attribute :description, String
23
+ translatable_attribute :location, String
24
+ translatable_attribute :location_hints, String
26
25
 
27
26
  validates :title, translatable_presence: true
28
27
  validates :description, translatable_presence: true
29
28
  validates :location, translatable_presence: true
29
+
30
30
  validates :address, presence: true
31
- validates :address, geocoding: true, if: -> { Decidim.geocoder.present? }
31
+ validates :address, geocoding: true, if: ->(form) { form.has_address? && !form.geocoded? }
32
32
  validates :start_time, presence: true, date: { before: :end_time }
33
33
  validates :end_time, presence: true, date: { after: :start_time }
34
34
 
35
35
  validates :current_component, presence: true
36
36
  validates :category, presence: true, if: ->(form) { form.decidim_category_id.present? }
37
37
  validates :scope, presence: true, if: ->(form) { form.decidim_scope_id.present? }
38
- validates :organizer, presence: true, if: ->(form) { form.organizer_id.present? }
39
-
40
- validate :scope_belongs_to_participatory_space_scope
38
+ validates :decidim_scope_id, scope_belongs_to_component: true, if: ->(form) { form.decidim_scope_id.present? }
41
39
 
42
40
  delegate :categories, to: :current_component
43
41
 
44
42
  def map_model(model)
45
43
  self.services = model.services.map do |service|
46
- MeetingServiceForm.new(service)
44
+ MeetingServiceForm.from_model(service)
47
45
  end
48
46
 
49
47
  self.decidim_category_id = model.categorization.decidim_category_id if model.categorization
50
48
  presenter = MeetingPresenter.new(model)
51
- self.title = presenter.title(all_locales: true)
52
- self.description = presenter.description(all_locales: true)
49
+
50
+ self.title = presenter.title(all_locales: title.is_a?(Hash))
51
+ self.description = presenter.description(all_locales: description.is_a?(Hash))
53
52
  end
54
53
 
55
54
  def services_to_persist
@@ -60,17 +59,13 @@ module Decidim
60
59
  services.size
61
60
  end
62
61
 
63
- def organizer
64
- @organizer ||= current_organization.users.find_by(id: organizer_id)
65
- end
66
-
67
62
  alias component current_component
68
63
 
69
- # Finds the Scope from the given decidim_scope_id, uses participatory space scope if missing.
64
+ # Finds the Scope from the given decidim_scope_id, uses component scope if missing.
70
65
  #
71
66
  # Returns a Decidim::Scope
72
67
  def scope
73
- @scope ||= @decidim_scope_id ? current_participatory_space.scopes.find_by(id: @decidim_scope_id) : current_participatory_space.scope
68
+ @scope ||= @decidim_scope_id ? current_component.scopes.find_by(id: @decidim_scope_id) : current_component.scope
74
69
  end
75
70
 
76
71
  # Scope identifier
@@ -86,10 +81,16 @@ module Decidim
86
81
  @category ||= categories.find_by(id: decidim_category_id)
87
82
  end
88
83
 
89
- private
84
+ def geocoding_enabled?
85
+ Decidim::Map.available?(:geocoding)
86
+ end
87
+
88
+ def has_address?
89
+ geocoding_enabled? && address.present?
90
+ end
90
91
 
91
- def scope_belongs_to_participatory_space_scope
92
- errors.add(:decidim_scope_id, :invalid) if current_participatory_space.out_of_scope?(scope)
92
+ def geocoded?
93
+ latitude.present? && longitude.present?
93
94
  end
94
95
  end
95
96
  end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ # This class holds a Form to create/update meetings for Participants and UserGroups.
6
+ class MeetingForm < Decidim::Form
7
+ attribute :title, String
8
+ attribute :description, String
9
+ attribute :location, String
10
+ attribute :location_hints, String
11
+
12
+ attribute :address, String
13
+ attribute :latitude, Float
14
+ attribute :longitude, Float
15
+ attribute :start_time, Decidim::Attributes::TimeWithZone
16
+ attribute :end_time, Decidim::Attributes::TimeWithZone
17
+ attribute :decidim_scope_id, Integer
18
+ attribute :decidim_category_id, Integer
19
+ attribute :user_group_id, Integer
20
+
21
+ validates :title, presence: true
22
+ validates :description, presence: true
23
+ validates :location, presence: true
24
+ validates :address, presence: true
25
+ validates :address, geocoding: true, if: ->(form) { form.has_address? && !form.geocoded? }
26
+ validates :start_time, presence: true, date: { before: :end_time }
27
+ validates :end_time, presence: true, date: { after: :start_time }
28
+
29
+ validates :current_component, presence: true
30
+ validates :category, presence: true, if: ->(form) { form.decidim_category_id.present? }
31
+ validates :scope, presence: true, if: ->(form) { form.decidim_scope_id.present? }
32
+ validates :decidim_scope_id, scope_belongs_to_component: true, if: ->(form) { form.decidim_scope_id.present? }
33
+
34
+ delegate :categories, to: :current_component
35
+
36
+ def map_model(model)
37
+ self.decidim_category_id = model.categorization.decidim_category_id if model.categorization
38
+ presenter = MeetingPresenter.new(model)
39
+ self.title = presenter.title(all_locales: false)
40
+ self.description = presenter.description(all_locales: false)
41
+ end
42
+
43
+ alias component current_component
44
+
45
+ # Finds the Scope from the given decidim_scope_id, uses the compoenent scope if missing.
46
+ #
47
+ # Returns a Decidim::Scope
48
+ def scope
49
+ @scope ||= @decidim_scope_id ? current_component.scopes.find_by(id: @decidim_scope_id) : current_component.scope
50
+ end
51
+
52
+ # Scope identifier
53
+ #
54
+ # Returns the scope identifier related to the meeting
55
+ def decidim_scope_id
56
+ @decidim_scope_id || scope&.id
57
+ end
58
+
59
+ def category
60
+ return unless current_component
61
+
62
+ @category ||= categories.find_by(id: decidim_category_id)
63
+ end
64
+
65
+ def geocoding_enabled?
66
+ Decidim::Map.available?(:geocoding)
67
+ end
68
+
69
+ def has_address?
70
+ geocoding_enabled? && address.present?
71
+ end
72
+
73
+ def geocoded?
74
+ latitude.present? && longitude.present?
75
+ end
76
+ end
77
+ end
78
+ end
@@ -7,12 +7,7 @@ module Decidim
7
7
  #
8
8
  module ApplicationHelper
9
9
  include Decidim::MapHelper
10
-
11
- def meeting_organizer_picker_text(form)
12
- return "" if form.object.organizer.blank?
13
-
14
- "#{form.object.organizer.name} (@#{form.object.organizer.nickname})"
15
- end
10
+ include Decidim::Admin::ResourceScopeHelper
16
11
 
17
12
  def tabs_id_for_service(service)
18
13
  "meeting_service_#{service.to_param}"
@@ -10,6 +10,32 @@ module Decidim
10
10
  include Decidim::Meetings::MapHelper
11
11
  include Decidim::Meetings::MeetingsHelper
12
12
  include Decidim::Comments::CommentsHelper
13
+ include Decidim::SanitizeHelper
14
+ include Decidim::CheckBoxesTreeHelper
15
+
16
+ def filter_origin_values
17
+ origin_values = []
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
20
+ # if component_settings enabled enabled
21
+ origin_values << TreePoint.new("user_group", t("decidim.meetings.meetings.filters.origin_values.user_groups")) # todo
22
+ # if current_organization.user_groups_enabled? and component_settings enabled enabled
23
+
24
+ TreeNode.new(
25
+ TreePoint.new("", t("decidim.meetings.meetings.filters.origin_values.all")),
26
+ origin_values
27
+ )
28
+ end
29
+
30
+ def filter_date_values
31
+ TreeNode.new(
32
+ TreePoint.new("", t("decidim.meetings.meetings.filters.date_values.all")),
33
+ [
34
+ TreePoint.new("upcoming", t("decidim.meetings.meetings.filters.date_values.upcoming")),
35
+ TreePoint.new("past", t("decidim.meetings.meetings.filters.date_values.past"))
36
+ ]
37
+ )
38
+ end
13
39
  end
14
40
  end
15
41
  end
@@ -4,6 +4,7 @@ module Decidim
4
4
  module Meetings
5
5
  # This helper include some methods for rendering meetings dynamic maps.
6
6
  module MapHelper
7
+ include Decidim::SanitizeHelper
7
8
  # Serialize a collection of geocoded meetings to be used by the dynamic map component
8
9
  #
9
10
  # meetings - A collection of meetings
@@ -18,7 +19,7 @@ module Decidim
18
19
  startTime: "#{meeting.start_time.strftime("%H:%M")} - #{meeting.end_time.strftime("%H:%M")}",
19
20
  icon: icon("meetings", width: 40, height: 70, remove_icon_class: true),
20
21
  location: translated_attribute(meeting.location),
21
- locationHints: translated_attribute(meeting.location_hints),
22
+ locationHints: decidim_html_escape(translated_attribute(meeting.location_hints)),
22
23
  link: resource_locator(meeting).path)
23
24
  end
24
25
  end
@@ -16,7 +16,7 @@ module Decidim
16
16
  # Returns the meeting's description truncated.
17
17
  def meeting_description(meeting, max_length = 120)
18
18
  link = resource_locator(meeting).path
19
- description = present(meeting).description
19
+ description = CGI.unescapeHTML present(meeting).description
20
20
  tail = "... #{link_to(t("read_more", scope: "decidim.meetings"), link)}".html_safe
21
21
  CGI.unescapeHTML html_truncate(description, max_length: max_length, tail: tail)
22
22
  end
@@ -107,6 +107,18 @@ module Decidim
107
107
  t("validation_pending", scope: "decidim.meetings.meetings.show.registration_state")
108
108
  end
109
109
  end
110
+
111
+ def author_presenter_for(author)
112
+ if author.is_a?(Decidim::Organization)
113
+ Decidim::Meetings::OfficialAuthorPresenter.new
114
+ else
115
+ present(author)
116
+ end
117
+ end
118
+
119
+ def current_user_groups?
120
+ current_organization.user_groups_enabled? && Decidim::UserGroups::ManageableUserGroups.for(current_user).verified.any?
121
+ end
110
122
  end
111
123
  end
112
124
  end
@@ -7,6 +7,9 @@ module Decidim
7
7
  class Agenda < Meetings::ApplicationRecord
8
8
  include Decidim::Traceable
9
9
  include Decidim::Loggable
10
+ include Decidim::TranslatableResource
11
+
12
+ translatable_fields :title
10
13
 
11
14
  belongs_to :meeting, foreign_key: "decidim_meeting_id", class_name: "Decidim::Meetings::Meeting"
12
15
  has_many :agenda_items, foreign_key: "decidim_agenda_id", class_name: "Decidim::Meetings::AgendaItem", dependent: :destroy, inverse_of: :agenda
@@ -7,6 +7,9 @@ module Decidim
7
7
  class AgendaItem < Meetings::ApplicationRecord
8
8
  include Decidim::Traceable
9
9
  include Decidim::Loggable
10
+ include Decidim::TranslatableResource
11
+
12
+ translatable_fields :title, :description
10
13
 
11
14
  belongs_to :agenda, -> { order(:position) }, foreign_key: "decidim_agenda_id", class_name: "Decidim::Meetings::Agenda"
12
15
 
@@ -10,40 +10,72 @@ module Decidim
10
10
  include Decidim::HasAttachmentCollections
11
11
  include Decidim::HasComponent
12
12
  include Decidim::HasReference
13
- include Decidim::ScopableComponent
13
+ include Decidim::ScopableResource
14
14
  include Decidim::HasCategory
15
15
  include Decidim::Followable
16
16
  include Decidim::Comments::Commentable
17
17
  include Decidim::Searchable
18
18
  include Decidim::Traceable
19
19
  include Decidim::Loggable
20
- include Decidim::Hashtaggable
21
20
  include Decidim::Forms::HasQuestionnaire
22
21
  include Decidim::Paddable
23
22
  include Decidim::ActsAsAuthor
23
+ include Decidim::Reportable
24
+ include Decidim::Authorable
25
+ include Decidim::TranslatableResource
26
+
27
+ translatable_fields :title, :description, :location, :location_hints, :closing_report, :registration_terms
24
28
 
25
- belongs_to :organizer, foreign_key: "organizer_id", class_name: "Decidim::User", optional: true
26
29
  has_many :registrations, class_name: "Decidim::Meetings::Registration", foreign_key: "decidim_meeting_id", dependent: :destroy
27
30
  has_many :invites, class_name: "Decidim::Meetings::Invite", foreign_key: "decidim_meeting_id", dependent: :destroy
31
+ has_many :services, class_name: "Decidim::Meetings::Service", foreign_key: "decidim_meeting_id", dependent: :destroy
28
32
  has_one :minutes, class_name: "Decidim::Meetings::Minutes", foreign_key: "decidim_meeting_id", dependent: :destroy
29
33
  has_one :agenda, class_name: "Decidim::Meetings::Agenda", foreign_key: "decidim_meeting_id", dependent: :destroy
30
34
 
31
35
  component_manifest_name "meetings"
32
36
 
33
37
  validates :title, presence: true
34
- validate :organizer_belongs_to_organization
35
38
 
36
- geocoded_by :address, http_headers: ->(proposal) { { "Referer" => proposal.component.organization.host } }
39
+ geocoded_by :address
37
40
 
38
41
  scope :past, -> { where(arel_table[:end_time].lteq(Time.current)) }
39
42
  scope :upcoming, -> { where(arel_table[:end_time].gteq(Time.current)) }
40
43
 
41
44
  scope :visible_meeting_for, lambda { |user|
42
- joins("LEFT JOIN decidim_meetings_registrations ON
43
- decidim_meetings_registrations.decidim_meeting_id = #{table_name}.id")
44
- .where("(private_meeting = ? and decidim_meetings_registrations.decidim_user_id = ?)
45
- or private_meeting = ? or (private_meeting = ? and transparent = ?)", true, user, false, true, true).distinct
46
- }
45
+ (all.distinct if user&.admin?) ||
46
+ if user.present?
47
+ spaces = %w(assembly participatory_process)
48
+ spaces << "conference" if defined?(Decidim::Conference)
49
+ user_role_queries = spaces.map do |participatory_space_name|
50
+ "SELECT decidim_components.id FROM decidim_components
51
+ WHERE CONCAT(decidim_components.participatory_space_id, '-', decidim_components.participatory_space_type)
52
+ IN
53
+ (SELECT CONCAT(decidim_#{participatory_space_name}_user_roles.decidim_#{participatory_space_name}_id, '-Decidim::#{participatory_space_name.classify}')
54
+ FROM decidim_#{participatory_space_name}_user_roles WHERE decidim_#{participatory_space_name}_user_roles.decidim_user_id = ?)
55
+ "
56
+ end
57
+
58
+ where("decidim_meetings_meetings.private_meeting = ?
59
+ OR decidim_meetings_meetings.transparent = ?
60
+ OR decidim_meetings_meetings.id IN
61
+ (SELECT decidim_meetings_registrations.decidim_meeting_id FROM decidim_meetings_registrations WHERE decidim_meetings_registrations.decidim_user_id = ?)
62
+ OR decidim_meetings_meetings.decidim_component_id IN
63
+ (SELECT decidim_components.id FROM decidim_components
64
+ WHERE CONCAT(decidim_components.participatory_space_id, '-', decidim_components.participatory_space_type)
65
+ IN
66
+ (SELECT CONCAT(decidim_participatory_space_private_users.privatable_to_id, '-', decidim_participatory_space_private_users.privatable_to_type)
67
+ FROM decidim_participatory_space_private_users WHERE decidim_participatory_space_private_users.decidim_user_id = ?)
68
+ )
69
+ OR decidim_meetings_meetings.decidim_component_id IN
70
+ (
71
+ #{user_role_queries.compact.join(" UNION ")}
72
+ )
73
+ ", false, true, user.id, user.id, *user_role_queries.compact.map { user.id })
74
+ .distinct
75
+ else
76
+ visible
77
+ end
78
+ }
47
79
 
48
80
  scope :visible, -> { where("decidim_meetings_meetings.private_meeting != ? OR decidim_meetings_meetings.transparent = ?", true, true) }
49
81
 
@@ -57,6 +89,8 @@ module Decidim
57
89
  index_on_create: ->(meeting) { meeting.visible? },
58
90
  index_on_update: ->(meeting) { meeting.visible? })
59
91
 
92
+ after_initialize :set_default_salt
93
+
60
94
  # Return registrations of a particular meeting made by users representing a group
61
95
  def user_group_registrations
62
96
  registrations.where.not(decidim_user_group_id: nil)
@@ -76,6 +110,11 @@ module Decidim
76
110
  !closed? && registrations_enabled? && can_participate?(user)
77
111
  end
78
112
 
113
+ def can_register_invitation?(user)
114
+ !closed? && registrations_enabled? &&
115
+ can_participate_in_space?(user) && user_has_invitation_for_meeting?(user)
116
+ end
117
+
79
118
  def closed?
80
119
  closed_at.present?
81
120
  end
@@ -133,19 +172,8 @@ module Decidim
133
172
  can_participate_in_space?(user) && can_participate_in_meeting?(user)
134
173
  end
135
174
 
136
- def organizer_belongs_to_organization
137
- return if !organizer || !organization
138
-
139
- errors.add(:organizer, :invalid) unless organizer.organization == organization
140
- end
141
-
142
- def official?
143
- organizer.nil?
144
- end
145
-
146
- def current_user_can_visit_meeting?(current_user)
147
- (private_meeting? && registrations.exists?(decidim_user_id: current_user.try(:id))) ||
148
- !private_meeting? || (private_meeting? && transparent?)
175
+ def current_user_can_visit_meeting?(user)
176
+ Decidim::Meetings::Meeting.visible_meeting_for(user).find_by(id: id)
149
177
  end
150
178
 
151
179
  # Return the duration of the meeting in minutes
@@ -173,6 +201,22 @@ module Decidim
173
201
  (Time.current - end_time) < 72.hours
174
202
  end
175
203
 
204
+ def authored_proposals
205
+ Decidim::Proposals::Proposal
206
+ .joins(:coauthorships)
207
+ .where(
208
+ decidim_coauthorships: {
209
+ decidim_author_type: "Decidim::Meetings::Meeting",
210
+ decidim_author_id: id
211
+ }
212
+ )
213
+ end
214
+
215
+ # Public: Overrides the `reported_content_url` Reportable concern method.
216
+ def reported_content_url
217
+ ResourceLocatorPresenter.new(self).url
218
+ end
219
+
176
220
  private
177
221
 
178
222
  def can_participate_in_meeting?(user)
@@ -181,6 +225,18 @@ module Decidim
181
225
 
182
226
  registrations.exists?(decidim_user_id: user.id)
183
227
  end
228
+
229
+ def user_has_invitation_for_meeting?(user)
230
+ return true unless private_meeting?
231
+ return false unless user
232
+
233
+ invites.exists?(decidim_user_id: user.id)
234
+ end
235
+
236
+ # salt is used to generate secure hash in pads
237
+ def set_default_salt
238
+ self.salt ||= Tokenizer.random_salt
239
+ end
184
240
  end
185
241
  end
186
242
  end