decidim-meetings 0.23.0 → 0.27.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of decidim-meetings might be problematic. Click here for more details.

Files changed (322) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/meetings/content_blocks/highlighted_meetings/elements.erb +16 -0
  3. data/app/cells/decidim/meetings/content_blocks/highlighted_meetings/heading.erb +1 -0
  4. data/app/cells/decidim/meetings/content_blocks/highlighted_meetings_cell.rb +33 -0
  5. data/app/cells/decidim/meetings/content_blocks/{upcoming_events → upcoming_meetings}/show.erb +6 -6
  6. data/app/cells/decidim/meetings/content_blocks/{upcoming_events_cell.rb → upcoming_meetings_cell.rb} +13 -10
  7. data/app/cells/decidim/meetings/highlighted_meetings_for_component/show.erb +5 -4
  8. data/app/cells/decidim/meetings/highlighted_meetings_for_component_cell.rb +22 -1
  9. data/app/cells/decidim/meetings/join_meeting_button/registration_confirm.erb +6 -0
  10. data/app/cells/decidim/meetings/join_meeting_button/show.erb +15 -6
  11. data/app/cells/decidim/meetings/join_meeting_button_cell.rb +1 -1
  12. data/app/cells/decidim/meetings/meeting_activity_cell.rb +13 -5
  13. data/app/cells/decidim/meetings/meeting_cell.rb +2 -4
  14. data/app/cells/decidim/meetings/meeting_highlighted_list_item/show.erb +21 -0
  15. data/app/cells/decidim/meetings/meeting_highlighted_list_item_cell.rb +10 -0
  16. data/app/cells/decidim/meetings/meeting_list_item_cell.rb +11 -1
  17. data/app/cells/decidim/meetings/meeting_m/address.erb +5 -1
  18. data/app/cells/decidim/meetings/meeting_m_cell.rb +54 -0
  19. data/app/cells/decidim/meetings/meeting_s_cell.rb +22 -0
  20. data/app/cells/decidim/meetings/meeting_url/show.erb +20 -0
  21. data/app/cells/decidim/meetings/meeting_url_cell.rb +29 -0
  22. data/app/cells/decidim/meetings/meetings_map/show.erb +1 -1
  23. data/app/cells/decidim/meetings/meetings_map_cell.rb +7 -1
  24. data/app/cells/decidim/meetings/online_meeting_cell.rb +51 -0
  25. data/app/cells/decidim/meetings/online_meeting_link/show.erb +44 -0
  26. data/app/cells/decidim/meetings/online_meeting_link_cell.rb +23 -0
  27. data/app/cells/decidim/meetings/public_participants_list/show.erb +16 -0
  28. data/app/cells/decidim/meetings/public_participants_list_cell.rb +32 -0
  29. data/app/cells/decidim/meetings/question_responses/show.erb +7 -0
  30. data/app/cells/decidim/meetings/question_responses_cell.rb +72 -0
  31. data/app/cells/decidim/meetings/reported_content/show.erb +3 -0
  32. data/app/cells/decidim/meetings/reported_content_cell.rb +13 -0
  33. data/app/commands/decidim/meetings/admin/close_meeting.rb +4 -1
  34. data/app/commands/decidim/meetings/admin/copy_meeting.rb +1 -10
  35. data/app/commands/decidim/meetings/admin/create_agenda.rb +1 -1
  36. data/app/commands/decidim/meetings/admin/create_meeting.rb +16 -20
  37. data/app/commands/decidim/meetings/admin/destroy_meeting.rb +3 -1
  38. data/app/commands/decidim/meetings/admin/export_meeting_registrations.rb +1 -1
  39. data/app/commands/decidim/meetings/admin/invite_user_to_join_meeting.rb +10 -12
  40. data/app/commands/decidim/meetings/admin/publish_meeting.rb +74 -0
  41. data/app/commands/decidim/meetings/admin/unpublish_meeting.rb +45 -0
  42. data/app/commands/decidim/meetings/admin/update_agenda.rb +1 -1
  43. data/app/commands/decidim/meetings/admin/update_meeting.rb +17 -6
  44. data/app/commands/decidim/meetings/admin/update_question_status.rb +57 -0
  45. data/app/commands/decidim/meetings/admin/update_questionnaire.rb +96 -0
  46. data/app/commands/decidim/meetings/admin/update_registrations.rb +5 -3
  47. data/app/commands/decidim/meetings/admin/validate_registration_code.rb +3 -1
  48. data/app/commands/decidim/meetings/close_meeting.rb +68 -0
  49. data/app/commands/decidim/meetings/create_answer.rb +52 -0
  50. data/app/commands/decidim/meetings/create_meeting.rb +26 -5
  51. data/app/commands/decidim/meetings/decline_invitation.rb +1 -1
  52. data/app/commands/decidim/meetings/join_meeting.rb +17 -8
  53. data/app/commands/decidim/meetings/leave_meeting.rb +5 -5
  54. data/app/commands/decidim/meetings/update_meeting.rb +15 -4
  55. data/app/commands/decidim/meetings/withdraw_meeting.rb +39 -0
  56. data/app/controllers/concerns/decidim/meetings/admin/filterable.rb +55 -0
  57. data/app/controllers/concerns/decidim/meetings/filterable.rb +27 -0
  58. data/app/controllers/concerns/decidim/meetings/polls_resources.rb +29 -0
  59. data/app/controllers/decidim/meetings/admin/application_controller.rb +6 -2
  60. data/app/controllers/decidim/meetings/admin/invites_controller.rb +0 -2
  61. data/app/controllers/decidim/meetings/admin/meeting_closes_controller.rb +3 -3
  62. data/app/controllers/decidim/meetings/admin/meetings_controller.rb +46 -1
  63. data/app/controllers/decidim/meetings/admin/meetings_poll_controller.rb +107 -0
  64. data/app/controllers/decidim/meetings/calendars_controller.rb +9 -1
  65. data/app/controllers/decidim/meetings/directory/application_controller.rb +16 -0
  66. data/app/controllers/decidim/meetings/directory/meetings_controller.rb +40 -26
  67. data/app/controllers/decidim/meetings/live_events_controller.rb +35 -0
  68. data/app/controllers/decidim/meetings/meeting_closes_controller.rb +43 -0
  69. data/app/controllers/decidim/meetings/meetings_controller.rb +43 -29
  70. data/app/controllers/decidim/meetings/polls/answers_controller.rb +37 -0
  71. data/app/controllers/decidim/meetings/polls/questions_controller.rb +45 -0
  72. data/app/events/decidim/meetings/close_meeting_event.rb +1 -3
  73. data/app/events/decidim/meetings/create_meeting_event.rb +16 -2
  74. data/app/events/decidim/meetings/meeting_event.rb +37 -0
  75. data/app/events/decidim/meetings/meeting_registration_notification_event.rb +1 -1
  76. data/app/events/decidim/meetings/meeting_registrations_enabled_event.rb +1 -3
  77. data/app/events/decidim/meetings/meeting_registrations_over_percentage_event.rb +2 -4
  78. data/app/events/decidim/meetings/registration_code_validated_event.rb +2 -4
  79. data/app/events/decidim/meetings/upcoming_meeting_event.rb +1 -3
  80. data/app/events/decidim/meetings/update_meeting_event.rb +1 -3
  81. data/app/forms/decidim/meetings/admin/answer_option_form.rb +24 -0
  82. data/app/forms/decidim/meetings/admin/close_meeting_form.rb +9 -7
  83. data/app/forms/decidim/meetings/admin/meeting_copy_form.rb +4 -13
  84. data/app/forms/decidim/meetings/admin/meeting_form.rb +76 -26
  85. data/app/forms/decidim/meetings/admin/meeting_registration_invite_form.rb +1 -1
  86. data/app/forms/decidim/meetings/admin/meeting_registrations_form.rb +17 -4
  87. data/app/forms/decidim/meetings/admin/question_form.rb +44 -0
  88. data/app/forms/decidim/meetings/admin/questionnaire_form.rb +19 -0
  89. data/app/forms/decidim/meetings/answer_choice_form.rb +14 -0
  90. data/app/forms/decidim/meetings/answer_form.rb +64 -0
  91. data/app/forms/decidim/meetings/base_meeting_form.rb +59 -0
  92. data/app/forms/decidim/meetings/close_meeting_form.rb +35 -0
  93. data/app/forms/decidim/meetings/join_meeting_form.rb +1 -0
  94. data/app/forms/decidim/meetings/meeting_form.rb +83 -22
  95. data/app/helpers/decidim/meetings/admin/filterable_helper.rb +13 -0
  96. data/app/helpers/decidim/meetings/application_helper.rb +59 -10
  97. data/app/helpers/decidim/meetings/directory/application_helper.rb +148 -0
  98. data/app/helpers/decidim/meetings/map_helper.rb +2 -2
  99. data/app/helpers/decidim/meetings/meeting_cells_helper.rb +4 -1
  100. data/app/helpers/decidim/meetings/meetings_helper.rb +23 -1
  101. data/app/jobs/decidim/meetings/send_close_meeting_reminder_job.rb +17 -0
  102. data/app/jobs/decidim/meetings/upcoming_meeting_notification_job.rb +4 -1
  103. data/app/mailers/decidim/meetings/close_meeting_reminder_mailer.rb +43 -0
  104. data/app/models/decidim/meetings/agenda_item.rb +2 -2
  105. data/app/models/decidim/meetings/answer.rb +48 -0
  106. data/app/models/decidim/meetings/answer_choice.rb +15 -0
  107. data/app/models/decidim/meetings/answer_option.rb +24 -0
  108. data/app/models/decidim/meetings/invite.rb +2 -2
  109. data/app/models/decidim/meetings/meeting.rb +230 -24
  110. data/app/models/decidim/meetings/poll.rb +19 -0
  111. data/app/models/decidim/meetings/question.rb +54 -0
  112. data/app/models/decidim/meetings/questionnaire.rb +29 -0
  113. data/app/models/decidim/meetings/registration.rb +4 -2
  114. data/app/packs/entrypoints/decidim_meetings.js +6 -0
  115. data/app/packs/entrypoints/decidim_meetings_admin.js +5 -0
  116. data/app/{assets/images/decidim/gamification/badges/attended_meetings.svg → packs/images/decidim/gamification/badges/decidim_gamification_badges_attended_meetings.svg} +0 -0
  117. data/app/{assets/images/decidim/meetings/icon.svg → packs/images/decidim/meetings/decidim_meetings.svg} +0 -0
  118. data/app/packs/src/decidim/meetings/admin/agendas.js +159 -0
  119. data/app/{assets/javascripts/decidim/meetings/admin/destroy_meeting_alert.js.es6 → packs/src/decidim/meetings/admin/destroy_meeting_alert.js} +0 -0
  120. data/app/{assets/javascripts/decidim/meetings/admin/meetings_form.js.es6 → packs/src/decidim/meetings/admin/meetings_form.js} +67 -5
  121. data/app/{assets/javascripts/decidim/meetings/admin/registrations_form.js.es6 → packs/src/decidim/meetings/admin/registrations_form.js} +2 -0
  122. data/app/{assets/javascripts/decidim/meetings/admin/registrations_invite_form.es6 → packs/src/decidim/meetings/admin/registrations_invite_form.js} +3 -3
  123. data/app/packs/src/decidim/meetings/meetings_form.js +73 -0
  124. data/app/packs/src/decidim/meetings/meetings_polls.js +46 -0
  125. data/app/packs/src/decidim/meetings/poll.component.js +166 -0
  126. data/app/packs/stylesheets/decidim/meetings/_header.scss +52 -0
  127. data/app/packs/stylesheets/decidim/meetings/_main.scss +178 -0
  128. data/app/packs/stylesheets/decidim/meetings/_meetings.scss +2 -0
  129. data/app/permissions/decidim/meetings/admin/permissions.rb +16 -8
  130. data/app/permissions/decidim/meetings/permissions.rb +60 -17
  131. data/app/presenters/decidim/meetings/admin_log/meeting_presenter.rb +7 -3
  132. data/app/presenters/decidim/meetings/admin_log/{minutes_presenter.rb → questionnaire_presenter.rb} +13 -16
  133. data/app/presenters/decidim/meetings/meeting_edition_presenter.rb +14 -0
  134. data/app/presenters/decidim/meetings/meeting_presenter.rb +73 -24
  135. data/app/queries/decidim/meetings/admin/invites.rb +1 -1
  136. data/app/queries/decidim/meetings/filtered_meetings.rb +2 -2
  137. data/app/queries/decidim/meetings/metrics/meetings_metric_manage.rb +1 -1
  138. data/app/queries/decidim/meetings/questionnaire_user_answers.rb +29 -0
  139. data/app/serializers/decidim/meetings/{data_portability_invite_serializer.rb → download_your_data_invite_serializer.rb} +4 -3
  140. data/app/serializers/decidim/meetings/{data_portability_registration_serializer.rb → download_your_data_registration_serializer.rb} +4 -3
  141. data/app/serializers/decidim/meetings/registration_serializer.rb +3 -12
  142. data/app/services/decidim/meetings/calendar/base_calendar.rb +4 -3
  143. data/app/services/decidim/meetings/calendar/component_calendar.rb +7 -9
  144. data/app/services/decidim/meetings/calendar/meeting_calendar.rb +33 -0
  145. data/app/services/decidim/meetings/calendar/organization_calendar.rb +1 -1
  146. data/app/services/decidim/meetings/calendar_renderer.rb +5 -3
  147. data/app/services/decidim/meetings/close_meeting_reminder_generator.rb +68 -0
  148. data/app/services/decidim/meetings/diff_renderer.rb +4 -4
  149. data/app/services/decidim/meetings/meeting_iframe_embedder.rb +90 -0
  150. data/app/services/decidim/meetings/meeting_search.rb +7 -20
  151. data/app/views/decidim/meetings/_calendar_modal.html.erb +19 -2
  152. data/app/views/decidim/meetings/admin/agenda/_form.html.erb +1 -1
  153. data/app/views/decidim/meetings/admin/invite_join_meeting_mailer/invite.html.erb +4 -4
  154. data/app/views/decidim/meetings/admin/invites/_form.html.erb +1 -1
  155. data/app/views/decidim/meetings/admin/invites/index.html.erb +1 -1
  156. data/app/views/decidim/meetings/admin/meeting_closes/_form.html.erb +16 -1
  157. data/app/views/decidim/meetings/admin/meeting_copies/_form.html.erb +17 -2
  158. data/app/views/decidim/meetings/admin/meeting_copies/new.html.erb +1 -1
  159. data/app/views/decidim/meetings/admin/meetings/_form.html.erb +47 -2
  160. data/app/views/decidim/meetings/admin/meetings/_services.html.erb +1 -1
  161. data/app/views/decidim/meetings/admin/meetings/edit.html.erb +2 -2
  162. data/app/views/decidim/meetings/admin/meetings/index.html.erb +60 -10
  163. data/app/views/decidim/meetings/admin/meetings/new.html.erb +2 -2
  164. data/app/views/decidim/meetings/admin/poll/_answer_option.html.erb +34 -0
  165. data/app/views/decidim/meetings/admin/poll/_answer_option_template.html.erb +7 -0
  166. data/app/views/decidim/meetings/admin/poll/_form.html.erb +63 -0
  167. data/app/views/decidim/meetings/admin/poll/_question.html.erb +96 -0
  168. data/app/views/decidim/meetings/admin/poll/edit.html.erb +9 -0
  169. data/app/views/decidim/meetings/admin/registrations/_form.html.erb +10 -1
  170. data/app/views/decidim/meetings/admin/registrations/edit.html.erb +20 -18
  171. data/app/views/decidim/meetings/close_meeting_reminder_mailer/close_meeting_reminder.html.erb +5 -0
  172. data/app/views/decidim/meetings/directory/meetings/_filters.html.erb +34 -0
  173. data/app/views/decidim/meetings/directory/meetings/_meetings.html.erb +6 -1
  174. data/app/views/decidim/meetings/directory/meetings/index.html.erb +5 -21
  175. data/app/views/decidim/meetings/directory/meetings/index.js.erb +9 -4
  176. data/app/views/decidim/meetings/layouts/live_event.html.erb +55 -0
  177. data/app/views/decidim/meetings/live_events/show.html.erb +12 -0
  178. data/app/views/decidim/meetings/meeting_closes/_form.html.erb +14 -0
  179. data/app/views/decidim/meetings/meeting_closes/edit.html.erb +25 -0
  180. data/app/views/decidim/meetings/meeting_closes/proposals_picker.html.erb +1 -0
  181. data/app/views/decidim/meetings/meetings/_calendar_modal.html.erb +26 -0
  182. data/app/views/decidim/meetings/meetings/_count.html.erb +1 -1
  183. data/app/views/decidim/meetings/meetings/_filters.html.erb +13 -5
  184. data/app/views/decidim/meetings/meetings/_filters_small_view.html.erb +4 -4
  185. data/app/views/decidim/meetings/meetings/_form.html.erb +55 -3
  186. data/app/views/decidim/meetings/meetings/_linked_meetings.html.erb +2 -2
  187. data/app/views/decidim/meetings/meetings/_meeting_minutes.html.erb +7 -18
  188. data/app/views/decidim/meetings/meetings/_meetings.html.erb +24 -1
  189. data/app/views/decidim/meetings/meetings/edit.html.erb +2 -2
  190. data/app/views/decidim/meetings/meetings/index.html.erb +7 -6
  191. data/app/views/decidim/meetings/meetings/index.js.erb +7 -4
  192. data/app/views/decidim/meetings/meetings/new.html.erb +2 -2
  193. data/app/views/decidim/meetings/meetings/show.html.erb +50 -43
  194. data/app/views/decidim/meetings/polls/answers/_multiple_option.html.erb +13 -0
  195. data/app/views/decidim/meetings/polls/answers/_single_option.html.erb +19 -0
  196. data/app/views/decidim/meetings/polls/answers/create.js.erb +5 -0
  197. data/app/views/decidim/meetings/polls/questions/_closed_question.html.erb +7 -0
  198. data/app/views/decidim/meetings/polls/questions/_index.html.erb +5 -0
  199. data/app/views/decidim/meetings/polls/questions/_index_admin.html.erb +43 -0
  200. data/app/views/decidim/meetings/polls/questions/_published_question.html.erb +29 -0
  201. data/app/views/decidim/meetings/polls/questions/_question.html.erb +7 -0
  202. data/app/views/decidim/meetings/polls/questions/index.js.erb +5 -0
  203. data/app/views/decidim/meetings/polls/questions/index_admin.js.erb +5 -0
  204. data/app/views/decidim/meetings/registration_mailer/confirmation.html.erb +8 -3
  205. data/app/views/decidim/participatory_spaces/_upcoming_meeting_for_card.html.erb +1 -1
  206. data/app/views/devise/mailer/join_meeting.html.erb +6 -6
  207. data/config/assets.rb +11 -0
  208. data/config/locales/ar.yml +27 -40
  209. data/config/locales/bg.yml +1 -0
  210. data/config/locales/ca.yml +211 -44
  211. data/config/locales/cs.yml +220 -51
  212. data/config/locales/de.yml +249 -106
  213. data/config/locales/el.yml +6 -43
  214. data/config/locales/en.yml +208 -42
  215. data/config/locales/es-MX.yml +208 -41
  216. data/config/locales/es-PY.yml +209 -42
  217. data/config/locales/es.yml +210 -43
  218. data/config/locales/eu.yml +221 -39
  219. data/config/locales/fi-plain.yml +209 -42
  220. data/config/locales/fi.yml +337 -170
  221. data/config/locales/fr-CA.yml +208 -41
  222. data/config/locales/fr-LU.yml +534 -0
  223. data/config/locales/fr.yml +221 -54
  224. data/config/locales/ga-IE.yml +201 -0
  225. data/config/locales/gl.yml +92 -40
  226. data/config/locales/hu.yml +194 -41
  227. data/config/locales/id-ID.yml +6 -40
  228. data/config/locales/is-IS.yml +4 -30
  229. data/config/locales/it.yml +145 -42
  230. data/config/locales/ja.yml +246 -80
  231. data/config/locales/lb-LU.yml +211 -0
  232. data/config/locales/lb.yml +403 -0
  233. data/config/locales/lt.yml +688 -0
  234. data/config/locales/lv.yml +6 -43
  235. data/config/locales/nl.yml +264 -89
  236. data/config/locales/no.yml +167 -42
  237. data/config/locales/oc-FR.yml +1 -0
  238. data/config/locales/pl.yml +111 -61
  239. data/config/locales/pt-BR.yml +174 -40
  240. data/config/locales/pt.yml +143 -42
  241. data/config/locales/ro-RO.yml +257 -109
  242. data/config/locales/ru.yml +4 -39
  243. data/config/locales/si-LK.yml +1 -0
  244. data/config/locales/sk.yml +6 -43
  245. data/config/locales/sl.yml +1 -3
  246. data/config/locales/sr-CS.yml +1 -0
  247. data/config/locales/sv.yml +193 -42
  248. data/config/locales/sw-KE.yml +1 -0
  249. data/config/locales/tr-TR.yml +187 -120
  250. data/config/locales/uk.yml +4 -31
  251. data/config/locales/val-ES.yml +1 -0
  252. data/config/locales/zh-CN.yml +6 -43
  253. data/db/migrate/20180809134748_add_upcoming_events_as_content_block.rb +1 -1
  254. data/db/migrate/20201006140511_add_online_meeting_url.rb +7 -0
  255. data/db/migrate/20201009124057_add_type_of_meeting.rb +7 -0
  256. data/db/migrate/20201016112641_add_registration_type_and_url_to_meetings.rb +19 -0
  257. data/db/migrate/20201111133246_add_salt_to_decidim_meetings.rb +8 -0
  258. data/db/migrate/20210217124802_add_registration_custom_content_to_meetings.rb +8 -0
  259. data/db/migrate/20210310120731_add_followable_counter_cache_to_meetings.rb +16 -0
  260. data/db/migrate/20210413050756_add_published_at_to_meetings.rb +7 -0
  261. data/db/migrate/20210413050917_update_published_at_to_existing_meetings.rb +20 -0
  262. data/db/migrate/20210430123416_add_public_participation_to_decidim_meetings_registrations.rb +7 -0
  263. data/db/migrate/20210506180226_merge_meetings_minutes_into_meetings_table.rb +48 -0
  264. data/db/migrate/20210512055802_create_decidim_meetings_polls.rb +10 -0
  265. data/db/migrate/20210512100333_drop_decidim_meetings_minutes_table.rb +78 -0
  266. data/db/migrate/20210518133236_merge_minutes_with_closing_report_in_meetings_table.rb +57 -0
  267. data/db/migrate/20210519133705_add_comments_availability_columns_to_meetings_table.rb +14 -0
  268. data/db/migrate/20210520084247_create_decidim_meetings_questionnaires.rb +11 -0
  269. data/db/migrate/20210520084253_create_decidim_meetings_questions.rb +15 -0
  270. data/db/migrate/20210520084321_create_decidim_meetings_answers.rb +13 -0
  271. data/db/migrate/20210520084330_create_decidim_meetings_answer_options.rb +10 -0
  272. data/db/migrate/20210520084337_create_decidim_meetings_answer_choices.rb +13 -0
  273. data/db/migrate/20210520134834_add_status_to_meetings_questions.rb +7 -0
  274. data/db/migrate/20210602040614_add_setting_embed_iframe_to_meetings.rb +7 -0
  275. data/db/migrate/20210727085318_add_state_field_to_meeting.rb +7 -0
  276. data/db/migrate/20210903143040_add_iframe_access_level_to_decidim_meetings.rb +7 -0
  277. data/db/migrate/20210922140454_transform_show_embedded_iframe_column.rb +15 -0
  278. data/db/migrate/20210928095036_rename_upcoming_events_content_block_to_upcoming_meetings.rb +13 -0
  279. data/db/migrate/20211105115625_remove_not_null_on_customize_registration_email.rb +7 -0
  280. data/lib/decidim/api/agenda_item_type.rb +22 -0
  281. data/lib/decidim/api/agenda_type.rb +19 -0
  282. data/lib/decidim/api/linked_resources_interface.rb +14 -6
  283. data/lib/decidim/api/meeting_type.rb +79 -0
  284. data/lib/decidim/api/meetings_type.rb +26 -0
  285. data/{app/types/decidim/meetings → lib/decidim/api}/service_type.rb +4 -4
  286. data/lib/decidim/api/services_interface.rb +3 -3
  287. data/lib/decidim/content_parsers/meeting_parser.rb +20 -0
  288. data/lib/decidim/content_renderers/meeting_renderer.rb +17 -0
  289. data/lib/decidim/meetings/admin_engine.rb +5 -1
  290. data/lib/decidim/meetings/api.rb +5 -0
  291. data/lib/decidim/meetings/component.rb +108 -34
  292. data/lib/decidim/meetings/directory_engine.rb +3 -3
  293. data/lib/decidim/meetings/download_your_data_user_answers_serializer.rb +33 -0
  294. data/lib/decidim/meetings/engine.rb +39 -27
  295. data/lib/decidim/meetings/meeting_serializer.rb +5 -3
  296. data/lib/decidim/meetings/polls.rb +10 -0
  297. data/lib/decidim/meetings/test/factories.rb +131 -13
  298. data/lib/decidim/meetings/test/notifications_handling.rb +39 -0
  299. data/lib/decidim/meetings/test/translated_event.rb +22 -0
  300. data/lib/decidim/meetings/user_answers_serializer.rb +47 -0
  301. data/lib/decidim/meetings/version.rb +1 -1
  302. data/lib/decidim/meetings.rb +28 -1
  303. metadata +160 -137
  304. data/app/assets/config/decidim_meetings_manifest.js +0 -8
  305. data/app/assets/javascripts/decidim/meetings/admin/agendas.js.es6 +0 -158
  306. data/app/assets/javascripts/decidim/meetings/meetings_form.js.es6 +0 -9
  307. data/app/commands/decidim/meetings/admin/create_minutes.rb +0 -55
  308. data/app/commands/decidim/meetings/admin/update_minutes.rb +0 -63
  309. data/app/controllers/decidim/meetings/admin/minutes_controller.rb +0 -69
  310. data/app/forms/decidim/meetings/admin/minutes_form.rb +0 -20
  311. data/app/models/decidim/meetings/minutes.rb +0 -22
  312. data/app/types/decidim/meetings/agenda_item_type.rb +0 -28
  313. data/app/types/decidim/meetings/agenda_type.rb +0 -25
  314. data/app/types/decidim/meetings/meeting_type.rb +0 -65
  315. data/app/types/decidim/meetings/meetings_type.rb +0 -32
  316. data/app/types/decidim/meetings/minutes_type.rb +0 -26
  317. data/app/views/decidim/meetings/admin/minutes/_form.html.erb +0 -23
  318. data/app/views/decidim/meetings/admin/minutes/edit.html.erb +0 -7
  319. data/app/views/decidim/meetings/admin/minutes/new.html.erb +0 -7
  320. data/app/views/decidim/participatory_processes/participatory_process_groups/_highlighted_meetings.html.erb +0 -15
  321. data/app/views/decidim/participatory_processes/participatory_process_groups/_meeting.html.erb +0 -10
  322. data/config/locales/ja-JP.yml +0 -494
