decidim-core 0.26.2 → 0.27.0.rc1
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 +1 -1
- data/app/cells/decidim/amendable/announcement_cell.rb +3 -8
- data/app/cells/decidim/announcement_cell.rb +1 -1
- data/app/cells/decidim/author_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/footer_sub_hero/show.erb +1 -1
- data/app/cells/decidim/content_blocks/hero/show.erb +1 -1
- data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +3 -3
- data/app/cells/decidim/content_blocks/highlighted_elements_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/how_to_participate/show.erb +1 -1
- data/app/cells/decidim/content_blocks/last_activity/show.erb +1 -1
- data/app/cells/decidim/content_blocks/last_activity_cell.rb +3 -3
- data/app/cells/decidim/content_blocks/stats_cell.rb +4 -4
- data/app/cells/decidim/content_blocks/sub_hero/show.erb +1 -1
- data/app/cells/decidim/data_consent/category.erb +64 -0
- data/app/cells/decidim/data_consent/dialog.erb +29 -0
- data/app/cells/decidim/data_consent/modal.erb +39 -0
- data/app/cells/decidim/data_consent/show.erb +3 -0
- data/app/cells/decidim/data_consent_cell.rb +21 -0
- data/app/cells/decidim/follow_button_cell.rb +5 -7
- data/app/cells/decidim/profile_sidebar_cell.rb +1 -1
- data/app/cells/decidim/search_results_cell.rb +1 -1
- data/app/cells/decidim/tos_page/refuse_btn_modal.erb +1 -1
- data/app/cells/decidim/upload_modal/files.erb +52 -0
- data/app/cells/decidim/upload_modal/modal.erb +49 -0
- data/app/cells/decidim/upload_modal/show.erb +3 -0
- data/app/cells/decidim/upload_modal_cell.rb +205 -0
- data/app/cells/decidim/user_conversation/reply.erb +1 -1
- data/app/cells/decidim/user_conversations/add_conversation_users.erb +5 -3
- data/app/cells/decidim/version_cell.rb +2 -13
- data/app/cells/decidim/versions_list_cell.rb +2 -13
- data/app/cells/decidim/versions_list_item_cell.rb +2 -13
- data/app/commands/decidim/accept_group_invitation.rb +1 -1
- data/app/commands/decidim/accept_user_group_join_request.rb +1 -1
- data/app/commands/decidim/amendable/accept.rb +1 -1
- data/app/commands/decidim/amendable/create_draft.rb +1 -1
- data/app/commands/decidim/amendable/destroy_draft.rb +1 -1
- data/app/commands/decidim/amendable/promote.rb +1 -1
- data/app/commands/decidim/amendable/publish_draft.rb +1 -1
- data/app/commands/decidim/amendable/reject.rb +1 -1
- data/app/commands/decidim/amendable/update_draft.rb +1 -1
- data/app/commands/decidim/amendable/withdraw.rb +1 -1
- data/app/commands/decidim/attachment_methods.rb +3 -2
- data/app/commands/decidim/create_editor_image.rb +1 -1
- data/app/commands/decidim/create_follow.rb +1 -1
- data/app/commands/decidim/create_omniauth_registration.rb +2 -3
- data/app/commands/decidim/create_registration.rb +1 -2
- data/app/commands/decidim/create_report.rb +1 -1
- data/app/commands/decidim/create_user_group.rb +2 -2
- data/app/commands/decidim/create_user_report.rb +5 -3
- data/app/commands/decidim/delete_follow.rb +1 -1
- data/app/commands/decidim/demote_membership.rb +1 -1
- data/app/commands/decidim/destroy_account.rb +1 -1
- data/app/commands/decidim/endorse_resource.rb +1 -1
- data/app/commands/decidim/gallery_methods.rb +45 -10
- data/app/commands/decidim/invite_user.rb +1 -3
- data/app/commands/decidim/invite_user_again.rb +1 -1
- data/app/commands/decidim/invite_user_to_group.rb +1 -1
- data/app/commands/decidim/join_user_group.rb +1 -1
- data/app/commands/decidim/leave_user_group.rb +8 -2
- data/app/commands/decidim/messaging/reply_to_conversation.rb +2 -2
- data/app/commands/decidim/messaging/start_conversation.rb +2 -2
- data/app/commands/decidim/multiple_attachments_methods.rb +44 -5
- data/app/commands/decidim/promote_membership.rb +1 -1
- data/app/commands/decidim/reject_group_invitation.rb +1 -1
- data/app/commands/decidim/reject_user_group_join_request.rb +1 -1
- data/app/commands/decidim/remove_user_from_group.rb +1 -1
- data/app/commands/decidim/resend_confirmation_instructions.rb +18 -0
- data/app/commands/decidim/search.rb +10 -9
- data/app/commands/decidim/unendorse_resource.rb +1 -1
- data/app/commands/decidim/unsubscribe_settings.rb +1 -1
- data/app/commands/decidim/update_account.rb +2 -2
- data/app/commands/decidim/update_notifications_settings.rb +3 -2
- data/app/commands/decidim/update_password.rb +31 -0
- data/app/commands/decidim/update_user_group.rb +2 -2
- data/app/commands/decidim/update_user_interests.rb +1 -1
- data/app/commands/decidim/validate_upload.rb +15 -0
- data/app/controllers/concerns/decidim/devise_controllers.rb +0 -1
- data/app/controllers/concerns/decidim/filter_resource.rb +23 -24
- data/app/controllers/concerns/decidim/force_authentication.rb +1 -2
- data/app/controllers/concerns/decidim/http_caching_disabler.rb +1 -1
- data/app/controllers/concerns/decidim/needs_password_change.rb +43 -0
- data/app/controllers/concerns/decidim/needs_tos_accepted.rb +3 -3
- data/app/controllers/concerns/decidim/orderable.rb +1 -1
- data/app/controllers/concerns/decidim/participatory_space_context.rb +2 -2
- data/app/controllers/decidim/account_controller.rb +45 -0
- data/app/controllers/decidim/application_controller.rb +1 -1
- data/app/controllers/decidim/devise/invitations_controller.rb +2 -0
- data/app/controllers/decidim/devise/passwords_controller.rb +33 -0
- data/app/controllers/decidim/devise/registrations_controller.rb +2 -0
- data/app/controllers/decidim/devise/sessions_controller.rb +2 -0
- data/app/controllers/decidim/{data_portability_controller.rb → download_your_data_controller.rb} +8 -8
- data/app/controllers/decidim/groups_controller.rb +5 -0
- data/app/controllers/decidim/last_activities_controller.rb +7 -9
- data/app/controllers/decidim/manifests_controller.rb +11 -0
- data/app/controllers/decidim/newsletters_controller.rb +1 -1
- data/app/controllers/decidim/notifications_subscriptions_controller.rb +16 -0
- data/app/controllers/decidim/offline_controller.rb +7 -0
- data/app/controllers/decidim/profiles_controller.rb +1 -1
- data/app/controllers/decidim/searches_controller.rb +4 -3
- data/app/controllers/decidim/short_links_controller.rb +35 -0
- data/app/controllers/decidim/upload_validations_controller.rb +44 -0
- data/app/controllers/decidim/user_activities_controller.rb +32 -16
- data/app/controllers/decidim/user_interests_controller.rb +0 -2
- data/app/controllers/decidim/user_timeline_controller.rb +6 -8
- data/app/events/decidim/change_nickname_event.rb +21 -0
- data/app/forms/decidim/account_form.rb +7 -6
- data/app/forms/decidim/form.rb +1 -1
- data/app/forms/decidim/messaging/conversation_form.rb +1 -1
- data/app/forms/decidim/notifications_settings_form.rb +8 -2
- data/app/forms/decidim/password_form.rb +10 -0
- data/app/forms/decidim/registration_form.rb +10 -4
- data/app/forms/decidim/upload_validation_form.rb +54 -0
- data/app/forms/decidim/user_group_form.rb +1 -1
- data/app/forms/decidim/user_interest_scope_form.rb +1 -1
- data/app/forms/decidim/user_interests_form.rb +1 -1
- data/app/forms/translatable_presence_validator.rb +2 -2
- data/app/forms/url_validator.rb +1 -1
- data/app/helpers/decidim/application_helper.rb +2 -2
- data/app/helpers/decidim/attachments_helper.rb +1 -1
- data/app/helpers/decidim/cells_paginate_helper.rb +1 -1
- data/app/helpers/decidim/datalist_select_helper.rb +40 -0
- data/app/helpers/decidim/decidim_form_helper.rb +1 -1
- data/app/helpers/decidim/followable_helper.rb +1 -1
- data/app/helpers/decidim/icon_helper.rb +1 -1
- data/app/helpers/decidim/layout_helper.rb +15 -1
- data/app/helpers/decidim/map_helper.rb +12 -8
- data/app/helpers/decidim/meta_tags_helper.rb +0 -2
- data/app/helpers/decidim/notifications_settings_helper.rb +15 -0
- data/app/helpers/decidim/passwords_helper.rb +41 -0
- data/app/helpers/decidim/sanitize_helper.rb +1 -0
- data/app/helpers/decidim/searches_helper.rb +6 -6
- data/app/helpers/decidim/short_link_helper.rb +28 -0
- data/app/helpers/decidim/translations_helper.rb +2 -2
- data/app/jobs/decidim/{data_portability_export_job.rb → download_your_data_export_job.rb} +5 -5
- data/app/jobs/decidim/email_notifications_digest_generator_job.rb +21 -0
- data/app/jobs/decidim/notification_generator_for_recipient_job.rb +5 -3
- data/app/jobs/decidim/reminder_generator_job.rb +12 -0
- data/app/jobs/decidim/resend_confirmation_instructions_job.rb +11 -0
- data/app/jobs/decidim/user_report_job.rb +2 -2
- data/app/mailers/concerns/decidim/multitenant_asset_host.rb +11 -3
- data/app/mailers/decidim/application_mailer.rb +1 -1
- data/app/mailers/decidim/block_user_mailer.rb +8 -7
- data/app/mailers/decidim/export_mailer.rb +2 -2
- data/app/mailers/decidim/newsletter_mailer.rb +2 -2
- data/app/mailers/decidim/newsletters_opt_in_mailer.rb +7 -5
- data/app/mailers/decidim/notifications_digest_mailer.rb +23 -0
- data/app/mailers/decidim/user_report_mailer.rb +10 -11
- data/app/models/decidim/action_log.rb +86 -2
- data/app/models/decidim/amendment.rb +0 -1
- data/app/models/decidim/area.rb +1 -2
- data/app/models/decidim/area_type.rb +5 -0
- data/app/models/decidim/attachment.rb +6 -0
- data/app/models/decidim/attachment_collection.rb +5 -0
- data/app/models/decidim/category.rb +9 -4
- data/app/models/decidim/coauthorship.rb +0 -2
- data/app/models/decidim/contextual_help_section.rb +5 -1
- data/app/models/decidim/follow.rb +2 -2
- data/app/models/decidim/gamification/badge_score.rb +0 -1
- data/app/models/decidim/identity.rb +2 -2
- data/app/models/decidim/messaging/conversation.rb +4 -4
- data/app/models/decidim/messaging/message.rb +1 -2
- data/app/models/decidim/messaging/participation.rb +0 -2
- data/app/models/decidim/messaging/receipt.rb +0 -2
- data/app/models/decidim/notification.rb +5 -2
- data/app/models/decidim/oauth_application.rb +12 -1
- data/app/models/decidim/organization.rb +7 -7
- data/app/models/decidim/participatory_space_private_user.rb +4 -2
- data/app/models/decidim/permission_action.rb +1 -0
- data/app/models/decidim/reminder.rb +10 -0
- data/app/models/decidim/reminder_delivery.rb +7 -0
- data/app/models/decidim/reminder_record.rb +29 -0
- data/app/models/decidim/report.rb +2 -2
- data/app/models/decidim/scope.rb +3 -4
- data/app/models/decidim/scope_type.rb +5 -0
- data/app/models/decidim/share_token.rb +0 -2
- data/app/models/decidim/short_link.rb +162 -0
- data/app/models/decidim/user.rb +34 -6
- data/app/models/decidim/user_base_entity.rb +1 -1
- data/app/models/decidim/user_group.rb +3 -3
- data/app/models/decidim/user_moderation.rb +0 -2
- data/app/models/decidim/user_report.rb +2 -2
- data/app/packs/entrypoints/decidim_core.js +2 -2
- data/app/packs/entrypoints/decidim_sw.js +1 -0
- data/app/packs/src/decidim/autocomplete.js +298 -0
- data/app/packs/src/decidim/cookie_consent/consent_manager.js +133 -0
- data/app/packs/src/decidim/cookie_consent/cookie_consent.js +103 -0
- data/app/packs/src/decidim/datalist_select.js +36 -0
- data/app/packs/src/decidim/direct_uploads/upload_field.js +117 -0
- data/app/packs/src/decidim/direct_uploads/upload_modal.js +264 -0
- data/app/packs/src/decidim/direct_uploads/upload_utility.js +49 -0
- data/app/packs/src/decidim/direct_uploads/uploader.js +89 -0
- data/app/packs/src/decidim/external_domain_warning.js +1 -1
- data/app/packs/src/decidim/external_link.js +14 -3
- data/app/packs/src/decidim/external_link.test.js +64 -0
- data/app/packs/src/decidim/geocoding.js +10 -35
- data/app/packs/src/decidim/identity_selector_dialog.js +1 -1
- data/app/packs/src/decidim/impersonation.js +3 -3
- data/app/packs/src/decidim/input_character_counter.js +177 -7
- data/app/packs/src/decidim/input_multiple_mentions.js +87 -187
- data/app/packs/src/decidim/map/factory.js +3 -1
- data/app/packs/src/decidim/map/icon.js +2 -1
- data/app/packs/src/decidim/map/legacy.js +2 -2
- data/app/packs/src/decidim/map/svg-icon.js +248 -0
- data/app/packs/src/decidim/map.js +2 -2
- data/app/packs/src/decidim/security/selfxss_warning.js +5 -1
- data/app/packs/src/decidim/session_timeouter.js +15 -15
- data/app/packs/src/decidim/sw/a2hs.js +28 -0
- data/app/packs/src/decidim/sw/index.js +3 -0
- data/app/packs/src/decidim/sw/loader.js +18 -0
- data/app/packs/src/decidim/sw/push-permissions.js +87 -0
- data/app/packs/src/decidim/sw/sw.js +80 -0
- data/app/packs/src/decidim/vizzs/areachart.js +33 -28
- data/app/packs/src/decidim/vizzs/{metrics.js → index.js} +0 -0
- data/app/packs/src/decidim/vizzs/linechart.js +23 -18
- data/app/packs/src/decidim/vizzs/rowchart.js +15 -11
- data/app/packs/stylesheets/decidim/email.scss +66 -0
- data/app/packs/stylesheets/decidim/layouts/_user.scss +8 -0
- data/app/packs/stylesheets/decidim/modules/_autocomplete.scss +99 -0
- data/app/packs/stylesheets/decidim/modules/_cookie-consent.scss +115 -0
- data/app/packs/stylesheets/decidim/modules/_footer.scss +4 -0
- data/app/packs/stylesheets/decidim/modules/_input-multiple-mentions.scss +29 -2
- data/app/packs/stylesheets/decidim/modules/_modules.scss +3 -1
- data/app/packs/stylesheets/decidim/modules/_reveal.scss +15 -0
- data/app/packs/stylesheets/decidim/modules/_upload_modal.scss +143 -0
- data/app/packs/stylesheets/decidim/utils/_fontface.scss +3 -0
- data/app/permissions/decidim/permissions.rb +2 -4
- data/app/presenters/decidim/admin_log/area_type_presenter.rb +34 -0
- data/app/presenters/decidim/admin_log/attachment_collection_presenter.rb +35 -0
- data/app/presenters/decidim/admin_log/attachment_presenter.rb +27 -0
- data/app/presenters/decidim/admin_log/category_presenter.rb +36 -0
- data/app/presenters/decidim/admin_log/component_presenter.rb +35 -3
- data/app/presenters/decidim/admin_log/contextual_help_section_presenter.rb +33 -0
- data/app/presenters/decidim/admin_log/organization_presenter.rb +9 -4
- data/app/presenters/decidim/admin_log/scope_type_presenter.rb +34 -0
- data/app/presenters/decidim/home_stats_presenter.rb +4 -2
- data/app/presenters/decidim/log/base_presenter.rb +1 -1
- data/app/presenters/decidim/menu_item_presenter.rb +1 -1
- data/app/presenters/decidim/metric_charts_presenter.rb +7 -1
- data/app/presenters/decidim/nil_presenter.rb +3 -1
- data/app/presenters/decidim/notification_to_mailer_presenter.rb +39 -0
- data/app/presenters/decidim/notifications_digest_presenter.rb +42 -0
- data/app/presenters/decidim/official_author_presenter.rb +4 -0
- data/app/presenters/decidim/organization_presenter.rb +22 -0
- data/app/presenters/decidim/push_notification_presenter.rb +24 -0
- data/app/presenters/decidim/stats_presenter.rb +1 -1
- data/app/presenters/decidim/validation_errors_presenter.rb +1 -1
- data/app/queries/decidim/messaging/user_conversations.rb +1 -1
- data/app/queries/decidim/metric_manage.rb +1 -1
- data/app/queries/decidim/own_activities.rb +11 -0
- data/app/queries/decidim/participatory_processes_with_user_role.rb +1 -1
- data/app/{services/decidim/activity_search.rb → queries/decidim/public_activities.rb} +35 -77
- data/app/queries/decidim/public_components.rb +1 -1
- data/app/queries/decidim/similar_emendations.rb +1 -1
- data/app/queries/decidim/stats_users_count.rb +1 -1
- data/app/queries/decidim/user_groups/accepted_memberships.rb +1 -1
- data/app/queries/decidim/user_groups/accepted_user_groups.rb +1 -1
- data/app/queries/decidim/user_groups/accepted_users.rb +1 -1
- data/app/queries/decidim/user_groups/admin_memberships.rb +1 -1
- data/app/queries/decidim/user_groups/invited_memberships.rb +1 -1
- data/app/queries/decidim/user_groups/manageable_user_groups.rb +1 -1
- data/app/queries/decidim/user_groups/member_memberships.rb +1 -1
- data/app/services/decidim/{data_portability_exporter.rb → download_your_data_exporter.rb} +6 -6
- data/app/services/decidim/email_notification_generator.rb +2 -2
- data/app/services/decidim/engine_resolver.rb +66 -0
- data/app/services/decidim/events_manager.rb +1 -1
- data/app/services/decidim/iframe_disabler.rb +31 -0
- data/app/services/decidim/notification_generator_for_recipient.rb +1 -1
- data/app/services/decidim/notifications_digest_sending_decider.rb +18 -0
- data/app/services/decidim/notifications_subscriptions_persistor.rb +37 -0
- data/app/services/decidim/open_data_exporter.rb +1 -1
- data/app/services/decidim/resource_search.rb +17 -164
- data/app/services/decidim/send_push_notification.rb +59 -0
- data/app/services/decidim/traceability.rb +1 -1
- data/app/uploaders/decidim/application_uploader.rb +2 -12
- data/app/uploaders/decidim/cw/attachment_uploader.rb +1 -1
- data/app/uploaders/decidim/cw/{data_portability_uploader.rb → download_your_data_uploader.rb} +3 -3
- data/app/uploaders/decidim/cw/image_uploader.rb +2 -2
- data/app/uploaders/decidim/organization_favicon_uploader.rb +3 -2
- data/app/validators/passthru_validator.rb +29 -21
- data/app/validators/password_validator.rb +25 -4
- data/app/validators/uploader_image_dimensions_validator.rb +1 -1
- data/app/views/decidim/account/_account_notification.js.erb +20 -0
- data/app/views/decidim/account/_password_fields.html.erb +2 -2
- data/app/views/decidim/account/cancel_email_change.js.erb +6 -0
- data/app/views/decidim/account/resend_confirmation_instructions.erb +1 -0
- data/app/views/decidim/account/show.html.erb +19 -6
- data/app/views/decidim/application/{_attachments.html.erb → _attachments.erb} +2 -2
- data/app/views/decidim/application/_collection.html.erb +1 -1
- data/app/views/decidim/application/{_document.html.erb → _document.erb} +0 -0
- data/app/views/decidim/application/{_documents.html.erb → _documents.erb} +2 -2
- data/app/views/decidim/application/{_photos.html.erb → _photos.erb} +0 -0
- data/app/views/decidim/devise/confirmations/new.html.erb +1 -1
- data/app/views/decidim/devise/invitations/edit.html.erb +3 -4
- data/app/views/decidim/devise/omniauth_registrations/new.html.erb +3 -3
- data/app/views/decidim/devise/passwords/edit.html.erb +7 -5
- data/app/views/decidim/devise/passwords/new.html.erb +1 -1
- data/app/views/decidim/devise/registrations/edit.html.erb +5 -5
- data/app/views/decidim/devise/registrations/new.html.erb +5 -5
- data/app/views/decidim/devise/sessions/new.html.erb +2 -2
- data/app/views/decidim/{data_portability → download_your_data}/export.html.erb +0 -0
- data/app/views/decidim/{data_portability → download_your_data}/show.html.erb +2 -2
- data/app/views/decidim/export_mailer/download_your_data_export.html.erb +7 -0
- data/app/views/decidim/last_activities/index.html.erb +1 -1
- data/app/views/decidim/manifests/show.json.erb +31 -0
- data/app/views/decidim/messaging/conversations/_add_conversation_users.html.erb +5 -3
- data/app/views/decidim/messaging/conversations/_reply.html.erb +1 -1
- data/app/views/decidim/messaging/conversations/_start.html.erb +1 -3
- data/app/views/decidim/messaging/conversations/create.js.erb +1 -0
- data/app/views/decidim/notifications_digest_mailer/_email_content.html.erb +11 -0
- data/app/views/decidim/notifications_digest_mailer/digest_mail.erb +27 -0
- data/app/views/decidim/notifications_settings/show.html.erb +34 -9
- data/app/views/decidim/offline/show.html.erb +9 -0
- data/app/views/decidim/pages/_standalone.html.erb +1 -1
- data/app/views/decidim/reported_mailer/hide.html.erb +1 -1
- data/app/views/decidim/reported_mailer/report.html.erb +1 -1
- data/app/views/decidim/scopes/picker.html.erb +1 -1
- data/app/views/decidim/searches/_filters.html.erb +2 -2
- data/app/views/decidim/shared/participatory_space_filters/_filters.html.erb +3 -3
- data/app/views/decidim/user_report_mailer/notify.html.erb +10 -3
- data/app/views/devise/mailer/confirmation_instructions.html.erb +3 -1
- data/app/views/layouts/decidim/_application.html.erb +6 -3
- data/app/views/layouts/decidim/_cookie_warning.html.erb +8 -8
- data/app/views/layouts/decidim/_decidim_javascript.html.erb +12 -0
- data/app/views/layouts/decidim/_head.html.erb +4 -2
- data/app/views/layouts/decidim/_js_configuration.html.erb +5 -1
- data/app/views/layouts/decidim/_main_footer.html.erb +1 -0
- data/app/views/layouts/decidim/_offline_banner.html.erb +11 -0
- data/app/views/layouts/decidim/widget.html.erb +2 -2
- data/config/assets.rb +1 -0
- data/config/locales/am-ET.yml +1 -0
- data/config/locales/ar.yml +48 -36
- data/config/locales/bg.yml +15 -30
- data/config/locales/ca.yml +186 -35
- data/config/locales/cs.yml +186 -33
- data/config/locales/da.yml +1 -0
- data/config/locales/de.yml +25 -36
- data/config/locales/el.yml +15 -30
- data/config/locales/en.yml +183 -32
- data/config/locales/eo.yml +4 -6
- data/config/locales/es-MX.yml +185 -34
- data/config/locales/es-PY.yml +185 -34
- data/config/locales/es.yml +185 -34
- data/config/locales/et.yml +1 -0
- data/config/locales/eu.yml +15 -36
- data/config/locales/fi-plain.yml +184 -33
- data/config/locales/fi.yml +184 -33
- data/config/locales/fr-CA.yml +170 -33
- data/config/locales/fr.yml +170 -33
- data/config/locales/ga-IE.yml +5 -7
- data/config/locales/gl.yml +47 -30
- data/config/locales/hr.yml +1 -0
- data/config/locales/hu.yml +65 -35
- data/config/locales/id-ID.yml +15 -29
- data/config/locales/is-IS.yml +6 -15
- data/config/locales/it.yml +22 -38
- data/config/locales/ja.yml +173 -34
- data/config/locales/ko.yml +1 -0
- data/config/locales/lb.yml +16 -32
- data/config/locales/lt.yml +1 -0
- data/config/locales/lv.yml +15 -28
- data/config/locales/mt.yml +1 -0
- data/config/locales/nl.yml +25 -33
- data/config/locales/no.yml +24 -35
- data/config/locales/om-ET.yml +1 -0
- data/config/locales/pl.yml +113 -32
- data/config/locales/pt-BR.yml +17 -32
- data/config/locales/pt.yml +16 -32
- data/config/locales/ro-RO.yml +20 -36
- data/config/locales/ru.yml +15 -27
- data/config/locales/si-LK.yml +1 -0
- data/config/locales/sk.yml +15 -30
- data/config/locales/sl.yml +1 -0
- data/config/locales/so-SO.yml +1 -0
- data/config/locales/sr-CS.yml +1 -0
- data/config/locales/sv.yml +69 -34
- data/config/locales/sw-KE.yml +1 -0
- data/config/locales/ti-ER.yml +1 -0
- data/config/locales/tr-TR.yml +15 -29
- data/config/locales/uk.yml +15 -26
- data/config/locales/val-ES.yml +1 -0
- data/config/locales/vi.yml +1 -0
- data/config/locales/zh-CN.yml +15 -28
- data/config/locales/zh-TW.yml +1 -0
- data/config/routes.rb +17 -2
- data/db/migrate/20180508111710_add_accepted_tos_version_field_to_users.rb +1 -0
- data/db/migrate/20181030090144_destroy_deleted_users_follows.rb +1 -0
- data/db/migrate/20190412131728_fix_user_names.rb +4 -4
- data/db/migrate/20210831181634_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
- data/db/migrate/20210831181635_create_active_storage_variant_records.active_storage.rb +14 -0
- data/db/migrate/20211208155453_create_decidim_reminders.rb +11 -0
- data/db/migrate/20211209121025_create_decidim_reminder_records.rb +11 -0
- data/db/migrate/20211209121040_create_decidim_reminder_deliveries.rb +10 -0
- data/db/migrate/20220118121921_change_required_description_categories.rb +7 -0
- data/db/migrate/20220127113419_add_notification_settings_to_users.rb +7 -0
- data/db/migrate/20220203121137_add_notifications_sending_frequency_to_users.rb +7 -0
- data/db/migrate/20220215172439_add_digest_sent_at_to_users.rb +7 -0
- data/db/migrate/20220323195258_add_index_to_decidim_users_notifications_sending_frequency.rb +7 -0
- data/db/migrate/20220427142214_drop_emails_on_notifications_flag_from_user.rb +15 -0
- data/db/migrate/20220518094535_add_previous_passwords_to_users.rb +20 -0
- data/db/migrate/20220524195530_create_decidim_short_links.rb +23 -0
- data/db/seeds.rb +17 -18
- data/lib/decidim/acts_as_tree.rb +47 -0
- data/lib/decidim/api/input_sorts/component_input_sort.rb +2 -1
- data/lib/decidim/api/interfaces/authorable_interface.rb +6 -5
- data/lib/decidim/asset_router.rb +80 -0
- data/lib/decidim/attachment_attributes.rb +8 -8
- data/lib/decidim/attribute_object/form.rb +174 -0
- data/lib/decidim/attribute_object/model.rb +148 -0
- data/lib/decidim/attribute_object/nested_validator.rb +22 -0
- data/lib/decidim/attribute_object/type_map.rb +14 -0
- data/lib/decidim/attribute_object/type_resolver.rb +91 -0
- data/lib/decidim/attribute_object.rb +26 -0
- data/lib/decidim/attributes/array.rb +62 -0
- data/lib/decidim/attributes/blob.rb +20 -0
- data/lib/decidim/attributes/clean_string.rb +12 -6
- data/lib/decidim/attributes/hash.rb +36 -0
- data/lib/decidim/attributes/integer.rb +17 -0
- data/lib/decidim/attributes/localized_date.rb +9 -7
- data/lib/decidim/attributes/model.rb +24 -0
- data/lib/decidim/attributes/object.rb +28 -0
- data/lib/decidim/attributes/symbol.rb +23 -0
- data/lib/decidim/attributes/time_with_zone.rb +9 -7
- data/lib/decidim/attributes.rb +29 -0
- data/lib/decidim/authorable.rb +21 -6
- data/lib/decidim/authorization_form_builder.rb +9 -11
- data/lib/decidim/carrier_wave_migrator_service.rb +15 -15
- data/lib/decidim/coauthorable.rb +22 -4
- data/lib/decidim/command.rb +44 -0
- data/lib/decidim/common_passwords.rb +1 -1
- data/lib/decidim/component_manifest.rb +5 -5
- data/lib/decidim/component_validator.rb +2 -2
- data/lib/decidim/content_block_manifest.rb +1 -1
- data/lib/decidim/content_parsers/hashtag_parser.rb +2 -2
- data/lib/decidim/content_parsers/resource_parser.rb +1 -1
- data/lib/decidim/content_parsers/user_group_parser.rb +1 -1
- data/lib/decidim/content_parsers/user_parser.rb +4 -4
- data/lib/decidim/content_renderers/hashtag_renderer.rb +1 -1
- data/lib/decidim/content_renderers/link_renderer.rb +2 -2
- data/lib/decidim/content_renderers/user_group_renderer.rb +1 -1
- data/lib/decidim/content_renderers/user_renderer.rb +1 -1
- data/lib/decidim/controller_helpers.rb +41 -0
- data/lib/decidim/core/engine.rb +29 -18
- data/lib/decidim/core/test/factories.rb +48 -8
- data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +16 -4
- data/lib/decidim/core/test/shared_examples/amendable/amendment_form_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/authorable_interface_examples.rb +15 -2
- data/lib/decidim/core/test/shared_examples/coauthorable_interface_examples.rb +2 -2
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +203 -0
- data/lib/decidim/core/test/shared_examples/localised_email.rb +1 -1
- data/lib/decidim/core/test/shared_examples/logo_email.rb +1 -1
- data/lib/decidim/core/test/shared_examples/map_examples.rb +2 -2
- data/lib/decidim/core/test/shared_examples/preview_component_with_share_token_examples.rb +0 -6
- data/lib/decidim/core/test/shared_examples/resource_search_examples.rb +120 -40
- data/lib/decidim/core/test/shared_examples/resourceable.rb +0 -6
- data/lib/decidim/core/test/shared_examples/searchable_participatory_space_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/searchable_resources_shared_context.rb +1 -1
- data/lib/decidim/core/test/shared_examples/system_endorse_resource_examples.rb +3 -3
- data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +2 -2
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +108 -14
- data/lib/decidim/{data_portability.rb → download_your_data.rb} +3 -3
- data/lib/decidim/{data_portability_serializers/data_portability_conversation_serializer.rb → download_your_data_serializers/download_your_data_conversation_serializer.rb} +2 -2
- data/lib/decidim/{data_portability_serializers/data_portability_follow_serializer.rb → download_your_data_serializers/download_your_data_follow_serializer.rb} +2 -2
- data/lib/decidim/{data_portability_serializers/data_portability_identity_serializer.rb → download_your_data_serializers/download_your_data_identity_serializer.rb} +2 -2
- data/lib/decidim/{data_portability_serializers/data_portability_notification_serializer.rb → download_your_data_serializers/download_your_data_notification_serializer.rb} +2 -2
- data/lib/decidim/{data_portability_serializers/data_portability_participatory_space_private_user_serializer.rb → download_your_data_serializers/download_your_data_participatory_space_private_user_serializer.rb} +2 -2
- data/lib/decidim/{data_portability_serializers/data_portability_report_serializer.rb → download_your_data_serializers/download_your_data_report_serializer.rb} +2 -2
- data/lib/decidim/{data_portability_serializers/data_portability_user_group_serializer.rb → download_your_data_serializers/download_your_data_user_group_serializer.rb} +2 -2
- data/lib/decidim/{data_portability_serializers/data_portability_user_serializer.rb → download_your_data_serializers/download_your_data_user_serializer.rb} +3 -3
- data/lib/decidim/download_your_data_serializers.rb +23 -0
- data/lib/decidim/engine_router.rb +7 -1
- data/lib/decidim/env.rb +56 -0
- data/lib/decidim/event_recorder.rb +25 -0
- data/lib/decidim/events/base_event.rb +10 -14
- data/lib/decidim/events/simple_event.rb +12 -4
- data/lib/decidim/exporters/export_data.rb +1 -1
- data/lib/decidim/exporters/export_manifest.rb +2 -1
- data/lib/decidim/file_validator_humanizer.rb +24 -1
- data/lib/decidim/filterable_resource.rb +55 -0
- data/lib/decidim/fingerprint_calculator.rb +2 -4
- data/lib/decidim/form_builder.rb +158 -130
- data/lib/decidim/gamification/badge.rb +2 -3
- data/lib/decidim/gamification/badge_scorer.rb +1 -0
- data/lib/decidim/has_area.rb +27 -0
- data/lib/decidim/has_attachments.rb +2 -2
- data/lib/decidim/has_category.rb +36 -0
- data/lib/decidim/importers/import_manifest.rb +3 -21
- data/lib/decidim/jsonb_attributes.rb +6 -4
- data/lib/decidim/manifest_messages.rb +23 -0
- data/lib/decidim/map/autocomplete.rb +6 -4
- data/lib/decidim/map/frontend.rb +2 -2
- data/lib/decidim/map/provider/geocoding/here.rb +5 -5
- data/lib/decidim/map/provider/here.rb +3 -0
- data/lib/decidim/map/provider/osm.rb +3 -0
- data/lib/decidim/map.rb +4 -4
- data/lib/decidim/menu.rb +1 -1
- data/lib/decidim/metric_manifest.rb +2 -2
- data/lib/decidim/nicknamizable.rb +1 -1
- data/lib/decidim/notification_setting_manifest.rb +19 -0
- data/lib/decidim/organization_settings.rb +8 -7
- data/lib/decidim/participatory_space_context_manifest.rb +2 -2
- data/lib/decidim/participatory_space_manifest.rb +2 -2
- data/lib/decidim/processes_file_locally.rb +31 -0
- data/lib/decidim/query.rb +84 -0
- data/lib/decidim/record_encryptor.rb +29 -8
- data/lib/decidim/reminder_manifest.rb +75 -0
- data/lib/decidim/reminder_registry.rb +67 -0
- data/lib/decidim/resource_manifest.rb +1 -1
- data/lib/decidim/resourceable.rb +11 -0
- data/lib/decidim/scopable.rb +15 -0
- data/lib/decidim/settings_manifest.rb +4 -4
- data/lib/decidim/spring.rb +16 -0
- data/lib/decidim/translatable_attributes.rb +12 -8
- data/lib/decidim/url_option_resolver.rb +50 -0
- data/lib/decidim/view_hooks.rb +1 -1
- data/lib/decidim/view_model.rb +5 -1
- data/lib/decidim/webpacker/thread_safe_compiler.rb +30 -0
- data/lib/decidim/webpacker/webpack/custom.js +15 -3
- data/lib/decidim/webpacker/webpacker.yml +1 -1
- data/lib/decidim/webpacker.rb +2 -0
- data/lib/devise/models/decidim_validatable.rb +1 -1
- data/lib/tasks/decidim_active_storage_migration_tasks.rake +1 -3
- data/lib/tasks/{decidim_data_portability_tasks.rake → decidim_download_your_data_tasks.rake} +9 -9
- data/lib/tasks/decidim_mailers_tasks.rake +23 -0
- data/lib/tasks/decidim_metrics_tasks.rake +1 -1
- data/lib/tasks/decidim_pwa_tasks.rake +18 -0
- data/lib/tasks/decidim_reminders_tasks.rake +17 -0
- data/lib/tasks/decidim_tasks.rake +6 -1
- data/lib/tasks/decidim_webpacker_tasks.rake +1 -1
- data/lib/tasks/upgrade/decidim_fix_nickname_uniqueness.rake +51 -0
- metadata +184 -83
- data/app/controllers/decidim/cookie_policy_controller.rb +0 -24
- data/app/helpers/decidim/cookies_helper.rb +0 -11
- data/app/packs/src/decidim/vizzs/renders.js +0 -9
- data/app/packs/src/decidim/vizzs.js +0 -1
- data/app/packs/stylesheets/decidim/modules/_cookie-bar.scss +0 -26
- data/app/services/decidim/home_activity_search.rb +0 -80
- data/app/services/decidim/participatory_space_search.rb +0 -54
- data/app/views/decidim/cookie_policy/accept.js.erb +0 -3
- data/app/views/decidim/export_mailer/data_portability_export.html.erb +0 -7
- data/lib/decidim/data_portability_serializers.rb +0 -23
- data/lib/decidim/middleware/rails_cookies.rb +0 -23
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module Decidim
|
|
4
4
|
class ShareToken < ApplicationRecord
|
|
5
|
-
validates :organization, presence: true
|
|
6
|
-
validates :user, presence: true
|
|
7
5
|
validates :token, presence: true, uniqueness: { scope: [:decidim_organization_id, :token_for_type, :token_for_id] }
|
|
8
6
|
|
|
9
7
|
belongs_to :organization, foreign_key: "decidim_organization_id", class_name: "Decidim::Organization"
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
# Short links are a way to reference specific locations within Decidim with
|
|
5
|
+
# shorted URLs, similar to the popular link shortening services. The original
|
|
6
|
+
# reason for creating the feature was to reference long calendar URLs in a
|
|
7
|
+
# more compact way for the URLs to be compatible with the calendar programs.
|
|
8
|
+
# When the URL is long with lots of filtering parameters included in it, it
|
|
9
|
+
# may be too long for specific 3rd party programs.
|
|
10
|
+
#
|
|
11
|
+
# This feature can be used to link to any URLs or resources in Decidim with a
|
|
12
|
+
# short reference.
|
|
13
|
+
class ShortLink < ApplicationRecord
|
|
14
|
+
belongs_to :organization, foreign_key: "decidim_organization_id", class_name: "Decidim::Organization"
|
|
15
|
+
belongs_to :target, polymorphic: true
|
|
16
|
+
|
|
17
|
+
validates :identifier, presence: true, uniqueness: true
|
|
18
|
+
|
|
19
|
+
before_validation :generate_identifier
|
|
20
|
+
|
|
21
|
+
# Finds a matching short link to the same target with exactly the same
|
|
22
|
+
# parameters if it already exists or creates a new one if it doesn't exist.
|
|
23
|
+
#
|
|
24
|
+
# @param target [ActiveRecord::Base] The target where this short link should
|
|
25
|
+
# link to. Most of the times [Decidim::Organization], [Decidim::Component]
|
|
26
|
+
# or some other top-level record.
|
|
27
|
+
# @param mounted_engine [String] The mounted engine helper name that will be
|
|
28
|
+
# used to generate the link.
|
|
29
|
+
# @param route_name [String, nil] The route name to be linked to. If not
|
|
30
|
+
# defined, the short link will be generated for the root URL for the
|
|
31
|
+
# mounted engine.
|
|
32
|
+
# @param params [Hash] The query parameters that should be included in the
|
|
33
|
+
# URL where this short link will redirect to.
|
|
34
|
+
# @return [Decidim::ShortLink] The short link instance to link to.
|
|
35
|
+
def self.to(target, mounted_engine, route_name: nil, params: {})
|
|
36
|
+
organization =
|
|
37
|
+
if target.is_a?(Decidim::Organization)
|
|
38
|
+
target
|
|
39
|
+
else
|
|
40
|
+
target.try(:organization)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
values = {
|
|
44
|
+
organization: organization,
|
|
45
|
+
target: target,
|
|
46
|
+
mounted_engine_name: mounted_engine,
|
|
47
|
+
route_name: route_name
|
|
48
|
+
}
|
|
49
|
+
existing =
|
|
50
|
+
if params
|
|
51
|
+
where(values).find_by("params = ?::jsonb", params.to_json)
|
|
52
|
+
else
|
|
53
|
+
find_by(values.merge(params: nil))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
existing || create!(values.merge(params: params))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Creates a random unique identifier for any new links. Raises an
|
|
60
|
+
# OutOfCandidatesError if a free candidate cannot be found with 20 tries.
|
|
61
|
+
# In this situation the older records should be removed from the database.
|
|
62
|
+
#
|
|
63
|
+
# @return [String] A new unique identifier.
|
|
64
|
+
def self.unique_identifier_within(organization)
|
|
65
|
+
1.step do |n|
|
|
66
|
+
raise OutOfCandidatesError if n > 20
|
|
67
|
+
|
|
68
|
+
# A-Z, a-z and 0-9
|
|
69
|
+
# 26 + 26 + 10 = 62 possibilities per character
|
|
70
|
+
# 62^10 ≈ 8×10¹⁷ total possibilities
|
|
71
|
+
candidate = SecureRandom.alphanumeric(10)
|
|
72
|
+
next if where(organization: organization, identifier: candidate).any?
|
|
73
|
+
|
|
74
|
+
return candidate
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Overrides the route_name method to add a default route name for the "root"
|
|
79
|
+
# path in case the route name is not defined for the record.
|
|
80
|
+
#
|
|
81
|
+
# @return [String] The route name to link to.
|
|
82
|
+
def route_name
|
|
83
|
+
super || "root"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Generates the short URL referencing this link.
|
|
87
|
+
#
|
|
88
|
+
# @return [String] The short URL that can be used to link to the target.
|
|
89
|
+
def short_url
|
|
90
|
+
EngineRouter.new("decidim", default_url_options).short_link_url(id: identifier)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Generates the full long URL to the resource matching this short link.
|
|
94
|
+
#
|
|
95
|
+
# @return [String] The target full URL that the short link should link to.
|
|
96
|
+
def target_url
|
|
97
|
+
url_helpers.send("#{route_name}_url", **params)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
|
|
102
|
+
# Generates a new identifier for new records.
|
|
103
|
+
#
|
|
104
|
+
# @return [void]
|
|
105
|
+
def generate_identifier
|
|
106
|
+
return if identifier.present?
|
|
107
|
+
|
|
108
|
+
self.identifier = self.class.unique_identifier_within(organization)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Returns the default URL options for the organization. The participatory
|
|
112
|
+
# space and component related parameters are excluded from the
|
|
113
|
+
# default_url_options because these are also needed for the short URL
|
|
114
|
+
# generation.
|
|
115
|
+
#
|
|
116
|
+
# @return [Hash] A hash of the default URL options for the links.
|
|
117
|
+
def default_url_options
|
|
118
|
+
{ host: organization&.host }.compact
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Returns the options for the URL helper call against the routes proxy.
|
|
122
|
+
# The options include the mounted params for the target, such as
|
|
123
|
+
# participatory space slug and component ID, depending what the target is.
|
|
124
|
+
#
|
|
125
|
+
# @return [Hash] The mounted options for the target record that will be used
|
|
126
|
+
# to generate the final link.
|
|
127
|
+
def mounted_options
|
|
128
|
+
if target.is_a?(Decidim::Participable)
|
|
129
|
+
# The mounted_params method returns always e.g. participatory_space_slug
|
|
130
|
+
# assembly_slug, etc. But when we want to link to the space itself, we
|
|
131
|
+
# only need the `slug` parameter.
|
|
132
|
+
{ host: target.organization.host, slug: target.slug }
|
|
133
|
+
elsif target.respond_to?(:mounted_params)
|
|
134
|
+
target.mounted_params
|
|
135
|
+
elsif target.respond_to?(:component)
|
|
136
|
+
target.component.mounted_params.merge(id: target.id)
|
|
137
|
+
elsif target.respond_to?(:participatory_space)
|
|
138
|
+
target.participatory_space.mounted_params
|
|
139
|
+
elsif target.respond_to?(:slug)
|
|
140
|
+
# E.g. Decidim::StaticPage uses the slug as the `:id` parameter.
|
|
141
|
+
default_url_options.merge(id: target.slug)
|
|
142
|
+
elsif !target.is_a?(Decidim::Organization)
|
|
143
|
+
default_url_options.merge(id: target.id)
|
|
144
|
+
else
|
|
145
|
+
default_url_options
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Returns the routes helpers for the target engine.
|
|
150
|
+
#
|
|
151
|
+
# @return [Decidim::EngineRouter] An instance of the engine router that will
|
|
152
|
+
# be used to generate the links to the correct context.
|
|
153
|
+
def url_helpers
|
|
154
|
+
@url_helpers ||= EngineRouter.new(mounted_engine_name, mounted_options)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# The OutOfCandidatesError is an error class that will be raised when the
|
|
158
|
+
# short link identifiers are running out and the short link cannot be
|
|
159
|
+
# generated.
|
|
160
|
+
class OutOfCandidatesError < StandardError; end
|
|
161
|
+
end
|
|
162
|
+
end
|
data/app/models/decidim/user.rb
CHANGED
|
@@ -5,15 +5,15 @@ require "devise/models/decidim_newsletterable"
|
|
|
5
5
|
require "valid_email2"
|
|
6
6
|
|
|
7
7
|
module Decidim
|
|
8
|
-
# A User is a
|
|
8
|
+
# A User is a participant that wants to join the platform to engage.
|
|
9
9
|
class User < UserBaseEntity
|
|
10
|
-
include Decidim::
|
|
10
|
+
include Decidim::DownloadYourData
|
|
11
11
|
include Decidim::Searchable
|
|
12
12
|
include Decidim::ActsAsAuthor
|
|
13
13
|
include Decidim::UserReportable
|
|
14
14
|
include Decidim::Traceable
|
|
15
15
|
|
|
16
|
-
REGEXP_NICKNAME = /\A[\w\-]+\z
|
|
16
|
+
REGEXP_NICKNAME = /\A[\w\-]+\z/
|
|
17
17
|
|
|
18
18
|
class Roles
|
|
19
19
|
def self.all
|
|
@@ -34,6 +34,7 @@ module Decidim
|
|
|
34
34
|
has_many :user_groups, through: :memberships, class_name: "Decidim::UserGroup", foreign_key: :decidim_user_group_id
|
|
35
35
|
has_many :access_grants, class_name: "Doorkeeper::AccessGrant", foreign_key: :resource_owner_id, dependent: :destroy
|
|
36
36
|
has_many :access_tokens, class_name: "Doorkeeper::AccessToken", foreign_key: :resource_owner_id, dependent: :destroy
|
|
37
|
+
has_many :reminders, foreign_key: "decidim_user_id", class_name: "Decidim::Reminder", dependent: :destroy
|
|
37
38
|
|
|
38
39
|
has_one :blocking, class_name: "Decidim::UserBlock", foreign_key: :id, primary_key: :block_id, dependent: :destroy
|
|
39
40
|
|
|
@@ -50,7 +51,7 @@ module Decidim
|
|
|
50
51
|
|
|
51
52
|
validate :all_roles_are_valid
|
|
52
53
|
|
|
53
|
-
has_one_attached :
|
|
54
|
+
has_one_attached :download_your_data_file
|
|
54
55
|
|
|
55
56
|
scope :not_deleted, -> { where(deleted_at: nil) }
|
|
56
57
|
|
|
@@ -81,12 +82,14 @@ module Decidim
|
|
|
81
82
|
# scope_id: :decidim_scope_id,
|
|
82
83
|
organization_id: :decidim_organization_id,
|
|
83
84
|
A: :name,
|
|
85
|
+
B: :nickname,
|
|
84
86
|
datetime: :created_at
|
|
85
87
|
},
|
|
86
88
|
index_on_create: ->(user) { !(user.deleted? || user.blocked?) },
|
|
87
89
|
index_on_update: ->(user) { !(user.deleted? || user.blocked?) })
|
|
88
90
|
|
|
89
91
|
before_save :ensure_encrypted_password
|
|
92
|
+
before_save :save_password_change
|
|
90
93
|
|
|
91
94
|
def user_invited?
|
|
92
95
|
invitation_token_changed? && invitation_accepted_at_changed?
|
|
@@ -186,10 +189,10 @@ module Decidim
|
|
|
186
189
|
end
|
|
187
190
|
|
|
188
191
|
def self.export_serializer
|
|
189
|
-
Decidim::
|
|
192
|
+
Decidim::DownloadYourDataSerializers::DownloadYourDataUserSerializer
|
|
190
193
|
end
|
|
191
194
|
|
|
192
|
-
def self.
|
|
195
|
+
def self.download_your_data_images(user)
|
|
193
196
|
user_collection(user).map(&:avatar)
|
|
194
197
|
end
|
|
195
198
|
|
|
@@ -255,6 +258,18 @@ module Decidim
|
|
|
255
258
|
Arel.sql(%{("decidim_users"."last_sign_in_at")::text})
|
|
256
259
|
end
|
|
257
260
|
|
|
261
|
+
def notifications_subscriptions
|
|
262
|
+
notification_settings.fetch("subscriptions", {})
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def needs_password_update?
|
|
266
|
+
return false unless admin?
|
|
267
|
+
return false unless Decidim.config.admin_password_strong
|
|
268
|
+
return true if password_updated_at.blank?
|
|
269
|
+
|
|
270
|
+
password_updated_at < Decidim.config.admin_password_expiration_days.days.ago
|
|
271
|
+
end
|
|
272
|
+
|
|
258
273
|
protected
|
|
259
274
|
|
|
260
275
|
# Overrides devise email required validation.
|
|
@@ -302,5 +317,18 @@ module Decidim
|
|
|
302
317
|
def ensure_encrypted_password
|
|
303
318
|
restore_encrypted_password! if will_save_change_to_encrypted_password? && encrypted_password.blank?
|
|
304
319
|
end
|
|
320
|
+
|
|
321
|
+
def save_password_change
|
|
322
|
+
return unless persisted?
|
|
323
|
+
return unless encrypted_password_changed?
|
|
324
|
+
return unless admin?
|
|
325
|
+
return unless Decidim.config.admin_password_strong
|
|
326
|
+
|
|
327
|
+
# We don't want to run validations here because that could lead to an endless validation loop.
|
|
328
|
+
# rubocop:disable Rails/SkipsModelValidations
|
|
329
|
+
update_column(:password_updated_at, Time.current)
|
|
330
|
+
update_column(:previous_passwords, [encrypted_password_was, *previous_passwords].first(Decidim.config.admin_password_repetition_times))
|
|
331
|
+
# rubocop:enable Rails/SkipsModelValidations
|
|
332
|
+
end
|
|
305
333
|
end
|
|
306
334
|
end
|
|
@@ -18,7 +18,7 @@ module Decidim
|
|
|
18
18
|
has_many :following_follows, foreign_key: "decidim_user_id", class_name: "Decidim::Follow", dependent: :destroy
|
|
19
19
|
|
|
20
20
|
# Regex for name & nickname format validations
|
|
21
|
-
REGEXP_NAME = /\A(?!.*[<>?%&\^*#@()\[\]=+:;"{}\\|])
|
|
21
|
+
REGEXP_NAME = /\A(?!.*[<>?%&\^*#@()\[\]=+:;"{}\\|])/
|
|
22
22
|
|
|
23
23
|
has_one_attached :avatar
|
|
24
24
|
validates_avatar :avatar, uploader: Decidim::AvatarUploader
|
|
@@ -4,10 +4,10 @@ require "devise/models/decidim_validatable"
|
|
|
4
4
|
require "valid_email2"
|
|
5
5
|
|
|
6
6
|
module Decidim
|
|
7
|
-
# A UserGroup is an organization of
|
|
7
|
+
# A UserGroup is an organization of participants
|
|
8
8
|
class UserGroup < UserBaseEntity
|
|
9
9
|
include Decidim::Traceable
|
|
10
|
-
include Decidim::
|
|
10
|
+
include Decidim::DownloadYourData
|
|
11
11
|
include Decidim::ActsAsAuthor
|
|
12
12
|
include Decidim::UserReportable
|
|
13
13
|
include Decidim::Searchable
|
|
@@ -87,7 +87,7 @@ module Decidim
|
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
def self.export_serializer
|
|
90
|
-
Decidim::
|
|
90
|
+
Decidim::DownloadYourDataSerializers::DownloadYourDataUserGroupSerializer
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
def document_number
|
|
@@ -12,8 +12,6 @@ module Decidim
|
|
|
12
12
|
scope :unblocked, -> { joins(:user).where(decidim_users: { blocked: false }) }
|
|
13
13
|
|
|
14
14
|
delegate :organization, to: :user
|
|
15
|
-
scope :blocked, -> { joins(:user).where(decidim_users: { blocked: true }) }
|
|
16
|
-
scope :unblocked, -> { joins(:user).where(decidim_users: { blocked: false }) }
|
|
17
15
|
|
|
18
16
|
def self.log_presenter_class_for(_log)
|
|
19
17
|
Decidim::AdminLog::UserModerationPresenter
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Decidim
|
|
4
4
|
class UserReport < ApplicationRecord
|
|
5
|
-
include Decidim::
|
|
5
|
+
include Decidim::DownloadYourData
|
|
6
6
|
|
|
7
7
|
REASONS = %w(spam offensive does_not_belong).freeze
|
|
8
8
|
|
|
@@ -16,7 +16,7 @@ module Decidim
|
|
|
16
16
|
|
|
17
17
|
def self.export_serializer
|
|
18
18
|
raise NotImplementedError
|
|
19
|
-
# Decidim::
|
|
19
|
+
# Decidim::DownloadYourDataSerializers::DownloadYourDataReportSerializer
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
private
|
|
@@ -14,7 +14,6 @@ import "src/decidim/vendor/foundation-datepicker"
|
|
|
14
14
|
import "src/decidim/foundation_datepicker_locales"
|
|
15
15
|
import "src/decidim/vendor/modernizr"
|
|
16
16
|
import "src/decidim/vendor/social-share-button"
|
|
17
|
-
import "social-share-button"
|
|
18
17
|
|
|
19
18
|
import "src/decidim/input_tags"
|
|
20
19
|
import "src/decidim/input_hashtags"
|
|
@@ -57,7 +56,9 @@ import "src/decidim/start_conversation_dialog"
|
|
|
57
56
|
import "src/decidim/notifications"
|
|
58
57
|
import "src/decidim/identity_selector_dialog"
|
|
59
58
|
import "src/decidim/gallery"
|
|
59
|
+
import "src/decidim/direct_uploads/upload_field"
|
|
60
60
|
import "src/decidim/back_to_list"
|
|
61
|
+
import "src/decidim/cookie_consent/cookie_consent"
|
|
61
62
|
|
|
62
63
|
// CSS
|
|
63
64
|
import "entrypoints/decidim_core.scss"
|
|
@@ -70,4 +71,3 @@ require.context("../images", true)
|
|
|
70
71
|
|
|
71
72
|
// This needs to be loaded after confirm dialog to bind properly
|
|
72
73
|
Rails.start()
|
|
73
|
-
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "src/decidim/sw"
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import AutoCompleteJS from "@tarekraafat/autocomplete.js";
|
|
2
|
+
|
|
3
|
+
export default class AutoComplete {
|
|
4
|
+
constructor(el, options = {}) {
|
|
5
|
+
this.element = el;
|
|
6
|
+
this.stickySelectedSpan = null;
|
|
7
|
+
this.clearStickySelectionSpan = null;
|
|
8
|
+
this.stickyHiddenInput = null;
|
|
9
|
+
this.promptDiv = null;
|
|
10
|
+
const thresholdTemp = options.threshold || 2;
|
|
11
|
+
this.options = Object.assign({
|
|
12
|
+
// Defines name of the hidden input (e.g. assembly_member[user_id])
|
|
13
|
+
name: null,
|
|
14
|
+
// Placeholder of the visible input field
|
|
15
|
+
placeholder: "",
|
|
16
|
+
// Defines what happens after user has selected value from suggestions
|
|
17
|
+
// sticky - Allows selecting a single value and not editing the value after selected (e.g. as the admin autocomplete fields)
|
|
18
|
+
// single - Allows selecting a single value and editing the selected text after the selection (e.g. geocoding field)
|
|
19
|
+
// multi - Allows selecting multiple values
|
|
20
|
+
// null (default) - Disable selection event handling in this class
|
|
21
|
+
mode: null,
|
|
22
|
+
// Defines if we show input help (e.g. "Type at least three characters to search") or not.
|
|
23
|
+
searchPrompt: false,
|
|
24
|
+
// Defines search prompt message, only shown if showPrompt is enabled!
|
|
25
|
+
searchPromptText: `Type at least ${thresholdTemp} characters to search`,
|
|
26
|
+
// Defines items that are selected already when page is loaded before user selects them. (e.g. when form submit fails)
|
|
27
|
+
selected: null,
|
|
28
|
+
// Defines how many characters input has to have before we start searching
|
|
29
|
+
threshold: thresholdTemp,
|
|
30
|
+
// Defines how many results to show in the autocomplete selection list
|
|
31
|
+
// by maximum.
|
|
32
|
+
maxResults: 10,
|
|
33
|
+
// Defines the data keys against which to match the user input when
|
|
34
|
+
// searching through the results. For example, when the following
|
|
35
|
+
// data is returned by the API:
|
|
36
|
+
// { id: 123, name: "John", nickname: "john", __typename: "User" }
|
|
37
|
+
//
|
|
38
|
+
// You can define the data keys array as ["name", "nickname"] in
|
|
39
|
+
// which case the results shown to user would be only those that
|
|
40
|
+
// have matching text in these defined fields.
|
|
41
|
+
dataMatchKeys: null,
|
|
42
|
+
// The data source is a method that gets the callback parameter as
|
|
43
|
+
// its first argument which should be called with the results array
|
|
44
|
+
// once they are returned by the API.
|
|
45
|
+
// For example:
|
|
46
|
+
// (query, callback) => {
|
|
47
|
+
// (async () => {
|
|
48
|
+
// const results = await callAjax(`/api/url?query=${query}`);
|
|
49
|
+
// callback(results);
|
|
50
|
+
// })();
|
|
51
|
+
// }
|
|
52
|
+
//
|
|
53
|
+
// Signature: (callback: Function)
|
|
54
|
+
dataSource: () => [],
|
|
55
|
+
// Filters the data list returned by the data source before it is shown
|
|
56
|
+
// to the user. Can be used e.g. to hide already selected values from
|
|
57
|
+
// the list.
|
|
58
|
+
dataFilter: null,
|
|
59
|
+
// Delay in milliseconds how long to wait after user action before
|
|
60
|
+
// doing a backend request.
|
|
61
|
+
delay: 200,
|
|
62
|
+
// Allows modifying the suggested items before they are displayed in the list
|
|
63
|
+
// Signature: (element: HTMLElement, value: Object)
|
|
64
|
+
modifyResult: null
|
|
65
|
+
}, options);
|
|
66
|
+
|
|
67
|
+
this.autocomplete = new AutoCompleteJS({
|
|
68
|
+
selector: () => this.element,
|
|
69
|
+
placeHolder: options.placeholder,
|
|
70
|
+
// Delay (milliseconds) before autocomplete engine starts. It's preventing many queries when user is typing fast.
|
|
71
|
+
debounce: 200,
|
|
72
|
+
threshold: this.options.threshold,
|
|
73
|
+
data: {
|
|
74
|
+
keys: this.options.dataMatchKeys,
|
|
75
|
+
src: async (query) => {
|
|
76
|
+
const fetchResults = () => {
|
|
77
|
+
return new Promise((resolve) => {
|
|
78
|
+
this.options.dataSource(query, resolve);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
return await fetchResults();
|
|
84
|
+
} catch (error) {
|
|
85
|
+
return error;
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
filter: (list) => {
|
|
89
|
+
if (this.options.dataFilter) {
|
|
90
|
+
return this.options.dataFilter(list);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return list;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
resultsList: {
|
|
97
|
+
maxResults: this.options.maxResults
|
|
98
|
+
},
|
|
99
|
+
resultItem: {
|
|
100
|
+
element: (item, data) => {
|
|
101
|
+
if (!this.options.modifyResult) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.options.modifyResult(item, data.value);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
events: {
|
|
109
|
+
input: {
|
|
110
|
+
blur: () => {
|
|
111
|
+
this.promptDiv.style.display = "none";
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
this.acWrapper = this.element.closest(".autoComplete_wrapper");
|
|
118
|
+
this.element.ac = this.autocomplete;
|
|
119
|
+
|
|
120
|
+
// Stop input field from bubbling open and close events to parent elements,
|
|
121
|
+
// because foundation closes modal from these events.
|
|
122
|
+
const stopPropagation = (event) => {
|
|
123
|
+
event.stopPropagation();
|
|
124
|
+
}
|
|
125
|
+
this.element.addEventListener("close", stopPropagation);
|
|
126
|
+
this.element.addEventListener("open", stopPropagation);
|
|
127
|
+
|
|
128
|
+
this.createPromptDiv();
|
|
129
|
+
|
|
130
|
+
switch (this.options.mode) {
|
|
131
|
+
case "sticky":
|
|
132
|
+
this.createStickySelect(this.options.name);
|
|
133
|
+
break;
|
|
134
|
+
case "multi":
|
|
135
|
+
this.createMultiSelect(this.options.name);
|
|
136
|
+
break;
|
|
137
|
+
default:
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
setInput(value) {
|
|
142
|
+
this.autocomplete.input.value = value;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
handleEvent(event) {
|
|
146
|
+
switch (this.options.mode) {
|
|
147
|
+
case "single":
|
|
148
|
+
this.setInput(event.detail.selection.value[event.detail.selection.key]);
|
|
149
|
+
break;
|
|
150
|
+
case "sticky":
|
|
151
|
+
this.handleStickyEvents(event);
|
|
152
|
+
break;
|
|
153
|
+
case "multi":
|
|
154
|
+
this.handleMultiEvents(event);
|
|
155
|
+
break;
|
|
156
|
+
default:
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
handleMultiEvents(event) {
|
|
161
|
+
switch (event.type) {
|
|
162
|
+
case "selection":
|
|
163
|
+
this.addMultiSelectItem(event.detail.selection);
|
|
164
|
+
break;
|
|
165
|
+
default:
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
handleStickyEvents(event) {
|
|
170
|
+
switch (event.type) {
|
|
171
|
+
case "selection":
|
|
172
|
+
this.addStickySelectItem(event.detail.selection);
|
|
173
|
+
break;
|
|
174
|
+
case "click":
|
|
175
|
+
if (event.target === this.clearStickySelectionSpan) {
|
|
176
|
+
this.removeStickySelection();
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
case "keyup":
|
|
180
|
+
if (this.stickyHiddenInput.value !== "" && event.target === this.element && (["Escape", "Backspace", "Delete"].includes(event.key) || (/^[a-z0-9]$/i).test(event.key))) {
|
|
181
|
+
this.removeStickySelection();
|
|
182
|
+
} else if (this.options.searchPrompt) {
|
|
183
|
+
if (this.stickyHiddenInput.value === "" && this.element.value.length < this.options.threshold) {
|
|
184
|
+
this.promptDiv.style.display = "block";
|
|
185
|
+
} else {
|
|
186
|
+
this.promptDiv.style.display = "none";
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
default:
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
createHiddenInput(value) {
|
|
195
|
+
const hiddenInput = document.createElement("input");
|
|
196
|
+
hiddenInput.name = this.options.name;
|
|
197
|
+
hiddenInput.type = "hidden";
|
|
198
|
+
if (value) {
|
|
199
|
+
hiddenInput.value = value;
|
|
200
|
+
}
|
|
201
|
+
this.acWrapper.prepend(hiddenInput);
|
|
202
|
+
return hiddenInput;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
removeStickySelection() {
|
|
206
|
+
this.stickyHiddenInput.value = "";
|
|
207
|
+
this.element.placeholder = this.options.placeholder;
|
|
208
|
+
this.clearStickySelectionSpan.style.display = "none";
|
|
209
|
+
this.stickySelectedSpan.style.display = "none";
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
addStickySelectItem(selection) {
|
|
213
|
+
this.stickyHiddenInput.value = selection.value.value;
|
|
214
|
+
this.element.placeholder = "";
|
|
215
|
+
this.stickySelectedSpan.innerHTML = selection.value[selection.key];
|
|
216
|
+
this.stickySelectedSpan.style.display = "block";
|
|
217
|
+
this.clearStickySelectionSpan.style.display = "block";
|
|
218
|
+
this.setInput("");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
addMultiSelectItem(selection) {
|
|
222
|
+
this.setInput("");
|
|
223
|
+
const chosen = document.createElement("span");
|
|
224
|
+
chosen.classList.add("label", "primary", "autocomplete__selected-item", "multi");
|
|
225
|
+
chosen.innerHTML = selection.value[selection.key];
|
|
226
|
+
const clearSelection = document.createElement("span");
|
|
227
|
+
clearSelection.classList.add("clear-multi-selection");
|
|
228
|
+
clearSelection.innerHTML = "×";
|
|
229
|
+
clearSelection.setAttribute("data-remove", selection.value.value);
|
|
230
|
+
clearSelection.addEventListener("click", (evt) => {
|
|
231
|
+
const hiddenInput = this.acWrapper.querySelector(`input[type='hidden'][value='${selection.value.value}']`);
|
|
232
|
+
if (hiddenInput) {
|
|
233
|
+
hiddenInput.remove();
|
|
234
|
+
evt.target.parentElement.remove();
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
chosen.appendChild(clearSelection);
|
|
238
|
+
|
|
239
|
+
const multiSelectWrapper = this.acWrapper.querySelector(".multiselect");
|
|
240
|
+
const inputContainer = multiSelectWrapper.querySelector("span.input-container");
|
|
241
|
+
multiSelectWrapper.insertBefore(chosen, inputContainer);
|
|
242
|
+
this.createHiddenInput(selection.value.value);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
createStickySelect() {
|
|
246
|
+
this.stickySelectedSpan = document.createElement("span");
|
|
247
|
+
this.stickySelectedSpan.classList.add("autocomplete__selected-item", "sticky");
|
|
248
|
+
this.stickySelectedSpan.style.display = "none";
|
|
249
|
+
this.stickySelectedSpan.addEventListener("click", () => this.element.focus());
|
|
250
|
+
this.stickyHiddenInput = this.createHiddenInput();
|
|
251
|
+
|
|
252
|
+
this.clearStickySelectionSpan = document.createElement("span");
|
|
253
|
+
this.clearStickySelectionSpan.className = "clear-sticky-selection";
|
|
254
|
+
this.clearStickySelectionSpan.innerHTML = "×";
|
|
255
|
+
this.clearStickySelectionSpan.style.display = "none";
|
|
256
|
+
this.clearStickySelectionSpan.addEventListener("click", this);
|
|
257
|
+
|
|
258
|
+
this.element.addEventListener("selection", this);
|
|
259
|
+
this.element.addEventListener("keyup", this);
|
|
260
|
+
|
|
261
|
+
this.acWrapper.insertBefore(this.clearStickySelectionSpan, this.element);
|
|
262
|
+
this.acWrapper.insertBefore(this.stickySelectedSpan, this.element);
|
|
263
|
+
if (this.options.selected) {
|
|
264
|
+
this.addStickySelectItem(this.options.selected);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
createMultiSelect() {
|
|
269
|
+
const multiSelectWrapper = document.createElement("div");
|
|
270
|
+
multiSelectWrapper.classList.add("multiselect");
|
|
271
|
+
|
|
272
|
+
const inputContainer = document.createElement("span");
|
|
273
|
+
inputContainer.classList.add("input-container");
|
|
274
|
+
|
|
275
|
+
multiSelectWrapper.appendChild(inputContainer);
|
|
276
|
+
this.acWrapper.prepend(multiSelectWrapper);
|
|
277
|
+
inputContainer.appendChild(this.element);
|
|
278
|
+
|
|
279
|
+
this.element.addEventListener("selection", this);
|
|
280
|
+
multiSelectWrapper.addEventListener("click", () => {
|
|
281
|
+
this.element.focus();
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
if (this.options.selected) {
|
|
285
|
+
this.options.selected.forEach((selection) => {
|
|
286
|
+
this.addMultiSelectItem(selection);
|
|
287
|
+
})
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
createPromptDiv() {
|
|
292
|
+
this.promptDiv = document.createElement("div");
|
|
293
|
+
this.promptDiv.classList.add("search-prompt");
|
|
294
|
+
this.promptDiv.style.display = "none";
|
|
295
|
+
this.promptDiv.innerHTML = this.options.searchPromptText;
|
|
296
|
+
this.acWrapper.appendChild(this.promptDiv);
|
|
297
|
+
}
|
|
298
|
+
}
|