decidim-core 0.31.2 → 0.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +3 -13
- data/app/cells/decidim/amendable/amend_button_card/show.erb +2 -2
- data/app/cells/decidim/amendable/amend_button_card_cell.rb +1 -1
- data/app/cells/decidim/author_cell.rb +0 -4
- data/app/cells/decidim/card_metadata_cell.rb +1 -1
- data/app/cells/decidim/comments_button_cell.rb +9 -1
- data/app/cells/decidim/content_blocks/announcement_settings_form/show.erb +5 -0
- data/app/cells/decidim/content_blocks/announcement_settings_form_cell.rb +17 -0
- data/app/cells/decidim/content_blocks/cta_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/hero_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_content_banner_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_content_banner_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_elements_with_cell_for_list_cell.rb +5 -1
- data/app/cells/decidim/content_blocks/highlighted_participatory_spaces_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/how_to_participate/show.erb +1 -1
- data/app/cells/decidim/content_blocks/html_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/participatory_space_announcement_cell.rb +1 -3
- data/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb +1 -5
- data/app/cells/decidim/content_blocks/participatory_space_hero_settings_form/show.erb +1 -1
- data/app/cells/decidim/content_blocks/static_page/section_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/static_page/section_settings_form/show.erb +3 -1
- data/app/cells/decidim/content_blocks/static_page/summary_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/static_page/summary_settings_form/show.erb +3 -1
- data/app/cells/decidim/content_blocks/static_page/two_pane_section_cell.rb +2 -2
- data/app/cells/decidim/content_blocks/static_page/two_pane_section_settings_form/show.erb +4 -2
- data/app/cells/decidim/data_consent/category.erb +25 -38
- data/app/cells/decidim/footer_topics/show.erb +5 -8
- data/app/cells/decidim/{participatory_space_private_user → member}/show.erb +6 -6
- data/app/cells/decidim/{participatory_space_private_user_cell.rb → member_cell.rb} +1 -5
- data/app/cells/decidim/nav_links/show.erb +3 -3
- data/app/cells/decidim/onboarding_action_message_cell.rb +1 -0
- data/app/cells/decidim/profile/details.erb +1 -1
- data/app/cells/decidim/profile_cell.rb +1 -0
- data/app/cells/decidim/profile_member_of/show.erb +13 -0
- data/app/cells/decidim/profile_member_of_cell.rb +35 -0
- data/app/cells/decidim/report_button/already_reported_modal.erb +1 -1
- data/app/cells/decidim/report_button/flag_modal.erb +1 -1
- data/app/cells/decidim/report_user_button/already_reported_modal.erb +1 -1
- data/app/cells/decidim/report_user_button/flag_modal.erb +1 -1
- data/app/cells/decidim/resource_types_filter/show.erb +2 -2
- data/app/cells/decidim/share_text_widget/modal.erb +1 -1
- data/app/cells/decidim/share_widget/qr_code_modal.erb +1 -1
- data/app/cells/decidim/tags_cell.rb +1 -1
- data/app/cells/decidim/upload_modal/files.erb +5 -1
- data/app/cells/decidim/upload_modal_cell.rb +15 -1
- data/app/cells/decidim/versions_list/show.erb +25 -0
- data/app/commands/decidim/create_follow.rb +3 -5
- data/app/commands/decidim/create_user_report.rb +1 -1
- data/app/commands/decidim/destroy_account.rb +15 -4
- data/app/commands/decidim/multiple_attachments_methods.rb +42 -24
- data/app/commands/decidim/search.rb +5 -5
- data/app/controllers/concerns/decidim/ajax_permission_handler.rb +1 -1
- data/app/controllers/concerns/decidim/devise_controllers.rb +9 -0
- data/app/controllers/concerns/decidim/direct_upload.rb +3 -2
- data/app/controllers/concerns/decidim/ephemeral_session_checker.rb +1 -1
- data/app/controllers/concerns/decidim/force_authentication.rb +10 -1
- data/app/controllers/concerns/decidim/impersonate_users.rb +4 -0
- data/app/controllers/concerns/decidim/locale_switcher.rb +52 -2
- data/app/controllers/concerns/decidim/needs_tos_accepted.rb +1 -1
- data/app/controllers/concerns/decidim/participatory_space/has_members_page.rb +27 -0
- data/app/controllers/concerns/decidim/participatory_space_context.rb +1 -5
- data/app/controllers/decidim/account_controller.rb +1 -1
- data/app/controllers/decidim/amendments_controller.rb +5 -4
- data/app/controllers/decidim/components/base_controller.rb +20 -3
- data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +1 -1
- data/app/controllers/decidim/devise/passwords_controller.rb +1 -1
- data/app/controllers/decidim/devise/registrations_controller.rb +1 -1
- data/app/controllers/decidim/devise/sessions_controller.rb +1 -1
- data/app/controllers/decidim/download_your_data_controller.rb +2 -2
- data/app/controllers/decidim/editor_images_controller.rb +1 -1
- data/app/controllers/decidim/follows_controller.rb +4 -3
- data/app/controllers/decidim/geolocation_controller.rb +1 -1
- data/app/controllers/decidim/likes_controller.rb +2 -1
- data/app/controllers/decidim/locales_controller.rb +3 -11
- data/app/controllers/decidim/messaging/conversations_controller.rb +3 -3
- data/app/controllers/decidim/newsletters_controller.rb +1 -1
- data/app/controllers/decidim/notifications_settings_controller.rb +1 -1
- data/app/controllers/decidim/notifications_subscriptions_controller.rb +8 -0
- data/app/controllers/decidim/open_data_controller.rb +1 -1
- data/app/controllers/decidim/private_downloads_controller.rb +29 -0
- data/app/controllers/decidim/report_users_controller.rb +2 -2
- data/app/controllers/decidim/reports_controller.rb +1 -1
- data/app/controllers/decidim/user_activities_controller.rb +1 -2
- data/app/events/decidim/amendable/amendment_base_event.rb +7 -1
- data/app/events/decidim/welcome_notification_event.rb +1 -1
- data/app/forms/decidim/upload_validation_form.rb +1 -1
- data/app/helpers/concerns/decidim/flash_helper_extensions.rb +1 -0
- data/app/helpers/decidim/active_link_to_helper.rb +136 -0
- data/app/helpers/decidim/amendments_helper.rb +3 -3
- data/app/helpers/decidim/check_boxes_tree_helper.rb +2 -2
- data/app/helpers/decidim/component_path_helper.rb +9 -4
- data/app/helpers/decidim/filters_helper.rb +0 -2
- data/app/helpers/decidim/mailer_helper.rb +36 -0
- data/app/helpers/decidim/menu_helper.rb +4 -5
- data/app/helpers/decidim/meta_tags_helper.rb +0 -2
- data/app/helpers/decidim/newsletters_helper.rb +4 -22
- data/app/helpers/decidim/paginate_helper.rb +14 -1
- data/app/helpers/decidim/sanitize_helper.rb +1 -0
- data/app/helpers/decidim/short_link_helper.rb +5 -5
- data/app/helpers/decidim/translations_helper.rb +4 -4
- data/app/jobs/decidim/delete_inactive_participants_job.rb +2 -2
- data/app/jobs/decidim/find_and_update_descendants_job.rb +8 -2
- data/app/jobs/decidim/process_inactive_participant_job.rb +0 -7
- data/app/jobs/decidim/update_search_indexes_job.rb +2 -2
- data/app/mailers/decidim/application_mailer.rb +11 -2
- data/app/mailers/decidim/decidim_devise_mailer.rb +1 -0
- data/app/mailers/decidim/delete_user_mailer.rb +14 -0
- data/app/mailers/decidim/participants_account_mailer.rb +0 -16
- data/app/mailers/decidim/reported_mailer.rb +4 -1
- data/app/models/decidim/action_log.rb +1 -1
- data/app/models/decidim/attachment.rb +20 -2
- data/app/models/decidim/authorization.rb +7 -0
- data/app/models/decidim/authorization_transfer.rb +1 -1
- data/app/models/decidim/component.rb +6 -9
- data/app/models/decidim/content_block.rb +3 -3
- data/app/models/decidim/moderation.rb +1 -1
- data/app/models/decidim/newsletter.rb +2 -2
- data/app/models/decidim/participatory_space/member.rb +55 -0
- data/app/models/decidim/private_download.rb +61 -0
- data/app/models/decidim/private_export.rb +6 -0
- data/app/models/decidim/resource_link.rb +1 -1
- data/app/models/decidim/short_link.rb +1 -1
- data/app/models/decidim/user.rb +2 -2
- data/app/models/decidim/user_base_entity.rb +17 -2
- data/app/models/decidim/user_moderation.rb +1 -1
- data/app/packs/src/decidim/a11y.js +29 -0
- data/app/packs/src/decidim/a11y.test.js +81 -0
- data/app/packs/src/decidim/confirm.js +8 -1
- data/app/packs/src/decidim/confirm.test.js +225 -0
- data/app/packs/src/decidim/controllers/accordion/accordion.test.js +272 -0
- data/app/packs/src/decidim/controllers/accordion/controller.js +117 -17
- data/app/packs/src/decidim/controllers/assign_role/assign_role.test.js +80 -0
- data/app/packs/src/decidim/controllers/assign_role/controller.js +27 -0
- data/app/packs/src/decidim/controllers/breadcrumb_truncate/breadcrumb_truncate.test.js +230 -0
- data/app/packs/src/decidim/controllers/breadcrumb_truncate/controller.js +172 -0
- data/app/packs/src/decidim/controllers/dropdown/controller.js +32 -0
- data/app/packs/src/decidim/controllers/dropdown/dropdown.test.js +215 -0
- data/app/packs/src/decidim/controllers/form_validator/form_validator.js +9 -8
- data/app/packs/src/decidim/controllers/form_validator/form_validator.test.js +28 -1
- data/app/packs/src/decidim/controllers/language_change/controller.js +1 -0
- data/app/packs/src/decidim/controllers/language_change/language_change.test.js +13 -0
- data/app/packs/src/decidim/controllers/main_menu/controller.js +152 -0
- data/app/packs/src/decidim/controllers/main_menu/main_menu.test.js +285 -0
- data/app/packs/src/decidim/controllers/mention/controller.js +296 -140
- data/app/packs/src/decidim/controllers/mention/input_mentions.test.js +120 -457
- data/app/packs/src/decidim/controllers/multiple_mentions/controller.js +68 -32
- data/app/packs/src/decidim/controllers/multiple_mentions/input_multiple_mentions.test.js +30 -23
- data/app/packs/src/decidim/controllers/password_toggler/controller.js +22 -1
- data/app/packs/src/decidim/controllers/password_toggler/password_toggler.test.js +11 -20
- data/app/packs/src/decidim/datepicker/datepicker_functions.js +26 -0
- data/app/packs/src/decidim/datepicker/generate_datepicker.js +3 -14
- data/app/packs/src/decidim/datepicker/generate_timepicker.js +3 -2
- data/app/packs/src/decidim/datepicker/test/datepicker_functions_adjust_picker_position.test.js +234 -0
- data/app/packs/src/decidim/direct_uploads/upload_field.js +4 -4
- data/app/packs/src/decidim/direct_uploads/upload_modal.js +12 -7
- data/app/packs/src/decidim/editor/common/suggestion.js +4 -2
- data/app/packs/src/decidim/editor/extensions/decidim_kit/index.js +4 -1
- data/app/packs/src/decidim/editor/extensions/image/index.js +57 -16
- data/app/packs/src/decidim/editor/extensions/image/node_view.js +9 -1
- data/app/packs/src/decidim/editor/extensions/indent/index.js +9 -0
- data/app/packs/src/decidim/editor/extensions/link/bubble_menu.js +34 -6
- data/app/packs/src/decidim/editor/extensions/link/index.js +53 -12
- data/app/packs/src/decidim/editor/extensions/mention/index.js +18 -5
- data/app/packs/src/decidim/editor/extensions/mention_resource/index.js +16 -7
- data/app/packs/src/decidim/editor/test/extensions/decidim_kit.test.js +13 -4
- data/app/packs/src/decidim/editor/test/extensions/heading.test.js +1 -1
- data/app/packs/src/decidim/editor/test/extensions/image.test.js +26 -28
- data/app/packs/src/decidim/editor/test/extensions/image_links.test.js +161 -0
- data/app/packs/src/decidim/editor/test/extensions/mention.test.js +6 -2
- data/app/packs/src/decidim/editor/test/extensions/video_embed.test.js +27 -15
- data/app/packs/src/decidim/editor/test/helpers.js +8 -10
- data/app/packs/src/decidim/editor/test/toolbar/full.test.js +15 -4
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_block.js +8 -4
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_formatting.js +5 -1
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_indent.js +9 -5
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_link.js +5 -1
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_list.js +8 -4
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_styling.js +13 -9
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_content_styling.js +6 -2
- data/app/packs/src/decidim/geocoding/reverse_geocoding.js +15 -5
- data/app/packs/src/decidim/geocoding/reverse_geocoding.test.js +197 -0
- data/app/packs/src/decidim/index.js +4 -4
- data/app/packs/src/decidim/map/controller.js +10 -1
- data/app/packs/src/decidim/refactor/moved/focus_guard.js +16 -16
- data/app/packs/src/decidim/refactor/moved/focus_guard.test.js +136 -0
- data/app/packs/src/decidim/sw/push-permissions.js +48 -13
- data/app/packs/src/decidim/sw/sw.js +1 -1
- data/app/packs/src/decidim/utilities/text.js +6 -6
- data/app/packs/stylesheets/decidim/_cards.scss +15 -6
- data/app/packs/stylesheets/decidim/_conversations.scss +14 -0
- data/app/packs/stylesheets/decidim/_cookies.scss +13 -5
- data/app/packs/stylesheets/decidim/_datepicker.scss +0 -8
- data/app/packs/stylesheets/decidim/_documents.scss +1 -1
- data/app/packs/stylesheets/decidim/_dropdown.scss +22 -32
- data/app/packs/stylesheets/decidim/_editor_suggestions.scss +49 -0
- data/app/packs/stylesheets/decidim/_flash.scss +1 -1
- data/app/packs/stylesheets/decidim/_floating_help.scss +1 -1
- data/app/packs/stylesheets/decidim/_footer.scss +27 -31
- data/app/packs/stylesheets/decidim/_forms.scss +5 -1
- data/app/packs/stylesheets/decidim/_header.scss +183 -48
- data/app/packs/stylesheets/decidim/_language_chooser.scss +79 -0
- data/app/packs/stylesheets/decidim/_participatory_spaces.scss +1 -1
- data/app/packs/stylesheets/decidim/_rich_text.scss +17 -0
- data/app/packs/stylesheets/decidim/_tom_select.scss +23 -0
- data/app/packs/stylesheets/decidim/application.scss +3 -0
- data/app/packs/stylesheets/decidim/editor.scss +12 -33
- data/app/packs/stylesheets/decidim/geocoding_addons.scss +10 -2
- data/app/presenters/decidim/admin_log/participatory_space/member_presenter.rb +40 -0
- data/app/presenters/decidim/admin_log/static_page_resource_presenter.rb +1 -1
- data/app/presenters/decidim/authorization_transfer_presenter.rb +1 -1
- data/app/presenters/decidim/breadcrumb_root_menu_item_presenter.rb +3 -3
- data/app/presenters/decidim/footer_menu_presenter.rb +2 -4
- data/app/presenters/decidim/log/user_presenter.rb +1 -0
- data/app/presenters/decidim/log/value_types/access_mode_presenter.rb +45 -0
- data/app/presenters/decidim/menu_item_presenter.rb +15 -3
- data/app/presenters/decidim/participatory_space/member_presenter.rb +48 -0
- data/app/presenters/decidim/resource_locator_presenter.rb +22 -3
- data/app/presenters/decidim/stats_presenter.rb +1 -1
- data/app/queries/decidim/last_activity.rb +1 -1
- data/app/resolvers/decidim/meta_image_url_resolver.rb +7 -0
- data/app/serializers/decidim/exporters/participatory_space_serializer.rb +15 -1
- data/app/services/decidim/email_notification_generator.rb +2 -0
- data/app/services/decidim/notification_generator.rb +4 -0
- data/app/services/decidim/notifications_subscriptions_persistor.rb +6 -0
- data/app/services/decidim/push_subscription_endpoint_validator.rb +34 -0
- data/app/services/decidim/send_push_notification.rb +5 -1
- data/app/uploaders/decidim/image_uploader.rb +1 -1
- data/app/uploaders/decidim/organization_favicon_uploader.rb +4 -9
- data/app/validators/uploader_image_dimensions_validator.rb +13 -11
- data/app/views/decidim/delete_user_mailer/delete.html.erb +6 -0
- data/app/views/decidim/devise/invitations/edit.html.erb +3 -3
- data/app/views/decidim/devise/registrations/new.html.erb +1 -0
- data/app/views/decidim/devise/shared/_tos_fields.html.erb +3 -3
- data/app/views/decidim/gamification/badges/index.html.erb +1 -1
- data/app/views/decidim/homepage/show.html.erb +2 -2
- data/app/views/decidim/last_activities/index.html.erb +1 -1
- data/app/views/decidim/messaging/conversations/_error_modal.html.erb +11 -19
- data/app/views/decidim/messaging/conversations/_new_conversation_button.html.erb +1 -1
- data/app/views/decidim/messaging/conversations/_reply.html.erb +1 -1
- data/app/views/decidim/messaging/conversations/error.js.erb +12 -7
- data/app/views/decidim/messaging/conversations/new.html.erb +1 -1
- data/app/views/decidim/messaging/conversations/show.html.erb +2 -2
- data/app/views/decidim/newsletters/unsubscribe.html.erb +1 -1
- data/app/views/decidim/notification_mailer/event_received.html.erb +3 -3
- data/app/views/decidim/notifications_settings/show.html.erb +5 -5
- data/app/views/decidim/offline/show.html.erb +1 -1
- data/app/views/decidim/pages/_tabbed.html.erb +3 -3
- data/app/views/decidim/pages/index.html.erb +1 -1
- data/app/views/decidim/participatory_space/members/_member.html.erb +1 -0
- data/app/views/decidim/profiles/show.html.erb +1 -1
- data/app/views/decidim/searches/_filters.html.erb +1 -1
- data/app/views/decidim/shared/_filters.html.erb +5 -5
- data/app/views/decidim/shared/_resource_actions.html.erb +4 -4
- data/app/views/decidim/shared/_results_per_page.html.erb +1 -1
- data/app/views/decidim/shared/filters/_check_boxes_tree.html.erb +2 -2
- data/app/views/decidim/shared/filters/_collection.html.erb +1 -1
- data/app/views/decidim/shared/filters/_dropdown_label.html.erb +4 -3
- data/app/views/decidim/user_activities/index.html.erb +1 -1
- data/app/views/devise/mailer/{invite_private_user.html.erb → invite_member.html.erb} +2 -2
- data/app/views/devise/mailer/{invite_private_user.text.erb → invite_member.text.erb} +2 -2
- data/app/views/layouts/decidim/_head.html.erb +2 -2
- data/app/views/layouts/decidim/_wrapper.html.erb +3 -3
- data/app/views/layouts/decidim/footer/_focus_mode_main.html.erb +0 -1
- data/app/views/layouts/decidim/footer/_main.html.erb +1 -2
- data/app/views/layouts/decidim/footer/_main_links.html.erb +56 -28
- data/app/views/layouts/decidim/header/_focus_mode_back_button.html.erb +4 -1
- data/app/views/layouts/decidim/header/_main.html.erb +17 -8
- data/app/views/layouts/decidim/header/_main_language_chooser.html.erb +24 -0
- data/app/views/layouts/decidim/header/_main_links_desktop.html.erb +56 -56
- data/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +2 -2
- data/app/views/layouts/decidim/header/_main_links_mobile_item_account.html.erb +3 -1
- data/app/views/layouts/decidim/header/_main_menu_mobile.html.erb +18 -5
- data/app/views/layouts/decidim/header/_main_search.html.erb +3 -3
- data/app/views/layouts/decidim/header/_menu.html.erb +5 -5
- data/app/views/layouts/decidim/header/_menu_breadcrumb_desktop.html.erb +40 -12
- data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile.html.erb +33 -0
- data/app/views/layouts/decidim/shared/_layout_center.html.erb +1 -1
- data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
- data/app/views/layouts/decidim/shared/_layout_two_col.html.erb +1 -1
- data/config/initializers/decidim_locale_aware_named_route_helper.rb +16 -0
- data/config/initializers/devise.rb +6 -0
- data/config/initializers/invisible_captcha.rb +1 -0
- data/config/locales/ar.yml +6 -38
- data/config/locales/bg.yml +3 -39
- data/config/locales/ca-IT.yml +91 -58
- data/config/locales/ca.yml +91 -58
- data/config/locales/cs.yml +54 -58
- data/config/locales/de.yml +45 -68
- data/config/locales/el.yml +3 -31
- data/config/locales/en.yml +88 -55
- data/config/locales/es-MX.yml +93 -60
- data/config/locales/es-PY.yml +93 -60
- data/config/locales/es.yml +95 -62
- data/config/locales/eu.yml +124 -92
- data/config/locales/fi-plain.yml +93 -55
- data/config/locales/fi.yml +96 -58
- data/config/locales/fr-CA.yml +70 -52
- data/config/locales/fr.yml +71 -54
- data/config/locales/ga-IE.yml +3 -1
- data/config/locales/gl.yml +3 -31
- data/config/locales/hu.yml +7 -40
- data/config/locales/id-ID.yml +3 -30
- data/config/locales/is-IS.yml +0 -6
- data/config/locales/it.yml +15 -33
- data/config/locales/ja.yml +105 -71
- data/config/locales/lb.yml +3 -33
- data/config/locales/lt.yml +4 -37
- data/config/locales/lv.yml +3 -30
- data/config/locales/nl.yml +3 -33
- data/config/locales/no.yml +3 -33
- data/config/locales/pl.yml +7 -41
- data/config/locales/pt-BR.yml +24 -65
- data/config/locales/pt.yml +3 -33
- data/config/locales/ro-RO.yml +12 -55
- data/config/locales/ru.yml +0 -16
- data/config/locales/sk.yml +1417 -32
- data/config/locales/sv.yml +44 -62
- data/config/locales/tr-TR.yml +20 -37
- data/config/locales/uk.yml +0 -9
- data/config/locales/zh-CN.yml +3 -30
- data/config/locales/zh-TW.yml +4 -35
- data/config/routes.rb +140 -76
- data/db/data/20251213075429_rename_members_in_action_log.rb +22 -0
- data/db/data/20260319145808_rename_send_to_members_in_newsletter.rb +27 -0
- data/db/migrate/20200730142511_add_file_upload_settings_to_decidim_organizations.rb +13 -15
- data/db/migrate/20250217192438_convert_user_groups_into_users.rb +3 -2
- data/db/migrate/20250523104311_move_cta_to_hero_content_block.rb +1 -1
- data/db/migrate/20250527122040_move_highlighted_content_banner_settings_to_content_block.rb +1 -1
- data/db/migrate/20250819110800_convert_private_exports_id_to_uuid.rb +2 -2
- data/db/migrate/20251112132305_remove_legacy_images_from_core_module.rb +27 -0
- data/db/migrate/20251205122428_rename_participatory_space_private_users_to_members.rb +9 -0
- data/db/migrate/20251216185133_rename_privatable_to_to_participatory_space_in_members.rb +10 -0
- data/db/migrate/20260208201405_remove_user_group_core.rb +21 -0
- data/db/migrate/20260208201406_remove_user_group_memberships.rb +30 -0
- data/db/migrate/20260208201407_remove_user_group_organizations.rb +11 -0
- data/db/migrate/20260217152425_remove_enable_participatory_space_filters_from_decidim_organizations.rb +7 -0
- data/db/migrate/20260314081619_add_index_on_decidim_members.rb +25 -0
- data/decidim-core.gemspec +28 -28
- data/lib/decidim/acts_as_tree.rb +12 -12
- data/lib/decidim/admin_filters_registry.rb +1 -1
- data/lib/decidim/amendable.rb +5 -1
- data/lib/decidim/api/functions/category_list.rb +1 -0
- data/lib/decidim/api/functions/component_finder_base.rb +1 -1
- data/lib/decidim/api/functions/component_list.rb +3 -1
- data/lib/decidim/api/functions/component_list_base.rb +1 -0
- data/lib/decidim/api/functions/participatory_space_finder_base.rb +1 -1
- data/lib/decidim/api/functions/participatory_space_list_base.rb +1 -0
- data/lib/decidim/api/functions/user_entity_list.rb +2 -1
- data/lib/decidim/api/interfaces/amendable_entity_interface.rb +1 -0
- data/lib/decidim/api/interfaces/amendable_interface.rb +1 -0
- data/lib/decidim/api/interfaces/attachable_collection_interface.rb +1 -0
- data/lib/decidim/api/interfaces/attachable_interface.rb +1 -0
- data/lib/decidim/api/interfaces/author_interface.rb +2 -1
- data/lib/decidim/api/interfaces/authorable_interface.rb +1 -0
- data/lib/decidim/api/interfaces/categories_container_interface.rb +1 -0
- data/lib/decidim/api/interfaces/categorizable_interface.rb +1 -0
- data/lib/decidim/api/interfaces/coauthorable_interface.rb +1 -0
- data/lib/decidim/api/interfaces/component_interface.rb +9 -8
- data/lib/decidim/api/interfaces/fingerprint_interface.rb +1 -0
- data/lib/decidim/api/interfaces/followable_interface.rb +2 -0
- data/lib/decidim/api/interfaces/likeable_interface.rb +2 -2
- data/lib/decidim/api/interfaces/localizable_interface.rb +1 -0
- data/lib/decidim/api/interfaces/participatory_space_interface.rb +1 -0
- data/lib/decidim/api/interfaces/referable_interface.rb +1 -0
- data/lib/decidim/api/interfaces/scopable_interface.rb +1 -0
- data/lib/decidim/api/interfaces/taxonomizable_interface.rb +1 -0
- data/lib/decidim/api/interfaces/timestamps_interface.rb +1 -0
- data/lib/decidim/api/interfaces/traceable_interface.rb +1 -0
- data/lib/decidim/api/types/attachment_collection_type.rb +5 -3
- data/lib/decidim/api/types/attachment_type.rb +11 -4
- data/lib/decidim/api/types/badge_score_type.rb +28 -0
- data/lib/decidim/api/types/moderation_type.rb +25 -0
- data/lib/decidim/api/types/participant_details_type.rb +17 -0
- data/lib/decidim/api/types/reportable_type.rb +18 -0
- data/lib/decidim/api/types/reportable_user_type.rb +17 -0
- data/lib/decidim/api/types/static_page_topic_type.rb +16 -0
- data/lib/decidim/api/types/static_page_type.rb +22 -0
- data/lib/decidim/api/types/taxonomy_type.rb +2 -0
- data/lib/decidim/api/types/user_moderation_type.rb +36 -0
- data/lib/decidim/api/types/user_type.rb +13 -0
- data/lib/decidim/asset_router/pipeline.rb +1 -1
- data/lib/decidim/asset_router/storage.rb +9 -9
- data/lib/decidim/assets/tailwind/tailwind.config.js.erb +4 -1
- data/lib/decidim/attachment_attributes.rb +58 -9
- data/lib/decidim/attribute_encryptor.rb +51 -10
- data/lib/decidim/attribute_object/model.rb +0 -5
- data/lib/decidim/block_registry.rb +1 -1
- data/lib/decidim/coauthorable.rb +2 -1
- data/lib/decidim/command.rb +2 -1
- data/lib/decidim/content_parsers/blob_parser.rb +3 -3
- data/lib/decidim/content_processor.rb +1 -1
- data/lib/decidim/content_renderers/base_renderer.rb +112 -0
- data/lib/decidim/content_renderers/blob_renderer.rb +6 -9
- data/lib/decidim/content_renderers/mention_resource_renderer.rb +10 -6
- data/lib/decidim/content_renderers/resource_renderer.rb +16 -7
- data/lib/decidim/content_renderers/user_renderer.rb +11 -9
- data/lib/decidim/core/api.rb +8 -0
- data/lib/decidim/core/content_blocks/registry_manager.rb +4 -10
- data/lib/decidim/core/engine.rb +10 -34
- data/lib/decidim/core/menu.rb +0 -26
- data/lib/decidim/core/test/factories.rb +32 -18
- data/lib/decidim/core/test/shared_examples/access_mode_restricted_participatory_spaces.rb +175 -0
- data/lib/decidim/core/test/shared_examples/access_mode_transparent_participatory_spaces.rb +244 -0
- data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +10 -10
- data/lib/decidim/core/test/shared_examples/amendable/amendment_event_examples.rb +2 -2
- data/lib/decidim/core/test/shared_examples/amendable/amendment_promoted_event_examples.rb +3 -3
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +147 -117
- data/lib/decidim/core/test/shared_examples/fingerprint_examples.rb +2 -0
- data/lib/decidim/core/test/shared_examples/has_members.rb +63 -0
- data/lib/decidim/core/test/shared_examples/has_space_in_mcell_examples.rb +2 -1
- data/lib/decidim/core/test/shared_examples/manage_share_tokens_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/map_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/participant_details_examples.rb +16 -0
- data/lib/decidim/core/test/shared_examples/participatory_space_members_page_examples.rb +10 -10
- data/lib/decidim/core/test/shared_examples/participatory_space_members_shared_examples.rb +121 -0
- data/lib/decidim/core/test/shared_examples/resource_liked_event_examples.rb +3 -3
- data/lib/decidim/core/test/shared_examples/resource_locator_presenter_examples.rb +7 -7
- data/lib/decidim/core/test/shared_examples/searchable_participatory_space_examples.rb +3 -3
- data/lib/decidim/core/test/shared_examples/searchable_results_examples.rb +2 -2
- data/lib/decidim/core/test/shared_examples/simple_event.rb +1 -0
- data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +2 -2
- data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +1 -1
- data/lib/decidim/core/test.rb +2 -1
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +222 -335
- data/lib/decidim/download_your_data_serializers/{download_your_data_participatory_space_private_user_serializer.rb → download_your_data_member_serializer.rb} +6 -6
- data/lib/decidim/download_your_data_serializers.rb +2 -2
- data/lib/decidim/engine_router.rb +31 -6
- data/lib/decidim/exporters/csv.rb +1 -1
- data/lib/decidim/filter_form_builder.rb +1 -1
- data/lib/decidim/form_builder.rb +58 -36
- data/{app/controllers/concerns → lib}/decidim/form_factory.rb +11 -1
- data/lib/decidim/has_settings.rb +2 -2
- data/lib/decidim/legacy_form_builder.rb +1 -0
- data/lib/decidim/locale_router_detector.rb +41 -0
- data/lib/decidim/maintenance/import_models/scope.rb +1 -1
- data/lib/decidim/maintenance/import_models.rb +0 -2
- data/lib/decidim/maintenance/taxonomy_importer.rb +1 -1
- data/lib/decidim/map/autocomplete.rb +4 -3
- data/lib/decidim/map/dynamic_map.rb +3 -1
- data/lib/decidim/map/frontend.rb +1 -1
- data/lib/decidim/map/geocoding.rb +2 -2
- data/lib/decidim/map/static_map.rb +10 -22
- data/lib/decidim/map/utility.rb +3 -6
- data/lib/decidim/map.rb +2 -2
- data/lib/decidim/menu.rb +1 -1
- data/lib/decidim/menu_item.rb +1 -0
- data/lib/decidim/menu_registry.rb +1 -1
- data/lib/decidim/moderation_tools.rb +1 -1
- data/lib/decidim/newsletter_encryptor.rb +5 -8
- data/lib/decidim/organization_settings.rb +2 -2
- data/lib/decidim/participable.rb +1 -0
- data/lib/decidim/participatory_space/has_members.rb +61 -0
- data/lib/decidim/participatory_space_manifest.rb +0 -4
- data/lib/decidim/participatory_space_resourceable.rb +10 -1
- data/lib/decidim/participatory_space_user.rb +1 -1
- data/lib/decidim/routes/locale_redirects.rb +47 -0
- data/lib/decidim/routes.rb +7 -0
- data/lib/decidim/search_resource_fields_mapper.rb +3 -4
- data/lib/decidim/searchable.rb +9 -4
- data/lib/decidim/seeds.rb +17 -0
- data/lib/decidim/shakapacker/runner.rb +4 -4
- data/lib/decidim/shakapacker/shakapacker.yml +28 -3
- data/lib/decidim/taxonomizable.rb +1 -1
- data/lib/decidim/translatable_attributes.rb +9 -3
- data/lib/decidim/view_model.rb +5 -1
- data/lib/devise/models/decidim_newsletterable.rb +1 -1
- data/lib/tasks/decidim_mailers_tasks.rake +31 -9
- data/lib/tasks/decidim_procfile.rake +1 -1
- data/lib/tasks/decidim_tasks.rake +0 -1
- data/lib/tasks/decidim_taxonomies.rake +1 -1
- data/lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake +0 -1
- data/lib/tasks/upgrade/decidim_encryption.rake +12 -0
- data/lib/tasks/upgrade/decidim_migrate_wysiwyg_content.rake +0 -1
- data/lib/tasks/upgrade/decidim_remove_deleted_users_left_data_tasks.rake +1 -1
- data/lib/tasks/upgrade/{fix_deleted_private_follows.rake → fix_deleted_members_follows.rake} +5 -5
- data/lib/tasks/upgrade/migrations.rake +0 -1
- data/lib/tasks/upgrade/user_groups_migration.rake +0 -1
- metadata +244 -132
- data/app/cells/decidim/content_blocks/global_menu/show.erb +0 -11
- data/app/cells/decidim/content_blocks/global_menu_cell.rb +0 -35
- data/app/cells/decidim/content_blocks/menu_breadcrumb_last_activity/show.erb +0 -10
- data/app/cells/decidim/content_blocks/menu_breadcrumb_last_activity_cell.rb +0 -49
- data/app/cells/decidim/participatory_space_dropdown_metadata/links.erb +0 -9
- data/app/cells/decidim/participatory_space_dropdown_metadata/metadata.erb +0 -1
- data/app/cells/decidim/participatory_space_dropdown_metadata/show.erb +0 -11
- data/app/cells/decidim/participatory_space_dropdown_metadata_cell.rb +0 -26
- data/app/commands/decidim/gallery_methods.rb +0 -107
- data/app/controllers/concerns/decidim/has_members_page.rb +0 -25
- data/app/jobs/decidim/newsletters_opt_in_job.rb +0 -11
- data/app/jobs/decidim/user_report_job.rb +0 -11
- data/app/models/decidim/participatory_space_private_user.rb +0 -51
- data/app/packs/src/decidim/controllers/sticky_header/controller.js +0 -116
- data/app/packs/src/decidim/controllers/sticky_header/sticky_header.test.js +0 -320
- data/app/packs/src/decidim/dropdown_menu.js +0 -18
- data/app/packs/src/decidim/identity_selector_dialog.js +0 -33
- data/app/packs/src/decidim/vendor/tribute.js +0 -1890
- data/app/packs/stylesheets/decidim/_tribute.scss +0 -36
- data/app/presenters/decidim/admin_log/participatory_space_private_user_presenter.rb +0 -38
- data/app/presenters/decidim/participatory_space_private_user_presenter.rb +0 -46
- data/app/views/decidim/participants_account_mailer/removal_notification.html.erb +0 -11
- data/app/views/decidim/participatory_space_private_users/_participatory_space_private_user.html.erb +0 -1
- data/app/views/layouts/decidim/footer/_main_language_chooser.html.erb +0 -26
- data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +0 -34
- data/app/views/layouts/decidim/header/_menu_breadcrumb_main_dropdown_desktop.html.erb +0 -10
- data/app/views/layouts/decidim/header/_menu_breadcrumb_main_dropdown_mobile.html.erb +0 -17
- data/app/views/layouts/decidim/header/_menu_breadcrumb_main_dropdown_top_left.html.erb +0 -2
- data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +0 -33
- data/app/views/layouts/decidim/header/_mobile_language_choose.html.erb +0 -25
- data/lib/decidim/core/test/shared_examples/has_private_users.rb +0 -63
- data/lib/decidim/core/test/shared_examples/participatory_space_dropdown_metadata_cell_examples.rb +0 -81
- data/lib/decidim/has_private_users.rb +0 -57
- data/lib/decidim/maintenance/import_models/assembly_type.rb +0 -49
- data/lib/decidim/maintenance/import_models/participatory_process_type.rb +0 -21
- data/lib/decidim/query_extensions.rb +0 -64
|
@@ -5,6 +5,7 @@ module Decidim
|
|
|
5
5
|
# This interface represents an object that have a reference field.
|
|
6
6
|
module ReferableInterface
|
|
7
7
|
include Decidim::Api::Types::BaseInterface
|
|
8
|
+
|
|
8
9
|
description "An interface that can be used in display reference methods"
|
|
9
10
|
|
|
10
11
|
field :reference, GraphQL::Types::String, "The reference for this record", null: true
|
|
@@ -5,6 +5,7 @@ module Decidim
|
|
|
5
5
|
# This interface represents a scopable object.
|
|
6
6
|
module ScopableInterface
|
|
7
7
|
include Decidim::Api::Types::BaseInterface
|
|
8
|
+
|
|
8
9
|
description "An interface that can be used in scopable objects."
|
|
9
10
|
|
|
10
11
|
field :scope, Decidim::Core::ScopeApiType, "The object's scope", null: true
|
|
@@ -5,6 +5,7 @@ module Decidim
|
|
|
5
5
|
# This interface represents a categorizable object.
|
|
6
6
|
module TaxonomizableInterface
|
|
7
7
|
include Decidim::Api::Types::BaseInterface
|
|
8
|
+
|
|
8
9
|
description "An interface that can be used in taxonomizable objects."
|
|
9
10
|
|
|
10
11
|
field :taxonomies, [Decidim::Core::TaxonomyType], "The object's taxonomies", null: true
|
|
@@ -5,6 +5,7 @@ module Decidim
|
|
|
5
5
|
# This interface represents an object with standard create_at and updated_at timestamps.
|
|
6
6
|
module TimestampsInterface
|
|
7
7
|
include Decidim::Api::Types::BaseInterface
|
|
8
|
+
|
|
8
9
|
description "An interface that can be used in objects with created_at and updated_at attributes"
|
|
9
10
|
|
|
10
11
|
field :created_at, Decidim::Core::DateTimeType, description: "The date and time this object was created", null: true
|
|
@@ -5,6 +5,7 @@ module Decidim
|
|
|
5
5
|
# This interface represents an traceable object.
|
|
6
6
|
module TraceableInterface
|
|
7
7
|
include Decidim::Api::Types::BaseInterface
|
|
8
|
+
|
|
8
9
|
description "An interface that can be used in objects with traceability (versions)"
|
|
9
10
|
|
|
10
11
|
field :versions, [Decidim::Core::TraceVersionType, { null: true }], "This object's versions", null: false
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
module Decidim
|
|
4
4
|
module Core
|
|
5
|
+
# This type represents an attachment collection
|
|
5
6
|
class AttachmentCollectionType < Decidim::Api::Types::BaseObject
|
|
6
7
|
description "A file attachment collection"
|
|
7
8
|
|
|
8
|
-
field :description, Decidim::Core::TranslatedFieldType, "The description of this AttachmentCollection.", null: false
|
|
9
|
-
field :name, Decidim::Core::TranslatedFieldType, "The name of this AttachmentCollection.", null: false
|
|
10
|
-
|
|
11
9
|
field :attachments, [Decidim::Core::AttachmentType, { null: true }], "This object's attachments", null: false
|
|
10
|
+
field :description, Decidim::Core::TranslatedFieldType, "The description of this Attachment Collection", null: false
|
|
11
|
+
field :id, GraphQL::Types::ID, "Internal ID of this Attachment Collection", null: false
|
|
12
|
+
field :name, Decidim::Core::TranslatedFieldType, "The name of this Attachment Collection", null: false
|
|
13
|
+
field :weight, GraphQL::Types::Int, "The weight of this Attachment Collection", null: true
|
|
12
14
|
end
|
|
13
15
|
end
|
|
14
16
|
end
|
|
@@ -2,14 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
module Decidim
|
|
4
4
|
module Core
|
|
5
|
+
# This type represents an attachment
|
|
5
6
|
class AttachmentType < Decidim::Api::Types::BaseObject
|
|
6
7
|
description "A file attachment"
|
|
8
|
+
implements Decidim::Core::TimestampsInterface
|
|
7
9
|
|
|
8
|
-
field :
|
|
9
|
-
field :
|
|
10
|
-
field :
|
|
11
|
-
field :
|
|
10
|
+
field :content_type, GraphQL::Types::String, "The content type of this attachment (could be 'text/uri-list', 'image/jpeg', or any allowed content types)", null: true
|
|
11
|
+
field :description, Decidim::Core::TranslatedFieldType, "The description of this attachment", null: false
|
|
12
|
+
field :file_size, GraphQL::Types::String, "The file size of this attachment", null: true
|
|
13
|
+
field :id, GraphQL::Types::ID, "Internal ID of this attachment", null: false
|
|
14
|
+
field :link, GraphQL::Types::String, "The attached link of this attachment", null: true
|
|
15
|
+
field :thumbnail, GraphQL::Types::String, "A thumbnail of this attachment, if it is an image", method: :thumbnail_url, null: true
|
|
16
|
+
field :title, Decidim::Core::TranslatedFieldType, "The title of this attachment", null: false
|
|
17
|
+
field :type, GraphQL::Types::String, "The type of this attachment (could be 'link', 'jpeg', 'pdf' or any other allowed extensions)", method: :file_type, null: false
|
|
12
18
|
field :url, GraphQL::Types::String, "The url of this attachment", null: false
|
|
19
|
+
field :weight, GraphQL::Types::Int, "The weight of this attachment", null: true
|
|
13
20
|
end
|
|
14
21
|
end
|
|
15
22
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Core
|
|
5
|
+
class BadgeScoreType < Decidim::Api::Types::BaseObject
|
|
6
|
+
description "An user badge score"
|
|
7
|
+
|
|
8
|
+
field :description, GraphQL::Types::String, "The description of this badge", null: false
|
|
9
|
+
field :image, GraphQL::Types::String, "The image of this badge", null: false
|
|
10
|
+
field :level, GraphQL::Types::Int, "The level of this badge", null: false
|
|
11
|
+
field :name, GraphQL::Types::String, "The name of this badge", null: false, method: :badge_name
|
|
12
|
+
field :score, GraphQL::Types::Int, "The score of this badge", null: false
|
|
13
|
+
|
|
14
|
+
delegate :level, :score, to: :status
|
|
15
|
+
delegate :image, :description, to: :manifest
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def manifest
|
|
20
|
+
@manifest ||= status.badge
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def status
|
|
24
|
+
@status ||= Decidim::Gamification.status_for(object.user, object.badge_name)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Core
|
|
5
|
+
# This type represents a content moderation record
|
|
6
|
+
class ModerationType < Decidim::Api::Types::BaseObject
|
|
7
|
+
description "A moderation detail"
|
|
8
|
+
|
|
9
|
+
implements Decidim::Core::TimestampsInterface
|
|
10
|
+
|
|
11
|
+
field :hidden_at, Decidim::Core::DateTimeType, "The date and time when the resource was hidden", null: true
|
|
12
|
+
field :id, GraphQL::Types::ID, "The ID of the moderation", null: false
|
|
13
|
+
field :report_count, GraphQL::Types::Int, "The number of reports of this resource", null: true
|
|
14
|
+
field :reported_content, GraphQL::Types::String, "The content that has been reported", null: true
|
|
15
|
+
field :reported_url, GraphQL::Types::String, "The URL of the resource that was reported", null: true
|
|
16
|
+
field :reports, [Decidim::Core::ReportableType, { null: true }], "The reports of this resource", null: true
|
|
17
|
+
|
|
18
|
+
def reported_url
|
|
19
|
+
return "" unless object.reportable.respond_to?(:reported_content_url)
|
|
20
|
+
|
|
21
|
+
object.reportable.reported_content_url
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Core
|
|
5
|
+
class ParticipantDetailsType < Decidim::Api::Types::BaseObject
|
|
6
|
+
description "details of a participant"
|
|
7
|
+
|
|
8
|
+
field :email, GraphQL::Types::String, "The user's email", null: false
|
|
9
|
+
field :name, GraphQL::Types::String, "The user's name", null: false
|
|
10
|
+
field :nickname, GraphQL::Types::String, "The user's nickname", null: false
|
|
11
|
+
|
|
12
|
+
def self.authorized?(object, context)
|
|
13
|
+
super && allowed_to?(:read, :admin_dashboard, object, context, scope: :admin)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Core
|
|
5
|
+
# This type represents a content report
|
|
6
|
+
class ReportableType < Decidim::Api::Types::BaseObject
|
|
7
|
+
description "A report object"
|
|
8
|
+
|
|
9
|
+
implements Decidim::Core::TimestampsInterface
|
|
10
|
+
|
|
11
|
+
field :details, GraphQL::Types::String, "The details of this report", null: false
|
|
12
|
+
field :id, GraphQL::Types::ID, "The ID of this reportable", null: false
|
|
13
|
+
field :locale, GraphQL::Types::String, "The locale of the reportable", null: false
|
|
14
|
+
field :reason, GraphQL::Types::String, "The reason of this report", null: false
|
|
15
|
+
field :user, UserType, "The author of this report", null: true
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Core
|
|
5
|
+
# This type represents an user report
|
|
6
|
+
class ReportableUserType < Decidim::Api::Types::BaseObject
|
|
7
|
+
description "An user report"
|
|
8
|
+
|
|
9
|
+
implements Decidim::Core::TimestampsInterface
|
|
10
|
+
|
|
11
|
+
field :details, GraphQL::Types::String, "The details of this report", null: false
|
|
12
|
+
field :id, GraphQL::Types::ID, "The ID of this report", null: false
|
|
13
|
+
field :reason, GraphQL::Types::String, "The reason of this report", null: false
|
|
14
|
+
field :user, UserType, "The author of this report", null: true
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Core
|
|
5
|
+
# This type represents a topic's page
|
|
6
|
+
class StaticPageTopicType < Decidim::Api::Types::BaseObject
|
|
7
|
+
description "The current organization static page topics"
|
|
8
|
+
|
|
9
|
+
field :description, Decidim::Core::TranslatedFieldType, "The description of this static page topic", null: false
|
|
10
|
+
field :id, GraphQL::Types::ID, "Internal ID of this static page topic", null: false
|
|
11
|
+
field :show_in_footer, GraphQL::Types::Boolean, "Whether this static page topic should be shown in the footer", null: false
|
|
12
|
+
field :static_pages, [Decidim::Core::StaticPageType, { null: true }], "The static pages associated to this static page topic", null: true, method: :pages
|
|
13
|
+
field :title, Decidim::Core::TranslatedFieldType, "The title of this static page topic", null: false
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Core
|
|
5
|
+
# This type represents a page
|
|
6
|
+
class StaticPageType < Decidim::Api::Types::BaseObject
|
|
7
|
+
description "The current organization static pages"
|
|
8
|
+
|
|
9
|
+
implements Decidim::Core::TimestampsInterface
|
|
10
|
+
|
|
11
|
+
field :content, Decidim::Core::TranslatedFieldType, "The content of this page", null: true
|
|
12
|
+
field :id, GraphQL::Types::ID, "The id of this page", null: false
|
|
13
|
+
field :title, Decidim::Core::TranslatedFieldType, "The title of this page", null: false
|
|
14
|
+
field :topic, Decidim::Core::StaticPageTopicType, "The topic of this page", null: true
|
|
15
|
+
field :url, GraphQL::Types::String, "The URL of this page", null: false
|
|
16
|
+
|
|
17
|
+
def url
|
|
18
|
+
Decidim::EngineRouter.new("decidim", { host: object.organization.host }).page_url(object)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -6,10 +6,12 @@ module Decidim
|
|
|
6
6
|
description "A taxonomy that can be applied to other resources."
|
|
7
7
|
|
|
8
8
|
field :children, [Decidim::Core::TaxonomyType], "The children of this taxonomy.", null: false
|
|
9
|
+
field :children_count, GraphQL::Types::Int, "The number of children of this taxonomy."
|
|
9
10
|
field :id, GraphQL::Types::ID, "The id of this taxonomy.", null: false
|
|
10
11
|
field :is_root, Boolean, "Whether this taxonomy is a root taxonomy (root taxonomies have no parents).", null: false, method: :root?
|
|
11
12
|
field :name, Decidim::Core::TranslatedFieldType, "The name of this taxonomy.", null: false
|
|
12
13
|
field :parent, Decidim::Core::TaxonomyType, "The parent of this taxonomy.", null: true
|
|
14
|
+
field :taxonomizations_count, GraphQL::Types::Int, "The number of taxonomizations of this taxonomy."
|
|
13
15
|
end
|
|
14
16
|
end
|
|
15
17
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Core
|
|
5
|
+
# This type represents a user moderation
|
|
6
|
+
class UserModerationType < Decidim::Api::Types::BaseObject
|
|
7
|
+
description "A moderated user detail"
|
|
8
|
+
|
|
9
|
+
implements Decidim::Core::TimestampsInterface
|
|
10
|
+
|
|
11
|
+
field :about, GraphQL::Types::String, "The about data of this user", null: true
|
|
12
|
+
field :block_reasons, GraphQL::Types::String, "The reasons why the user was blocked", null: true
|
|
13
|
+
field :blocked_at, Decidim::Core::DateTimeType, "The date at which the user was blocked", null: true
|
|
14
|
+
field :blocking_user, UserType, "The user who blocked the user", null: true
|
|
15
|
+
field :id, GraphQL::Types::ID, "The ID of the moderation", null: false
|
|
16
|
+
field :reports, [Decidim::Core::ReportableUserType, { null: true }], "The reports for this user", null: true
|
|
17
|
+
field :user_id, GraphQL::Types::ID, "The ID of this user'", null: false, method: :decidim_user_id
|
|
18
|
+
|
|
19
|
+
def about
|
|
20
|
+
object.user.presenter.about
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def block_reasons
|
|
24
|
+
object.blocking.justification
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def blocked_at
|
|
28
|
+
object.user.blocked_at
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def blocking_user
|
|
32
|
+
object.blocking.blocking_user
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -7,18 +7,25 @@ module Decidim
|
|
|
7
7
|
description "A user"
|
|
8
8
|
|
|
9
9
|
implements Decidim::Core::AuthorInterface
|
|
10
|
+
implements Decidim::Core::FollowableInterface
|
|
11
|
+
implements Decidim::Core::TimestampsInterface
|
|
10
12
|
|
|
13
|
+
field :about, GraphQL::Types::String, "The user's about data", null: true
|
|
11
14
|
field :avatar_url, GraphQL::Types::String, "The user's avatar url", null: false
|
|
12
15
|
field :badge, GraphQL::Types::String, "A badge for the user", null: false
|
|
16
|
+
field :badges, [Decidim::Core::BadgeScoreType, { null: true }], "The user's badges", null: true
|
|
13
17
|
field :deleted, GraphQL::Types::Boolean, "Whether the user's account has been deleted or not", null: false
|
|
14
18
|
field :direct_messages_enabled, GraphQL::Types::String,
|
|
15
19
|
null: false,
|
|
16
20
|
description: ["If the user making the request is logged in, it will return whether this recipient accepts a conversation or not.",
|
|
17
21
|
" It will return false for non-logged requests."].join
|
|
22
|
+
field :followers_count, GraphQL::Types::Int, "The number of users following this user", null: true
|
|
23
|
+
field :following_count, GraphQL::Types::Int, "The number of users this user is following", null: true
|
|
18
24
|
field :id, GraphQL::Types::ID, "The user's id", null: false
|
|
19
25
|
field :name, GraphQL::Types::String, "The user's name", null: false
|
|
20
26
|
field :nickname, GraphQL::Types::String, "The user's nickname", null: false
|
|
21
27
|
field :organization_name, Decidim::Core::TranslatedFieldType, "The user's organization name", null: false
|
|
28
|
+
field :personal_url, GraphQL::Types::String, "The user's personal url", null: true
|
|
22
29
|
field :profile_path, GraphQL::Types::String, "The user's profile url", null: false
|
|
23
30
|
|
|
24
31
|
def nickname
|
|
@@ -49,6 +56,12 @@ module Decidim
|
|
|
49
56
|
object.presenter.badge
|
|
50
57
|
end
|
|
51
58
|
|
|
59
|
+
def badges
|
|
60
|
+
return [] unless object.organization.badges_enabled?
|
|
61
|
+
|
|
62
|
+
Decidim::Gamification::BadgeScore.where(user_id: object.id)
|
|
63
|
+
end
|
|
64
|
+
|
|
52
65
|
def self.authorized?(object, context)
|
|
53
66
|
super && object.confirmed? && !object.blocked? && !object.deleted?
|
|
54
67
|
end
|
|
@@ -22,7 +22,7 @@ module Decidim
|
|
|
22
22
|
|
|
23
23
|
# Generates the correct URL to the asset with the provided options.
|
|
24
24
|
#
|
|
25
|
-
#
|
|
25
|
+
# Accepts the options for the URL that are the normal route
|
|
26
26
|
# options Rails route helpers accept
|
|
27
27
|
# @return [String] The full URL to the asset or when host cannot be
|
|
28
28
|
# resolved, the asset path.
|
|
@@ -26,7 +26,7 @@ module Decidim
|
|
|
26
26
|
class Storage
|
|
27
27
|
# Initializes the router.
|
|
28
28
|
#
|
|
29
|
-
# @param [ActiveStorage::Attached, ActiveStorage::Blob] The asset to route
|
|
29
|
+
# @param asset [ActiveStorage::Attached, ActiveStorage::Blob] The asset to route
|
|
30
30
|
# to
|
|
31
31
|
def initialize(asset)
|
|
32
32
|
@asset = asset
|
|
@@ -41,7 +41,7 @@ module Decidim
|
|
|
41
41
|
|
|
42
42
|
# Generates the correct URL to the asset with the provided options.
|
|
43
43
|
#
|
|
44
|
-
#
|
|
44
|
+
# Accepts any options for the URL that are the normal route options
|
|
45
45
|
# Rails route helpers accept
|
|
46
46
|
# @return [String] The URL of the asset
|
|
47
47
|
def url(**options)
|
|
@@ -115,8 +115,8 @@ module Decidim
|
|
|
115
115
|
# already when the logic below is unnecessary. This logic is needed e.g.
|
|
116
116
|
# for serializers where the request context is not available.
|
|
117
117
|
#
|
|
118
|
-
# @param record The record for which to check the organization
|
|
119
|
-
# @param opts Options for building the URL
|
|
118
|
+
# @param record [Object] The record for which to check the organization
|
|
119
|
+
# @param opts [Hash] Options for building the URL
|
|
120
120
|
# @return [void]
|
|
121
121
|
def ensure_current_host(record, **opts)
|
|
122
122
|
return if asset_url_available?
|
|
@@ -141,7 +141,7 @@ module Decidim
|
|
|
141
141
|
|
|
142
142
|
# Determines the organization for the passed record.
|
|
143
143
|
#
|
|
144
|
-
# @param record The record for which to fetch the organization
|
|
144
|
+
# @param record [Object] The record for which to fetch the organization
|
|
145
145
|
# @return [Decidim::Organization, nil] The organization for the record or
|
|
146
146
|
# `nil` if the organization cannot be determined
|
|
147
147
|
def organization_for(record)
|
|
@@ -154,8 +154,7 @@ module Decidim
|
|
|
154
154
|
|
|
155
155
|
# Returns the URL for the given blob object.
|
|
156
156
|
#
|
|
157
|
-
# @param
|
|
158
|
-
# @param options Options for building the URL
|
|
157
|
+
# @param options [Hash] Options for building the URL
|
|
159
158
|
# @return [String, nil] The URL to the blob object or `nil` if the blob is
|
|
160
159
|
# not defined.
|
|
161
160
|
def blob_url(**options)
|
|
@@ -207,7 +206,8 @@ module Decidim
|
|
|
207
206
|
# because once the image is stored at the storage service, it already has
|
|
208
207
|
# the correct file extension.
|
|
209
208
|
#
|
|
210
|
-
#
|
|
209
|
+
# Accepts any options for the URL that are the normal route options
|
|
210
|
+
# Rails route helpers accept
|
|
211
211
|
# @return [String, nil] The converted representation URL or `nil` if the
|
|
212
212
|
# asset is not defined.
|
|
213
213
|
def rails_representation_url(**)
|
|
@@ -235,7 +235,7 @@ module Decidim
|
|
|
235
235
|
# variant has to be served through the service's own representation URL
|
|
236
236
|
# causing it to be processed and stored at the storage service.
|
|
237
237
|
#
|
|
238
|
-
# @param options The options for building the URL
|
|
238
|
+
# @param options [Hash] The options for building the URL
|
|
239
239
|
# @return [String, nil] The variant URL at the storage service or `nil` if
|
|
240
240
|
# the variant has not been processed yet and does not yet exist at the
|
|
241
241
|
# storage service or `nil` when the asset is not defined
|
|
@@ -68,7 +68,7 @@ module.exports = {
|
|
|
68
68
|
sans: ["Source Sans Pro", "ui-sans-serif", "system-ui", "sans-serif"]
|
|
69
69
|
},
|
|
70
70
|
fontSize: {
|
|
71
|
-
xs: ["
|
|
71
|
+
xs: ["12px", "16px"],
|
|
72
72
|
sm: ["14px", "18px"],
|
|
73
73
|
md: ["16px", "20px"],
|
|
74
74
|
lg: ["18px", "23px"],
|
|
@@ -81,6 +81,9 @@ module.exports = {
|
|
|
81
81
|
extend: {
|
|
82
82
|
transitionProperty: {
|
|
83
83
|
'top': 'top',
|
|
84
|
+
},
|
|
85
|
+
screens: {
|
|
86
|
+
'xs': '375px'
|
|
84
87
|
}
|
|
85
88
|
}
|
|
86
89
|
},
|
|
@@ -15,24 +15,39 @@ module Decidim
|
|
|
15
15
|
#
|
|
16
16
|
# name - The attribute's name
|
|
17
17
|
#
|
|
18
|
-
#
|
|
19
18
|
# Example:
|
|
20
19
|
#
|
|
21
|
-
#
|
|
20
|
+
# attachments_attribute :photos
|
|
22
21
|
# # This will create two attributes of the following types:
|
|
23
22
|
# # attribute :photos, Array[Integer]
|
|
24
23
|
# # attribute :add_photos, Array
|
|
25
|
-
# # In addition, it will generate
|
|
26
|
-
# #
|
|
24
|
+
# # In addition, it will generate:
|
|
25
|
+
# # - A setter that handles String (JSON/CSV), Integer, or Array inputs.
|
|
26
|
+
# # - A getter that falls back to add_photos when the attribute is blank.
|
|
27
|
+
# # - Private helpers for parsing and extracting IDs.
|
|
27
28
|
#
|
|
28
29
|
# Returns nothing.
|
|
29
|
-
def attachments_attribute(name)
|
|
30
|
+
def attachments_attribute(name) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
30
31
|
attribute name, Array[Integer]
|
|
31
32
|
attribute :"add_#{name}", Array
|
|
32
33
|
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
34
|
+
# Setter: coerces String (JSON or comma-separated IDs) and bare Integer
|
|
35
|
+
# values into the expected Array[Integer] format before delegating to super.
|
|
36
|
+
define_method :"#{name}=" do |value|
|
|
37
|
+
case value
|
|
38
|
+
when String
|
|
39
|
+
parsed = send(:"parse_string_#{name}", value)
|
|
40
|
+
parsed.any? ? super(parsed) : super(value)
|
|
41
|
+
when Integer
|
|
42
|
+
super([value])
|
|
43
|
+
else
|
|
44
|
+
super(value)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Getter: resolves stored integer IDs to Decidim::Attachment records,
|
|
49
|
+
# caching the result on the instance. Falls back to extracting IDs from
|
|
50
|
+
# add_<name> when the attribute itself is blank, then resolves those too.
|
|
36
51
|
variable_name = "@#{name}_records"
|
|
37
52
|
define_method name do
|
|
38
53
|
return instance_variable_get(variable_name) if instance_variable_defined?(variable_name)
|
|
@@ -40,9 +55,15 @@ module Decidim
|
|
|
40
55
|
original = @attributes[name.to_s].value_before_type_cast
|
|
41
56
|
return original if original && !original.is_a?(Array)
|
|
42
57
|
|
|
58
|
+
ids = if super().blank? && send(:"add_#{name}").present?
|
|
59
|
+
send(:"extract_ids_from_add_#{name}")
|
|
60
|
+
else
|
|
61
|
+
super()
|
|
62
|
+
end
|
|
63
|
+
|
|
43
64
|
instance_variable_set(
|
|
44
65
|
variable_name,
|
|
45
|
-
|
|
66
|
+
ids.map do |attachment|
|
|
46
67
|
if attachment.is_a?(Integer)
|
|
47
68
|
Decidim::Attachment.find_by(id: attachment)
|
|
48
69
|
else
|
|
@@ -51,6 +72,34 @@ module Decidim
|
|
|
51
72
|
end.compact
|
|
52
73
|
)
|
|
53
74
|
end
|
|
75
|
+
|
|
76
|
+
# Private helpers -------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
define_method :"extract_ids_from_add_#{name}" do
|
|
79
|
+
send(:"add_#{name}")
|
|
80
|
+
.select { |item| item.is_a?(Hash) && (item[:id].present? || item["id"].present?) }
|
|
81
|
+
.map { |item| (item[:id] || item["id"]).to_i }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
define_method :"parse_string_#{name}" do |value|
|
|
85
|
+
return [] if value.blank?
|
|
86
|
+
|
|
87
|
+
send(:"parse_#{name}_ids", value)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
define_method :"parse_#{name}_ids" do |value|
|
|
91
|
+
ids = begin
|
|
92
|
+
Array(JSON.parse(value))
|
|
93
|
+
rescue JSON::ParserError
|
|
94
|
+
value.split(",").map(&:strip)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
ids.map(&:to_i).reject(&:zero?)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private :"extract_ids_from_add_#{name}"
|
|
101
|
+
private :"parse_string_#{name}"
|
|
102
|
+
private :"parse_#{name}_ids"
|
|
54
103
|
end
|
|
55
104
|
end
|
|
56
105
|
end
|
|
@@ -2,11 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
module Decidim
|
|
4
4
|
class AttributeEncryptor
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
attr_reader :secret, :hash_digest_class, :secret_key_base, :key_len, :is_retry
|
|
6
|
+
|
|
7
|
+
def initialize(secret: "attribute", **options)
|
|
8
|
+
@secret = secret
|
|
9
|
+
@hash_digest_class = options.fetch(:hash_digest_class, Rails.application.config.active_support.hash_digest_class)
|
|
10
|
+
@secret_key_base = options.fetch(:secret_key_base, Rails.application.secret_key_base)
|
|
11
|
+
@key_len = options.fetch(:key_len, ActiveSupport::MessageEncryptor.key_len)
|
|
12
|
+
@is_retry = options.fetch(:is_retry, false)
|
|
7
13
|
end
|
|
8
14
|
|
|
9
|
-
def
|
|
15
|
+
def encrypt(string)
|
|
16
|
+
return if string.blank?
|
|
17
|
+
|
|
18
|
+
encryptor.encrypt_and_sign(string)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def decrypt(string_encrypted)
|
|
10
22
|
return if string_encrypted.blank?
|
|
11
23
|
|
|
12
24
|
# `ActiveSupport::MessageEncryptor` expects all values passed to the
|
|
@@ -15,16 +27,45 @@ module Decidim
|
|
|
15
27
|
# If something else is passed, just return the value as is.
|
|
16
28
|
return string_encrypted unless string_encrypted.is_a?(String)
|
|
17
29
|
|
|
18
|
-
|
|
30
|
+
encryptor.decrypt_and_verify(string_encrypted)
|
|
31
|
+
rescue ActiveSupport::MessageEncryptor::InvalidMessage => e
|
|
32
|
+
# Since we have migrated from SHA1 to SHA256, we need to ensure that any encrypted string not migrated is still being decrypted successfully.
|
|
33
|
+
# There are some resources that are still using SHA1, so we need to retry with the legacy encryptor.
|
|
34
|
+
# Some of those resources are:
|
|
35
|
+
# - Newsletter unsubscribe links (being sent to users via email)
|
|
36
|
+
raise e if is_retry
|
|
37
|
+
|
|
38
|
+
legacy_encryptor.decrypt(string_encrypted)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.encrypt(string)
|
|
42
|
+
cryptor.encrypt(string)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.decrypt(string_encrypted)
|
|
46
|
+
cryptor.decrypt(string_encrypted)
|
|
19
47
|
end
|
|
20
48
|
|
|
21
49
|
def self.cryptor
|
|
22
|
-
@cryptor ||=
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
50
|
+
@cryptor ||= new(secret: "attribute")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def legacy_encryptor
|
|
56
|
+
@legacy_encryptor ||= self.class.new(secret:, hash_digest_class: OpenSSL::Digest::SHA1, is_retry: true)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def encryptor
|
|
60
|
+
@encryptor ||= ActiveSupport::MessageEncryptor.new(key)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def key
|
|
64
|
+
@key ||= key_generator.generate_key(secret_key_base, key_len)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def key_generator
|
|
68
|
+
@key_generator ||= ActiveSupport::KeyGenerator.new(secret, hash_digest_class:)
|
|
28
69
|
end
|
|
29
70
|
end
|
|
30
71
|
end
|
|
@@ -107,11 +107,6 @@ module Decidim
|
|
|
107
107
|
# through symbols by calling `obj.attributes[:key]` or
|
|
108
108
|
# `obj.attributes.slice(:key1, :key2)`. In the legacy Virtus models, this
|
|
109
109
|
# returned a hash with symbol keys.
|
|
110
|
-
#
|
|
111
|
-
# Deprecated:
|
|
112
|
-
# Attributes access through symbols is deprecated and may be removed in
|
|
113
|
-
# future versions. Please refactor all your attributes calls to access the
|
|
114
|
-
# attributes through string keys.
|
|
115
110
|
def attributes
|
|
116
111
|
super.with_indifferent_access
|
|
117
112
|
end
|
|
@@ -8,7 +8,7 @@ module Decidim
|
|
|
8
8
|
class BlockRegistry
|
|
9
9
|
# Provides access to the registered blocks with their names.
|
|
10
10
|
#
|
|
11
|
-
# @return [Hash
|
|
11
|
+
# @return [Hash{Symbol => Proc}] A hash of the currently registered blocks
|
|
12
12
|
# with their keys as the hash keys and the blocks as the hash values.
|
|
13
13
|
def registrations
|
|
14
14
|
@registrations ||= {}
|
data/lib/decidim/coauthorable.rb
CHANGED
|
@@ -138,7 +138,8 @@ module Decidim
|
|
|
138
138
|
# Adds a new coauthor to the list of coauthors. The coauthorship is created with
|
|
139
139
|
# current object as coauthorable and `user` param as author.
|
|
140
140
|
#
|
|
141
|
-
# @param author
|
|
141
|
+
# @param author [Decidim::User] The new coauthor.
|
|
142
|
+
# @param extra_attributes [Hash{Symbol => Object}]
|
|
142
143
|
# @extra_attrs: Extra
|
|
143
144
|
def add_coauthor(author, extra_attributes = {})
|
|
144
145
|
return if coauthorships.exists?(decidim_author_id: author.id, decidim_author_type: author.class.base_class.name)
|