@@ -0,0 +1,37 @@
1
+ # frozen-string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ # This module is used to be included in events triggered by comments.
6
+ #
7
+ module MeetingEvent
8
+ extend ActiveSupport::Concern
9
+ include Decidim::Events::MachineTranslatedEvent
10
+
11
+ included do
12
+ def resource_text
13
+ translated_attribute(resource.description)
14
+ end
15
+
16
+ def translatable_resource
17
+ resource
18
+ end
19
+
20
+ def translatable_text
21
+ resource.description
22
+ end
23
+
24
+ def safe_resource_text
25
+ locale = resource.respond_to?(:content_original_language) ? resource.content_original_language : I18n.locale
26
+ I18n.with_locale(locale) { translated_attribute(resource.description).to_s.html_safe }
27
+ end
28
+
29
+ def safe_resource_translated_text
30
+ return safe_resource_text unless perform_translation?
31
+
32
+ I18n.with_locale(I18n.locale) { translated_attribute(resource.description, nil, true).to_s.html_safe }
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -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
@@ -3,9 +3,7 @@
3
3
  module Decidim
4
4
  module Meetings
5
5
  class MeetingRegistrationsEnabledEvent < Decidim::Events::SimpleEvent
6
- def resource_text
7
- translated_attribute(resource.description)
8
- end
6
+ include Decidim::Meetings::MeetingEvent
9
7
  end
10
8
  end
11
9
  end
@@ -3,11 +3,9 @@
3
3
  module Decidim
4
4
  module Meetings
5
5
  class MeetingRegistrationsOverPercentageEvent < Decidim::Events::SimpleEvent
6
- i18n_attributes :percentage
6
+ include Decidim::Meetings::MeetingEvent
7
7
 
8
- def resource_text
9
- translated_attribute(resource.description)
10
- end
8
+ i18n_attributes :percentage
11
9
 
12
10
  def percentage
13
11
  extra["percentage"] * 100
@@ -3,11 +3,9 @@
3
3
  module Decidim
4
4
  module Meetings
5
5
  class RegistrationCodeValidatedEvent < Decidim::Events::SimpleEvent
6
- i18n_attributes :registration_code
6
+ include Decidim::Meetings::MeetingEvent
7
7
 
8
- def resource_text
9
- translated_attribute(resource.description)
10
- end
8
+ i18n_attributes :registration_code
11
9
 
12
10
  private
13
11
 
@@ -3,9 +3,7 @@
3
3
  module Decidim
4
4
  module Meetings
5
5
  class UpcomingMeetingEvent < Decidim::Events::SimpleEvent
6
- def resource_text
7
- translated_attribute(resource.description)
8
- end
6
+ include Decidim::Meetings::MeetingEvent
9
7
  end
10
8
  end
11
9
  end
@@ -3,9 +3,7 @@
3
3
  module Decidim
4
4
  module Meetings
5
5
  class UpdateMeetingEvent < Decidim::Events::SimpleEvent
6
- def resource_text
7
- translated_attribute(resource.description)
8
- end
6
+ include Decidim::Meetings::MeetingEvent
9
7
  end
10
8
  end
11
9
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ module Admin
6
+ # This class holds a Form to update answer options
7
+ class AnswerOptionForm < Decidim::Form
8
+ include TranslatableAttributes
9
+
10
+ attribute :deleted, Boolean, default: false
11
+
12
+ translatable_attribute :body, String
13
+
14
+ validates :body, translatable_presence: true, unless: :deleted
15
+
16
+ def to_param
17
+ return id if id.present?
18
+
19
+ "questionnaire-question-answer-option-id"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -8,17 +8,19 @@ module Decidim
8
8
  include TranslatableAttributes
9
9
 
10
10
  translatable_attribute :closing_report, String
11
+ attribute :video_url, String
12
+ attribute :audio_url, String
13
+ attribute :closing_visible, Boolean, default: true
11
14
  attribute :attendees_count, Integer, default: 0
12
15
  attribute :contributions_count, Integer, default: 0
13
16
  attribute :attending_organizations, String
14
17
  attribute :proposal_ids, Array[Integer]
15
18
  attribute :proposals
16
- attribute :closed_at, Decidim::Attributes::TimeWithZone, default: ->(_form, _attribute) { Time.current }
19
+ attribute :closed_at, Decidim::Attributes::TimeWithZone, default: -> { Time.current }
17
20
 
18
21
  validates :closing_report, translatable_presence: true
19
- validates :attendees_count, presence: true, numericality: { greater_than_or_equal_to: 0 }
22
+ validates :attendees_count, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 999, only_integer: true }
20
23
  validates :contributions_count, numericality: true, allow_blank: true
21
- validates :attending_organizations, presence: true
22
24
 
23
25
  # Private: Gets the proposals from the meeting and injects them to the form.
24
26
  #
@@ -28,10 +30,10 @@ module Decidim
28
30
  end
29
31
 
30
32
  def proposals
31
- @proposals ||= Decidim.find_resource_manifest(:proposals)
32
- .try(:resource_scope, current_component)
33
- &.where(id: proposal_ids)
34
- &.order(title: :asc)
33
+ @proposals = Decidim.find_resource_manifest(:proposals)
34
+ .try(:resource_scope, current_component)
35
+ &.where(id: proposal_ids)
36
+ &.order(title: :asc)
35
37
  end
36
38
  end
37
39
  end
@@ -6,7 +6,7 @@ module Decidim
6
6
  # A form object used to copy a meeting from the admin
7
7
  # dashboard.
8
8
  #
9
- class MeetingCopyForm < Form
9
+ class MeetingCopyForm < ::Decidim::Meetings::BaseMeetingForm
10
10
  include TranslatableAttributes
11
11
 
12
12
  translatable_attribute :title, String
@@ -14,26 +14,17 @@ module Decidim
14
14
  translatable_attribute :location, String
15
15
  translatable_attribute :location_hints, String
16
16
 
17
- attribute :address, String
18
- attribute :latitude, Float
19
- attribute :longitude, Float
20
- attribute :start_time, Decidim::Attributes::TimeWithZone
21
- attribute :end_time, Decidim::Attributes::TimeWithZone
17
+ attribute :show_embedded_iframe, Boolean, default: false
22
18
  attribute :private_meeting, Boolean
23
19
  attribute :transparent, Boolean
24
20
  attribute :services, Array[MeetingServiceForm]
25
21
 
26
22
  mimic :meeting
27
23
 
28
- validates :current_component, presence: true
29
-
24
+ validates :online_meeting_url, url: true, if: ->(form) { form.online_meeting? || form.hybrid_meeting? }
30
25
  validates :title, translatable_presence: true
31
26
  validates :description, translatable_presence: true
32
- validates :location, translatable_presence: true
33
- validates :address, presence: true
34
- validates :address, geocoding: true, if: -> { Decidim::Map.available?(:geocoding) }
35
- validates :start_time, presence: true, date: { before: :end_time }
36
- validates :end_time, presence: true, date: { after: :start_time }
27
+ validates :location, translatable_presence: true, if: ->(form) { form.in_person_meeting? || form.hybrid_meeting? }
37
28
 
38
29
  def map_model(model)
39
30
  self.services = model.services.map do |service|
@@ -4,38 +4,48 @@ module Decidim
4
4
  module Meetings
5
5
  module Admin
6
6
  # This class holds a Form to create/update translatable meetings from Decidim's admin panel.
7
- class MeetingForm < Decidim::Form
7
+ class MeetingForm < ::Decidim::Meetings::BaseMeetingForm
8
8
  include TranslatableAttributes
9
9
 
10
- attribute :address, String
11
- attribute :latitude, Float
12
- attribute :longitude, Float
13
- attribute :start_time, Decidim::Attributes::TimeWithZone
14
- attribute :end_time, Decidim::Attributes::TimeWithZone
15
10
  attribute :services, Array[MeetingServiceForm]
16
11
  attribute :decidim_scope_id, Integer
17
12
  attribute :decidim_category_id, Integer
18
13
  attribute :private_meeting, Boolean
19
14
  attribute :transparent, Boolean
15
+ attribute :registration_type, String
16
+ attribute :registration_url, String
17
+ attribute :customize_registration_email, Boolean
18
+ attribute :iframe_embed_type, String, default: "none"
19
+ attribute :comments_enabled, Boolean, default: true
20
+ attribute :comments_start_time, Decidim::Attributes::TimeWithZone
21
+ attribute :comments_end_time, Decidim::Attributes::TimeWithZone
22
+ attribute :iframe_access_level, String
20
23
 
21
24
  translatable_attribute :title, String
22
25
  translatable_attribute :description, String
23
26
  translatable_attribute :location, String
24
27
  translatable_attribute :location_hints, String
25
28
 
29
+ validates :iframe_embed_type, inclusion: { in: Decidim::Meetings::Meeting.iframe_embed_types }
26
30
  validates :title, translatable_presence: true
27
31
  validates :description, translatable_presence: true
28
- validates :location, translatable_presence: true
29
-
30
- validates :address, presence: true
31
- validates :address, geocoding: true, if: ->(form) { form.has_address? && !form.geocoded? }
32
- validates :start_time, presence: true, date: { before: :end_time }
33
- validates :end_time, presence: true, date: { after: :start_time }
34
-
35
- validates :current_component, presence: true
32
+ validates :registration_type, presence: true
33
+ validates :registration_url, presence: true, url: true, if: ->(form) { form.on_different_platform? }
34
+ validates :type_of_meeting, presence: true
35
+ validates :location, translatable_presence: true, if: ->(form) { form.in_person_meeting? || form.hybrid_meeting? }
36
+ validates :online_meeting_url, url: true, if: ->(form) { form.online_meeting? || form.hybrid_meeting? }
37
+ validates :comments_start_time, date: { before: :comments_end_time, allow_blank: true, if: proc { |obj| obj.comments_end_time.present? } }
38
+ validates :comments_end_time, date: { after: :comments_start_time, allow_blank: true, if: proc { |obj| obj.comments_start_time.present? } }
36
39
  validates :category, presence: true, if: ->(form) { form.decidim_category_id.present? }
37
40
  validates :scope, presence: true, if: ->(form) { form.decidim_scope_id.present? }
38
41
  validates :decidim_scope_id, scope_belongs_to_component: true, if: ->(form) { form.decidim_scope_id.present? }
42
+ validates :clean_type_of_meeting, presence: true
43
+ validates(
44
+ :iframe_access_level,
45
+ inclusion: { in: Decidim::Meetings::Meeting.iframe_access_levels },
46
+ if: ->(form) { %w(embed_in_meeting_page open_in_live_event_page open_in_new_tab).include?(form.iframe_embed_type) }
47
+ )
48
+ validate :embeddable_meeting_url
39
49
 
40
50
  delegate :categories, to: :current_component
41
51
 
@@ -45,10 +55,7 @@ module Decidim
45
55
  end
46
56
 
47
57
  self.decidim_category_id = model.categorization.decidim_category_id if model.categorization
48
- presenter = MeetingPresenter.new(model)
49
-
50
- self.title = presenter.title(all_locales: title.is_a?(Hash))
51
- self.description = presenter.description(all_locales: description.is_a?(Hash))
58
+ self.type_of_meeting = model.type_of_meeting
52
59
  end
53
60
 
54
61
  def services_to_persist
@@ -65,14 +72,14 @@ module Decidim
65
72
  #
66
73
  # Returns a Decidim::Scope
67
74
  def scope
68
- @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
69
76
  end
70
77
 
71
78
  # Scope identifier
72
79
  #
73
80
  # Returns the scope identifier related to the meeting
74
81
  def decidim_scope_id
75
- @decidim_scope_id || scope&.id
82
+ super || scope&.id
76
83
  end
77
84
 
78
85
  def category
@@ -81,16 +88,59 @@ module Decidim
81
88
  @category ||= categories.find_by(id: decidim_category_id)
82
89
  end
83
90
 
84
- def geocoding_enabled?
85
- Decidim::Map.available?(:geocoding)
91
+ def clean_type_of_meeting
92
+ type_of_meeting.presence
93
+ end
94
+
95
+ def type_of_meeting_select
96
+ Decidim::Meetings::Meeting::TYPE_OF_MEETING.map do |type|
97
+ [
98
+ I18n.t("type_of_meeting.#{type}", scope: "decidim.meetings"),
99
+ type
100
+ ]
101
+ end
102
+ end
103
+
104
+ def iframe_access_level_select
105
+ Decidim::Meetings::Meeting.iframe_access_levels.map do |level, _value|
106
+ [
107
+ I18n.t("iframe_access_level.#{level}", scope: "decidim.meetings"),
108
+ level
109
+ ]
110
+ end
111
+ end
112
+
113
+ def iframe_embed_type_select
114
+ Decidim::Meetings::Meeting.iframe_embed_types.map do |type, _value|
115
+ [
116
+ I18n.t("iframe_embed_type.#{type}", scope: "decidim.meetings"),
117
+ type
118
+ ]
119
+ end
120
+ end
121
+
122
+ def on_this_platform?
123
+ registration_type == "on_this_platform"
86
124
  end
87
125
 
88
- def has_address?
89
- geocoding_enabled? && address.present?
126
+ def on_different_platform?
127
+ registration_type == "on_different_platform"
90
128
  end
91
129
 
92
- def geocoded?
93
- latitude.present? && longitude.present?
130
+ def registration_type_select
131
+ Decidim::Meetings::Meeting::REGISTRATION_TYPE.map do |type|
132
+ [
133
+ I18n.t("registration_type.#{type}", scope: "decidim.meetings"),
134
+ type
135
+ ]
136
+ end
137
+ end
138
+
139
+ def embeddable_meeting_url
140
+ if online_meeting_url.present? && %w(embed_in_meeting_page open_in_live_event_page).include?(iframe_embed_type)
141
+ embedder_service = Decidim::Meetings::MeetingIframeEmbedder.new(online_meeting_url)
142
+ errors.add(:iframe_embed_type, :not_embeddable) unless embedder_service.embeddable?
143
+ end
94
144
  end
95
145
  end
96
146
  end
@@ -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,17 +11,30 @@ 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
- validates :available_slots, numericality: { greater_than_or_equal_to: 0 }, if: ->(form) { form.registrations_enabled? }
22
+ validates :available_slots, :reserved_slots, presence: true, if: ->(form) { form.registrations_enabled? }
23
+ validates :available_slots, numericality: { greater_than_or_equal_to: 0 }, if: ->(form) { form.registrations_enabled? && form.available_slots.present? }
20
24
  validates :reserved_slots, numericality: { greater_than_or_equal_to: 0 }, if: ->(form) { form.registrations_enabled? }
21
- validates :reserved_slots, numericality: { less_than_or_equal_to: :available_slots }, if: ->(form) { form.registrations_enabled? }
25
+ validates :reserved_slots, numericality: { less_than_or_equal_to: :available_slots }, if: lambda { |form|
26
+ form.registrations_enabled? &&
27
+ form.reserved_slots.present? &&
28
+ form.available_slots.present?
29
+ }
30
+
31
+ validate :available_slots_greater_than_or_equal_to_registrations_count, if: ->(form) { form.registrations_enabled? && form.available_slots.try(:positive?) }
32
+ validate :reserved_slots_lower_than_or_equal_to_rest_available_slots_and_registrations_count, if: lambda { |form|
33
+ form.registrations_enabled? &&
34
+ form.reserved_slots.try(:positive?) &&
35
+ form.available_slots.present?
36
+ }
22
37
 
23
- validate :available_slots_greater_than_or_equal_to_registrations_count, if: ->(form) { form.registrations_enabled? && form.available_slots.positive? }
24
- validate :reserved_slots_lower_than_or_equal_to_rest_available_slots_and_registrations_count, if: ->(form) { form.registrations_enabled? && form.reserved_slots.positive? }
25
38
  # We need this method to ensure the form object will always have an ID,
26
39
  # and thus its `to_param` method will always return a significant value.
27
40
  # If we remove this method, get an error onn the `update` action and try
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ module Admin
6
+ # This class holds a Form to update questionnaire questions from Decidim's admin panel.
7
+ class QuestionForm < Decidim::Form
8
+ include TranslatableAttributes
9
+
10
+ attribute :position, Integer
11
+ attribute :mandatory, Boolean, default: false
12
+ attribute :question_type, String
13
+ attribute :answer_options, Array[AnswerOptionForm]
14
+ attribute :max_choices, Integer
15
+ attribute :deleted, Boolean, default: false
16
+
17
+ translatable_attribute :body, String
18
+ translatable_attribute :description, String
19
+
20
+ validates :position, numericality: { greater_than_or_equal_to: 0 }
21
+ validates :question_type, inclusion: { in: Decidim::Meetings::Question::QUESTION_TYPES }
22
+ validates :max_choices, numericality: { only_integer: true, greater_than: 1, less_than_or_equal_to: ->(form) { form.number_of_options } }, allow_blank: true
23
+ validates :body, translatable_presence: true, if: :requires_body?
24
+ validates :answer_options, presence: true
25
+
26
+ def to_param
27
+ return id if id.present?
28
+
29
+ "questionnaire-question-id"
30
+ end
31
+
32
+ def number_of_options
33
+ answer_options.size
34
+ end
35
+
36
+ private
37
+
38
+ def requires_body?
39
+ !deleted
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ module Admin
6
+ # This class holds a Form to update questionnaires from Decidim's admin panel.
7
+ class QuestionnaireForm < Decidim::Form
8
+ attribute :published_at, Decidim::Attributes::TimeWithZone
9
+ attribute :questions, Array[Decidim::Meetings::Admin::QuestionForm]
10
+
11
+ def map_model(model)
12
+ self.questions = model.questions.map do |question|
13
+ Decidim::Meetings::Admin::QuestionForm.from_model(question)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ # This class holds a Form to save the chosen option for an answer
6
+ class AnswerChoiceForm < Decidim::Form
7
+ attribute :body, String
8
+ attribute :position, Integer
9
+ attribute :answer_option_id, Integer
10
+
11
+ validates :answer_option_id, presence: true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ # This class holds a Form to save the questionnaire answers from Decidim's public page
6
+ class AnswerForm < Decidim::Form
7
+ include Decidim::TranslationsHelper
8
+
9
+ attribute :question_id, String
10
+ attribute :body, String
11
+ attribute :choices, Array[AnswerChoiceForm]
12
+ attribute :current_user, Decidim::User
13
+
14
+ validates :selected_choices, presence: true
15
+ validate :max_choices, if: -> { question.max_choices }
16
+
17
+ attr_writer :question
18
+
19
+ def question
20
+ @question ||= Decidim::Meetings::Question.find(question_id)
21
+ end
22
+
23
+ def answer
24
+ @answer ||= Decidim::Meetings::Answer.find_by(decidim_user_id: current_user.id, decidim_question_id: question_id) if current_user
25
+ end
26
+
27
+ def label(idx)
28
+ base = "#{idx + 1}. #{translated_attribute(question.body)}"
29
+ base += " (#{max_choices_label})" if question.max_choices
30
+ base
31
+ end
32
+
33
+ # Public: Map the correct fields.
34
+ #
35
+ # Returns nothing.
36
+ def map_model(model)
37
+ self.question_id = model.decidim_question_id
38
+ self.question = model.question
39
+
40
+ self.choices = model.choices.map do |choice|
41
+ AnswerChoiceForm.from_model(choice)
42
+ end
43
+ end
44
+
45
+ def selected_choices
46
+ choices.select(&:body)
47
+ end
48
+
49
+ private
50
+
51
+ def max_choices
52
+ errors.add(:choices, :too_many) if selected_choices.size > question.max_choices
53
+ end
54
+
55
+ def mandatory_label
56
+ "*"
57
+ end
58
+
59
+ def max_choices_label
60
+ I18n.t("questionnaires.question.max_choices", scope: "decidim.forms", n: question.max_choices)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ class BaseMeetingForm < Decidim::Form
6
+ attribute :address, String
7
+ attribute :latitude, Float
8
+ attribute :longitude, Float
9
+ attribute :online_meeting_url, String
10
+ attribute :type_of_meeting, String
11
+ attribute :start_time, Decidim::Attributes::TimeWithZone
12
+ attribute :end_time, Decidim::Attributes::TimeWithZone
13
+
14
+ validates :current_component, presence: true
15
+
16
+ validates :address, presence: true, if: ->(form) { form.needs_address? }
17
+ validates :address, geocoding: true, if: ->(form) { form.has_address? && !form.geocoded? && form.needs_address? }
18
+ validates :start_time, presence: true, date: { before: :end_time }
19
+ validates :end_time, presence: true, date: { after: :start_time }
20
+
21
+ def type_of_meeting_select
22
+ Decidim::Meetings::Meeting::TYPE_OF_MEETING.map do |type|
23
+ [
24
+ I18n.t("type_of_meeting.#{type}", scope: "decidim.meetings"),
25
+ type
26
+ ]
27
+ end
28
+ end
29
+
30
+ def geocoding_enabled?
31
+ Decidim::Map.available?(:geocoding)
32
+ end
33
+
34
+ def geocoded?
35
+ latitude.present? && longitude.present?
36
+ end
37
+
38
+ def has_address?
39
+ geocoding_enabled? && address.present?
40
+ end
41
+
42
+ def needs_address?
43
+ in_person_meeting? || hybrid_meeting?
44
+ end
45
+
46
+ def online_meeting?
47
+ type_of_meeting == "online"
48
+ end
49
+
50
+ def in_person_meeting?
51
+ type_of_meeting == "in_person"
52
+ end
53
+
54
+ def hybrid_meeting?
55
+ type_of_meeting == "hybrid"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Meetings
5
+ # This class holds a Form to close a meeting from Decidim's public views.
6
+ class CloseMeetingForm < Decidim::Form
7
+ attribute :closing_report, String
8
+ attribute :proposal_ids, Array[Integer]
9
+ attribute :proposals
10
+ attribute :closed_at, Decidim::Attributes::TimeWithZone, default: -> { Time.current }
11
+ attribute :attendees_count, Integer, default: 0
12
+
13
+ validates :closing_report, presence: true
14
+ validates :attendees_count,
15
+ presence: true,
16
+ numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 999, only_integer: true }
17
+
18
+ # Private: Gets the proposals from the meeting and injects them to the form.
19
+ #
20
+ # Returns nothing.
21
+ def map_model(model)
22
+ self.proposal_ids = model.linked_resources(:proposals, "proposals_from_meeting").pluck(:id)
23
+ presenter = MeetingEditionPresenter.new(model)
24
+ self.closing_report = presenter.closing_report(all_locales: false)
25
+ end
26
+
27
+ def proposals
28
+ @proposals = Decidim.find_resource_manifest(:proposals)
29
+ .try(:resource_scope, current_component)
30
+ &.where(id: proposal_ids)
31
+ &.order(title: :asc)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -4,6 +4,7 @@ module Decidim
4
4
  module Meetings
5
5
  class JoinMeetingForm < Decidim::Form
6
6
  attribute :user_group_id, Integer
7
+ attribute :public_participation, Boolean, default: false
7
8
  end
8
9
  end
9
10
  end