decidim-core 0.29.2 → 0.30.0.rc2
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/app/cells/decidim/amendable/amend_button_card/show.erb +6 -4
- data/app/cells/decidim/amendable/amend_button_card_cell.rb +8 -0
- data/app/cells/decidim/amendable/amendments/show.erb +1 -1
- data/app/cells/decidim/amendable/promote_button_card/show.erb +2 -0
- data/app/cells/decidim/author_cell.rb +1 -1
- data/app/cells/decidim/card_l/extra_data.erb +1 -0
- data/app/cells/decidim/card_metadata_cell.rb +9 -16
- data/app/cells/decidim/comments_button_cell.rb +14 -2
- data/app/cells/decidim/content_blocks/highlighted_elements_cell.rb +2 -0
- data/app/cells/decidim/content_blocks/highlighted_elements_with_cell_for_list_cell.rb +1 -1
- data/app/cells/decidim/endorsement_block/show.erb +0 -1
- data/app/cells/decidim/endorsement_block_cell.rb +6 -0
- data/app/cells/decidim/endorsement_buttons/button_content.erb +1 -1
- data/app/cells/decidim/endorsement_buttons/select_identity_button.erb +1 -1
- data/app/cells/decidim/endorsement_buttons/show.erb +7 -7
- data/app/cells/decidim/endorsement_buttons/verification_modal.erb +4 -2
- data/app/cells/decidim/endorsers_list/empty.erb +3 -0
- data/app/cells/decidim/endorsers_list/full.erb +17 -5
- data/app/cells/decidim/endorsers_list/show.erb +19 -10
- data/app/cells/decidim/endorsers_list_cell.rb +19 -6
- data/app/cells/decidim/follow_button/show.erb +1 -2
- data/app/cells/decidim/follow_button_cell.rb +5 -0
- data/app/cells/decidim/map/show.erb +3 -0
- data/app/cells/decidim/map/template.erb +14 -0
- data/app/cells/decidim/map_cell.rb +39 -0
- data/app/cells/decidim/notification_actions/buttons_cell.rb +1 -1
- data/app/cells/decidim/onboarding_action_message/show.erb +15 -0
- data/app/cells/decidim/onboarding_action_message_cell.rb +81 -0
- data/app/cells/decidim/participatory_space_private_user/show.erb +23 -0
- data/app/cells/decidim/participatory_space_private_user_cell.rb +21 -0
- data/app/cells/decidim/progress_bar/show.erb +2 -2
- data/app/cells/decidim/report_button_cell.rb +1 -0
- data/app/cells/decidim/resource_history/show.erb +20 -0
- data/app/cells/decidim/resource_history_cell.rb +66 -0
- data/app/cells/decidim/share_button_cell.rb +0 -4
- data/app/cells/decidim/share_widget/modal.erb +26 -0
- data/app/cells/decidim/share_widget/show.erb +2 -0
- data/app/cells/decidim/share_widget_cell.rb +20 -0
- data/app/cells/decidim/tags/show.erb +7 -4
- data/app/cells/decidim/tags_cell.rb +11 -72
- data/app/commands/decidim/amendable/create_draft.rb +2 -2
- data/app/commands/decidim/create_ephemeral_user.rb +52 -0
- data/app/commands/decidim/create_omniauth_registration.rb +13 -3
- data/app/commands/decidim/create_report.rb +1 -5
- data/app/commands/decidim/create_user_group.rb +6 -2
- data/app/commands/decidim/destroy_ephemeral_user.rb +47 -0
- data/app/commands/decidim/update_account.rb +11 -3
- data/app/commands/decidim/update_notifications_settings.rb +1 -0
- data/app/commands/decidim/update_resources_taxonomies.rb +67 -0
- data/app/commands/decidim/update_user_group.rb +7 -1
- data/app/constraints/decidim/current_component.rb +1 -1
- data/app/controllers/concerns/decidim/ajax_permission_handler.rb +21 -0
- data/app/controllers/concerns/decidim/devise_authentication_methods.rb +3 -6
- data/app/controllers/concerns/decidim/devise_controllers.rb +2 -0
- data/app/controllers/concerns/decidim/disable_redirection_to_external_host.rb +1 -1
- data/app/controllers/concerns/decidim/ephemeral_session_checker.rb +87 -0
- data/app/controllers/concerns/decidim/filter_resource.rb +4 -2
- data/app/controllers/concerns/decidim/has_members_page.rb +25 -0
- data/app/controllers/concerns/decidim/headers/browser_feature_permissions.rb +50 -0
- data/app/controllers/concerns/decidim/locale_switcher.rb +2 -2
- data/app/controllers/concerns/decidim/needs_password_change.rb +0 -1
- data/app/controllers/concerns/decidim/needs_permission.rb +2 -1
- data/app/controllers/concerns/decidim/needs_tos_accepted.rb +4 -5
- data/app/controllers/concerns/decidim/onboarding_action_methods.rb +52 -0
- data/app/controllers/decidim/application_controller.rb +10 -0
- data/app/controllers/decidim/authorization_modals_controller.rb +8 -2
- data/app/controllers/decidim/components/base_controller.rb +3 -7
- data/app/controllers/decidim/devise/confirmations_controller.rb +4 -0
- data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +8 -1
- data/app/controllers/decidim/devise/registrations_controller.rb +1 -1
- data/app/controllers/decidim/devise/sessions_controller.rb +2 -0
- data/app/controllers/decidim/download_your_data_controller.rb +33 -2
- data/app/controllers/decidim/editor_images_controller.rb +1 -11
- data/app/controllers/decidim/follows_controller.rb +1 -1
- data/app/controllers/decidim/geolocation_controller.rb +19 -0
- data/app/controllers/decidim/homepage_controller.rb +0 -1
- data/app/controllers/decidim/open_data_controller.rb +33 -8
- data/app/controllers/decidim/user_conversations_controller.rb +1 -11
- data/app/events/decidim/soft_delete_resource_event.rb +15 -0
- data/app/forms/decidim/amendable/form.rb +4 -2
- data/app/forms/decidim/ephemeral_user_form.rb +22 -0
- data/app/forms/decidim/notifications_settings_form.rb +1 -0
- data/app/forms/decidim/omniauth_registration_form.rb +14 -1
- data/app/helpers/concerns/decidim/flash_helper_extensions.rb +17 -2
- data/app/helpers/decidim/action_authorization_helper.rb +75 -14
- data/app/helpers/decidim/amendments_helper.rb +0 -9
- data/app/helpers/decidim/application_helper.rb +6 -2
- data/app/helpers/decidim/breadcrumb_helper.rb +6 -0
- data/app/helpers/decidim/cache_helper.rb +1 -1
- data/app/helpers/decidim/check_boxes_tree_helper.rb +25 -53
- data/app/helpers/decidim/decidim_form_helper.rb +0 -44
- data/app/helpers/decidim/endorsable_helper.rb +0 -10
- data/app/helpers/decidim/layout_helper.rb +6 -0
- data/app/helpers/decidim/messaging/conversation_helper.rb +2 -3
- data/app/helpers/decidim/meta_tags_helper.rb +32 -23
- data/app/helpers/decidim/modal_helper.rb +23 -0
- data/app/helpers/decidim/omniauth_helper.rb +5 -5
- data/app/helpers/decidim/onboarding_action_helper.rb +13 -0
- data/app/helpers/decidim/orders_helper.rb +2 -1
- data/app/helpers/decidim/participatory_space_helpers.rb +1 -1
- data/app/helpers/decidim/passwords_helper.rb +2 -2
- data/app/helpers/decidim/taxonomies_helper.rb +40 -0
- data/app/jobs/decidim/download_your_data_export_job.rb +2 -19
- data/app/jobs/decidim/event_publisher_job.rb +18 -9
- data/app/jobs/decidim/export_job.rb +5 -1
- data/app/jobs/decidim/export_participatory_space_job.rb +4 -1
- data/app/jobs/decidim/hide_child_resources_job.rb +24 -0
- data/app/jobs/decidim/open_data_job.rb +4 -4
- data/app/mailers/decidim/export_mailer.rb +7 -12
- data/app/models/decidim/action_log.rb +11 -0
- data/app/models/decidim/category.rb +4 -0
- data/app/models/decidim/component.rb +25 -3
- data/app/models/decidim/metric.rb +2 -1
- data/app/models/decidim/moderation.rb +16 -0
- data/app/models/decidim/newsletter.rb +12 -8
- data/app/models/decidim/organization.rb +7 -3
- data/app/models/decidim/participatory_space_private_user.rb +20 -0
- data/app/models/decidim/private_export.rb +24 -0
- data/app/models/decidim/push_notification_message.rb +1 -1
- data/app/models/decidim/report.rb +1 -1
- data/app/models/decidim/scope.rb +4 -0
- data/app/models/decidim/share_token.rb +36 -10
- data/app/models/decidim/taxonomization.rb +23 -0
- data/app/models/decidim/taxonomy.rb +139 -0
- data/app/models/decidim/taxonomy_filter.rb +130 -0
- data/app/models/decidim/taxonomy_filter_item.rb +33 -0
- data/app/models/decidim/user.rb +9 -23
- data/app/models/decidim/user_base_entity.rb +12 -0
- data/app/models/decidim/user_moderation.rb +9 -0
- data/app/models/decidim/user_report.rb +4 -0
- data/app/packs/entrypoints/decidim_core.js +1 -0
- data/app/packs/entrypoints/decidim_geocoding.js +2 -0
- data/app/packs/images/decidim/brands/facebook.svg +10 -0
- data/app/packs/images/decidim/brands/google.svg +7 -1
- data/app/packs/images/decidim/brands/twitter-x.svg +3 -0
- data/app/packs/src/decidim/check_boxes_tree.js +0 -1
- data/app/packs/src/decidim/clipboard.js +18 -9
- data/app/packs/src/decidim/confirm.js +79 -59
- data/app/packs/src/decidim/decidim_application.js +1 -0
- data/app/packs/src/decidim/form_remote.js +1 -1
- data/app/packs/src/decidim/geocoding/reverse_geocoding.js +60 -0
- data/app/packs/src/decidim/impersonation.js +1 -1
- data/app/packs/src/decidim/index.js +11 -1
- data/app/packs/src/decidim/map/provider/here.js +1 -1
- data/app/packs/src/decidim/onboarding_pending_action.js +24 -0
- data/app/packs/src/decidim/session_timeouter.js +1 -1
- data/app/packs/src/decidim/sticky_footer.js +29 -0
- data/app/packs/src/decidim/sticky_header.js +6 -31
- data/app/packs/src/decidim/user_registrations.js +13 -0
- data/app/packs/src/decidim/utilities/dom.js +148 -0
- data/app/packs/stylesheets/decidim/_accordion.scss +30 -0
- data/app/packs/stylesheets/decidim/_buttons.scss +19 -0
- data/app/packs/stylesheets/decidim/_dropdown.scss +1 -1
- data/app/packs/stylesheets/decidim/_endorsers_list.scss +26 -20
- data/app/packs/stylesheets/decidim/_forms.scss +2 -2
- data/app/packs/stylesheets/decidim/_hashtags.scss +5 -0
- data/app/packs/stylesheets/decidim/_header.scss +5 -3
- data/app/packs/stylesheets/decidim/_layout.scss +32 -2
- data/app/packs/stylesheets/decidim/_login.scss +53 -6
- data/app/packs/stylesheets/decidim/_modal.scss +42 -0
- data/app/packs/stylesheets/decidim/_modal_tos_refuse.scss +4 -0
- data/app/packs/stylesheets/decidim/_participatory_spaces.scss +46 -0
- data/app/packs/stylesheets/decidim/_profile.scss +1 -1
- data/app/packs/stylesheets/decidim/_success_image.scss +64 -0
- data/app/packs/stylesheets/decidim/_tribute.scss +36 -0
- data/app/packs/stylesheets/decidim/application.scss +2 -0
- data/app/packs/stylesheets/decidim/geocoding_addons.scss +5 -0
- data/app/packs/stylesheets/decidim/map.scss +7 -10
- data/app/packs/stylesheets/decidim/resource_history.scss +31 -0
- data/app/permissions/decidim/permissions.rb +8 -2
- data/app/presenters/decidim/admin_log/base_user_presenter.rb +67 -0
- data/app/presenters/decidim/admin_log/component_presenter.rb +32 -3
- data/app/presenters/decidim/admin_log/moderation_presenter.rb +30 -3
- data/app/presenters/decidim/admin_log/share_token_presenter.rb +39 -0
- data/app/presenters/decidim/admin_log/taxonomy_filter_presenter.rb +57 -0
- data/app/presenters/decidim/admin_log/taxonomy_presenter.rb +48 -0
- data/app/presenters/decidim/admin_log/user_group_presenter.rb +6 -6
- data/app/presenters/decidim/admin_log/user_presenter.rb +4 -18
- data/app/presenters/decidim/log/value_types/date_presenter.rb +1 -0
- data/app/presenters/decidim/log/value_types/taxonomy_presenter.rb +29 -0
- data/app/presenters/decidim/participatory_space_private_user_presenter.rb +50 -0
- data/app/presenters/decidim/taxonomy_filter_presenter.rb +19 -0
- data/app/presenters/decidim/taxonomy_presenter.rb +14 -0
- data/app/queries/decidim/metrics/blocked_users_metric_manage.rb +2 -2
- data/app/queries/decidim/metrics/users_metric_manage.rb +2 -2
- data/app/queries/decidim/public_activities.rb +1 -12
- data/app/queries/decidim/stats_users_count.rb +2 -2
- data/app/resolvers/decidim/meta_image_url_resolver.rb +128 -0
- data/app/serializers/decidim/exporters/open_data_blocked_user_serializer.rb +25 -0
- data/app/serializers/decidim/exporters/open_data_metric_serializer.rb +22 -0
- data/app/serializers/decidim/exporters/open_data_moderation_serializer.rb +30 -0
- data/app/serializers/decidim/exporters/open_data_taxonomy_serializer.rb +30 -0
- data/app/serializers/decidim/exporters/open_data_user_group_serializer.rb +38 -0
- data/app/serializers/decidim/exporters/open_data_user_serializer.rb +39 -0
- data/app/serializers/decidim/exporters/participatory_space_serializer.rb +104 -0
- data/app/serializers/decidim/exporters/serializer.rb +25 -0
- data/app/serializers/decidim/schema_org_breadcrumb_list_serializer.rb +52 -0
- data/app/services/decidim/action_authorizer.rb +32 -3
- data/app/services/decidim/base_diff_renderer.rb +1 -1
- data/app/services/decidim/download_your_data_exporter.rb +58 -24
- data/app/services/decidim/onboarding_manager.rb +272 -0
- data/app/services/decidim/open_data_exporter.rb +139 -13
- data/app/services/decidim/traceability.rb +13 -0
- data/app/uploaders/decidim/application_uploader.rb +1 -1
- data/app/validators/etiquette_validator.rb +9 -2
- data/app/validators/passthru_validator.rb +1 -1
- data/app/validators/translated_etiquette_validator.rb +32 -0
- data/app/views/decidim/account/_password_fields.html.erb +2 -2
- data/app/views/decidim/application/_accordion_section.html.erb +14 -0
- data/app/views/decidim/application/_collection.html.erb +30 -18
- data/app/views/decidim/devise/omniauth_registrations/new.html.erb +5 -1
- data/app/views/decidim/devise/omniauth_registrations/new_tos_fields.html.erb +29 -0
- data/app/views/decidim/devise/registrations/new.html.erb +10 -22
- data/app/views/decidim/devise/sessions/new.html.erb +24 -29
- data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +2 -4
- data/app/views/decidim/devise/shared/_tos_fields.html.erb +16 -0
- data/app/views/decidim/download_your_data/_export.html.erb +15 -0
- data/app/views/decidim/download_your_data/show.html.erb +51 -5
- data/app/views/decidim/endorsements/update_buttons_and_counters.js.erb +16 -19
- data/app/views/decidim/export_mailer/download_your_data_export.html.erb +2 -2
- data/app/views/decidim/export_mailer/export.html.erb +5 -1
- data/app/views/decidim/notifications_settings/show.html.erb +22 -0
- data/app/views/decidim/open_data/_how_to_open_accordion_section.html.erb +15 -0
- data/app/views/decidim/open_data/index.html.erb +108 -0
- data/app/views/decidim/pages/show.html.erb +2 -1
- data/app/views/decidim/participatory_space_private_users/_participatory_space_private_user.html.erb +1 -0
- data/app/views/decidim/shared/_login_modal.html.erb +26 -20
- data/app/views/decidim/shared/_orders.html.erb +2 -2
- data/app/views/decidim/shared/_resource_actions.html.erb +21 -0
- data/app/views/decidim/shared/filters/_check_boxes_tree.html.erb +1 -2
- data/app/views/decidim/shared/filters/_collection.html.erb +1 -1
- data/app/views/decidim/shared/filters/_dropdown_label.html.erb +7 -4
- data/app/views/layouts/decidim/_application.html.erb +0 -1
- data/app/views/layouts/decidim/_js_configuration.html.erb +1 -0
- data/app/views/layouts/decidim/_logo.html.erb +1 -1
- data/app/views/layouts/decidim/_logo_mobile.html.erb +1 -1
- data/app/views/layouts/decidim/_meta_tags_config.html.erb +6 -11
- data/app/views/layouts/decidim/_schema_org_breadcrumb_list.html.erb +3 -0
- data/app/views/layouts/decidim/_wrapper.html.erb +15 -9
- data/app/views/layouts/decidim/footer/_main_links.html.erb +1 -1
- data/app/views/layouts/decidim/header/_close_ephemeral_session.html.erb +25 -0
- data/app/views/layouts/decidim/header/_main.html.erb +14 -10
- data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +2 -0
- data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
- data/config/assets.rb +2 -1
- data/config/locales/ar.yml +27 -59
- data/config/locales/bg.yml +3 -64
- data/config/locales/ca.yml +370 -61
- data/config/locales/cs.yml +371 -54
- data/config/locales/de.yml +365 -54
- data/config/locales/el.yml +1 -48
- data/config/locales/en.yml +363 -54
- data/config/locales/eo.yml +0 -2
- data/config/locales/es-MX.yml +363 -57
- data/config/locales/es-PY.yml +363 -57
- data/config/locales/es.yml +367 -58
- data/config/locales/eu.yml +373 -65
- data/config/locales/fi-plain.yml +365 -57
- data/config/locales/fi.yml +370 -59
- data/config/locales/fr-CA.yml +178 -54
- data/config/locales/fr.yml +179 -52
- data/config/locales/ga-IE.yml +0 -21
- data/config/locales/gl.yml +1 -34
- data/config/locales/hu.yml +1 -53
- data/config/locales/id-ID.yml +1 -34
- data/config/locales/is-IS.yml +0 -16
- data/config/locales/it.yml +5 -60
- data/config/locales/ja.yml +215 -56
- data/config/locales/lb.yml +1 -52
- data/config/locales/lt.yml +1 -59
- data/config/locales/lv.yml +1 -40
- data/config/locales/nl.yml +1 -53
- data/config/locales/no.yml +2 -52
- data/config/locales/pl.yml +4 -66
- data/config/locales/pt-BR.yml +11 -52
- data/config/locales/pt.yml +2 -52
- data/config/locales/ro-RO.yml +219 -117
- data/config/locales/ru.yml +0 -20
- data/config/locales/sk.yml +1 -41
- data/config/locales/sv.yml +138 -59
- data/config/locales/tr-TR.yml +1 -50
- data/config/locales/uk.yml +0 -18
- data/config/locales/zh-CN.yml +1 -50
- data/config/locales/zh-TW.yml +1 -54
- data/config/routes.rb +4 -10
- data/db/migrate/20181025082245_add_timestamps_to_components.rb +2 -0
- data/db/migrate/20240628111905_add_visible_to_components.rb +7 -0
- data/db/migrate/20240704115429_create_decidim_taxonomies.rb +23 -0
- data/db/migrate/20240717093514_add_registered_only_to_decidim_share_tokens.rb +7 -0
- data/db/migrate/20240722215500_change_object_changes_on_versions.rb +39 -0
- data/db/migrate/20240806065417_create_decidim_taxonomy_filters.rb +23 -0
- data/db/migrate/20240822161348_add_deleted_at_to_decidim_components.rb +8 -0
- data/db/migrate/20240906162524_add_part_of_to_taxonomies.rb +26 -0
- data/db/migrate/20241001135825_add_role_to_participatory_space_private_users.rb +7 -0
- data/db/migrate/20241001140408_add_published_to_participatory_space_private_users.rb +7 -0
- data/db/migrate/20241022002600_create_private_exports.rb +18 -0
- data/db/migrate/20241028114430_add_component_counter_to_taxonomy_filters.rb +7 -0
- data/db/migrate/20241111104357_add_names_and_space_boolean_to_taxonomy_filters.rb +9 -0
- data/db/migrate/20241127093708_add_taxonomy_to_metrics.rb +7 -0
- data/db/migrate/20241204121445_add_participatory_space_manifests_from_taxonomy_filters.rb +9 -0
- data/decidim-core.gemspec +14 -17
- data/lib/decidim/action_authorization.rb +3 -2
- data/lib/decidim/amendable.rb +1 -1
- data/lib/decidim/api/input_filters/category_input_filter.rb +5 -3
- data/lib/decidim/api/input_filters/component_input_filter.rb +33 -20
- data/lib/decidim/api/input_filters/user_entity_input_filter.rb +53 -44
- data/lib/decidim/api/input_sorts/component_input_sort.rb +15 -13
- data/lib/decidim/api/input_sorts/user_entity_input_sort.rb +4 -4
- data/lib/decidim/api/interfaces/author_interface.rb +3 -2
- data/lib/decidim/api/interfaces/coauthorable_interface.rb +5 -5
- data/lib/decidim/api/interfaces/endorsable_interface.rb +2 -2
- data/lib/decidim/api/interfaces/participatory_space_interface.rb +5 -10
- data/lib/decidim/api/interfaces/taxonomizable_interface.rb +13 -0
- data/lib/decidim/api/types/amendment_type.rb +5 -7
- data/lib/decidim/api/types/area_api_type.rb +3 -3
- data/lib/decidim/api/types/attachment_type.rb +3 -3
- data/lib/decidim/api/types/category_type.rb +2 -2
- data/lib/decidim/api/types/decidim_type.rb +5 -1
- data/lib/decidim/api/types/fingerprint_type.rb +1 -1
- data/lib/decidim/api/types/localized_string_type.rb +1 -1
- data/lib/decidim/api/types/metric_history_type.rb +2 -0
- data/lib/decidim/api/types/metric_type.rb +1 -1
- data/lib/decidim/api/types/organization_type.rb +5 -0
- data/lib/decidim/api/types/participatory_space_link_type.rb +2 -2
- data/lib/decidim/api/types/participatory_space_manifest_type.rb +1 -1
- data/lib/decidim/api/types/quantifiable_translated_field_type.rb +1 -1
- data/lib/decidim/api/types/scope_api_type.rb +2 -3
- data/lib/decidim/api/types/session_type.rb +1 -2
- data/lib/decidim/api/types/taxonomy_type.rb +15 -0
- data/lib/decidim/api/types/trace_version_type.rb +2 -2
- data/lib/decidim/api/types/translated_field_type.rb +3 -5
- data/lib/decidim/api/types/user_group_type.rb +7 -20
- data/lib/decidim/api/types/user_type.rb +7 -20
- data/lib/decidim/asset_router/storage.rb +4 -4
- data/lib/decidim/assets/tailwind/tailwind.config.js.erb +2 -1
- data/lib/decidim/attachment_attributes.rb +1 -1
- data/lib/decidim/attribute_encryptor.rb +1 -1
- data/lib/decidim/attribute_object/nested_validator.rb +1 -1
- data/lib/decidim/attributes/integer_with_units.rb +27 -0
- data/lib/decidim/attributes.rb +2 -0
- data/lib/decidim/authorization_form_builder.rb +0 -7
- data/lib/decidim/coauthorable.rb +1 -1
- data/lib/decidim/command.rb +3 -3
- data/lib/decidim/commands/destroy_resource.rb +5 -1
- data/lib/decidim/commands/resource_handler.rb +2 -2
- data/lib/decidim/commands/restore_resource.rb +45 -0
- data/lib/decidim/commands/soft_delete_resource.rb +63 -0
- data/lib/decidim/component_manifest.rb +7 -0
- data/lib/decidim/core/api.rb +2 -0
- data/lib/decidim/core/engine.rb +21 -7
- data/lib/decidim/core/menu.rb +0 -5
- data/lib/decidim/core/seeds.rb +42 -2
- data/lib/decidim/core/test/factories.rb +105 -2
- data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +85 -0
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +393 -38
- data/lib/decidim/core/test/shared_examples/components_controller_hide_shared_examples.rb +11 -0
- data/lib/decidim/core/test/shared_examples/components_controller_reorder_shared_examples.rb +21 -0
- data/lib/decidim/core/test/shared_examples/download_open_data_shared_context.rb +36 -0
- data/lib/decidim/core/test/shared_examples/download_open_data_shared_examples.rb +45 -0
- data/lib/decidim/core/test/shared_examples/download_your_data_shared_examples.rb +17 -0
- data/lib/decidim/core/test/shared_examples/etiquette_validator_examples.rb +25 -0
- data/lib/decidim/core/test/shared_examples/follows_examples.rb +43 -0
- data/lib/decidim/core/test/shared_examples/has_taxonomies.rb +94 -0
- data/lib/decidim/core/test/shared_examples/manage_share_tokens_examples.rb +237 -0
- data/lib/decidim/core/test/shared_examples/map_examples.rb +2 -0
- data/lib/decidim/core/test/shared_examples/open_data_exporter_examples.rb +102 -0
- data/lib/decidim/core/test/shared_examples/participatory_space_members_page_examples.rb +46 -0
- data/lib/decidim/core/test/shared_examples/participatory_space_search_examples.rb +98 -0
- data/lib/decidim/core/test/shared_examples/permissions.rb +7 -7
- data/lib/decidim/core/test/shared_examples/preview_with_share_token_examples.rb +94 -0
- data/lib/decidim/core/test/shared_examples/reports_examples.rb +60 -5
- data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +2 -2
- data/lib/decidim/core/test/shared_examples/resource_search_examples.rb +75 -69
- data/lib/decidim/core/test/shared_examples/searchable_resources_shared_context.rb +1 -1
- data/lib/decidim/core/test/shared_examples/simple_event.rb +33 -19
- data/lib/decidim/core/test/shared_examples/social_share_examples.rb +46 -0
- data/lib/decidim/core/test/shared_examples/softdeleteable_components_examples.rb +173 -0
- data/lib/decidim/core/test/shared_examples/system_endorse_resource_examples.rb +54 -8
- data/lib/decidim/core/test/shared_examples/taxonomizable_interface_examples.rb +20 -0
- data/lib/decidim/core/test/shared_examples/taxonomizable_resource_examples.rb +37 -0
- data/lib/decidim/core/test/shared_examples/taxonomy_settings.rb +49 -0
- data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +2 -2
- data/lib/decidim/core/test/shared_examples/with_endorsable_permissions_examples.rb +1 -1
- data/lib/decidim/core/test.rb +9 -5
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +58 -0
- data/lib/decidim/download_your_data_serializers/download_your_data_identity_serializer.rb +0 -4
- data/lib/decidim/download_your_data_serializers/download_your_data_participatory_space_private_user_serializer.rb +3 -1
- data/lib/decidim/download_your_data_serializers/download_your_data_report_serializer.rb +2 -1
- data/lib/decidim/download_your_data_serializers/download_your_data_user_serializer.rb +6 -7
- data/lib/decidim/download_your_data_serializers.rb +19 -0
- data/lib/decidim/exporters/csv.rb +6 -0
- data/lib/decidim/exporters/export_manifest.rb +14 -0
- data/lib/decidim/exporters/pdf.rb +26 -22
- data/lib/decidim/filter_form_builder.rb +12 -15
- data/lib/decidim/form_builder.rb +6 -129
- data/lib/decidim/has_category.rb +5 -1
- data/lib/decidim/has_private_users.rb +4 -0
- data/lib/decidim/has_taxonomy_settings.rb +47 -0
- data/lib/decidim/has_upload_validations.rb +1 -1
- data/lib/decidim/legacy_form_builder.rb +118 -0
- data/lib/decidim/maintenance/import_models/application_record.rb +93 -0
- data/lib/decidim/maintenance/import_models/area.rb +82 -0
- data/lib/decidim/maintenance/import_models/area_type.rb +12 -0
- data/lib/decidim/maintenance/import_models/assembly_type.rb +49 -0
- data/lib/decidim/maintenance/import_models/categorization.rb +14 -0
- data/lib/decidim/maintenance/import_models/category.rb +139 -0
- data/lib/decidim/maintenance/import_models/participatory_process_type.rb +21 -0
- data/lib/decidim/maintenance/import_models/scope.rb +163 -0
- data/lib/decidim/maintenance/import_models.rb +19 -0
- data/lib/decidim/maintenance/taxonomy_importer.rb +142 -0
- data/lib/decidim/maintenance/taxonomy_plan.rb +78 -0
- data/lib/decidim/maintenance.rb +12 -0
- data/lib/decidim/map/autocomplete.rb +52 -8
- data/lib/decidim/map/dynamic_map.rb +1 -1
- data/lib/decidim/map/provider/dynamic_map/here.rb +1 -40
- data/lib/decidim/map/provider/geocoding/here.rb +9 -3
- data/lib/decidim/map.rb +3 -6
- data/lib/decidim/moderation_tools.rb +29 -5
- data/lib/decidim/newsletter_encryptor.rb +1 -1
- data/lib/decidim/paddable.rb +1 -1
- data/lib/decidim/participable.rb +10 -10
- data/lib/decidim/participatory_space_user.rb +10 -0
- data/lib/decidim/private_download_helper.rb +15 -0
- data/lib/decidim/record_encryptor.rb +51 -46
- data/lib/decidim/resourceable.rb +16 -0
- data/lib/decidim/seeds.rb +18 -20
- data/lib/decidim/settings_manifest.rb +34 -1
- data/lib/decidim/soft_deletable.rb +17 -0
- data/lib/decidim/taxonomizable.rb +72 -0
- data/lib/decidim/view_model.rb +0 -1
- data/lib/tasks/decidim_download_your_data_tasks.rake +2 -4
- data/lib/tasks/decidim_procfile.rake +6 -0
- data/lib/tasks/decidim_tasks.rake +1 -0
- data/lib/tasks/decidim_taxonomies.rake +160 -0
- data/lib/tasks/upgrade/{decidim_fix_categorization.rake → clean.rake} +25 -18
- data/lib/tasks/upgrade/clean_hidden_resources.rake +33 -0
- data/lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake +1 -1
- data/lib/tasks/upgrade/migrations.rake +94 -0
- metadata +198 -103
- data/app/cells/decidim/amendable/amenders_list/show.erb +0 -0
- data/app/cells/decidim/content_blocks/base/content.erb +0 -0
- data/app/cells/decidim/endorsers_list/full_endorsers_list.erb +0 -3
- data/app/cells/decidim/endorsers_list_button/content.erb +0 -1
- data/app/cells/decidim/endorsers_list_button_cell.rb +0 -15
- data/app/cells/decidim/scopes_picker/scope_picker_prompt.erb +0 -3
- data/app/cells/decidim/scopes_picker/scope_picker_values.erb +0 -5
- data/app/cells/decidim/scopes_picker/show.erb +0 -14
- data/app/cells/decidim/scopes_picker_cell.rb +0 -92
- data/app/commands/decidim/update_user_interests.rb +0 -41
- data/app/controllers/decidim/scopes_controller.rb +0 -84
- data/app/controllers/decidim/user_interests_controller.rb +0 -30
- data/app/forms/decidim/user_interest_scope_form.rb +0 -25
- data/app/forms/decidim/user_interests_form.rb +0 -17
- data/app/helpers/decidim/categories_helper.rb +0 -26
- data/app/helpers/decidim/scopes_helper.rb +0 -105
- data/app/packs/images/decidim/vendor/leaflet/layers-2x.png +0 -0
- data/app/packs/images/decidim/vendor/leaflet/layers.png +0 -0
- data/app/packs/images/decidim/vendor/leaflet/marker-icon-2x.png +0 -0
- data/app/packs/images/decidim/vendor/leaflet/marker-icon.png +0 -0
- data/app/packs/images/decidim/vendor/leaflet/marker-shadow.png +0 -0
- data/app/packs/src/decidim/vendor/leaflet-tilelayer-here.js +0 -212
- data/app/packs/stylesheets/decidim/legacy/MarkerCluster.Default.scss +0 -67
- data/app/packs/stylesheets/decidim/legacy/MarkerCluster.scss +0 -18
- data/app/packs/stylesheets/decidim/legacy/leaflet.scss +0 -705
- data/app/validators/scope_belongs_to_component_validator.rb +0 -16
- data/app/views/decidim/account/_user_groups.html.erb +0 -0
- data/app/views/decidim/scopes/_scopes_picker_input.html.erb +0 -19
- data/app/views/decidim/scopes/picker.html.erb +0 -53
- data/app/views/decidim/shared/_comments.html.erb +0 -0
- data/app/views/decidim/shared/_share_modal.html.erb +0 -26
- data/app/views/decidim/shared/_tags.html.erb +0 -1
- data/app/views/decidim/user_interests/_areas.html.erb +0 -14
- data/app/views/decidim/user_interests/_scopes.html.erb +0 -22
- data/app/views/decidim/user_interests/show.html.erb +0 -22
- data/config/initializers/foundation_rails_helper.rb +0 -4
- data/lib/decidim/core/test/shared_examples/has_category.rb +0 -38
- data/lib/decidim/core/test/shared_examples/has_scope.rb +0 -11
- data/lib/decidim/core/test/shared_examples/manage_component_share_tokens.rb +0 -83
- data/lib/decidim/core/test/shared_examples/preview_component_with_share_token_examples.rb +0 -49
- data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +0 -93
- data/lib/decidim/seven_zip_wrapper.rb +0 -29
@@ -1,41 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "decidim/seven_zip_wrapper"
|
4
|
-
|
5
3
|
module Decidim
|
6
|
-
# Public: Generates a
|
4
|
+
# Public: Generates a zip archive with data files ready to be persisted
|
7
5
|
# somewhere so users can download their data.
|
8
6
|
#
|
9
|
-
# In fact, the 7z file wraps a ZIP file which finally contains the data files.
|
10
7
|
class DownloadYourDataExporter
|
11
8
|
DEFAULT_EXPORT_FORMAT = "CSV"
|
12
9
|
ZIP_FILE_NAME = "download-your-data.zip"
|
13
10
|
|
11
|
+
include Decidim::TranslatableAttributes
|
12
|
+
|
14
13
|
# Public: Initializes the class.
|
15
14
|
#
|
16
15
|
# user - The user to export the data from.
|
17
|
-
#
|
18
|
-
# password - The password to protect the zip file.
|
16
|
+
# name - The name of the export in private area
|
19
17
|
# export_format - The format of the data files inside the zip file. (CSV by default)
|
20
|
-
def initialize(user,
|
18
|
+
def initialize(user, name, export_format = DEFAULT_EXPORT_FORMAT)
|
21
19
|
@user = user
|
22
|
-
@path = File.expand_path path
|
23
20
|
@export_format = export_format
|
24
|
-
@
|
21
|
+
@name = name
|
25
22
|
end
|
26
23
|
|
24
|
+
# i18n-tasks-use t("decidim.download_your_data.show.download_your_data")
|
27
25
|
def export
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
user_export = user.private_exports.build
|
27
|
+
user_export.export_type = name
|
28
|
+
user_export.file.attach(io: data, filename: "#{name}.zip", content_type: "application/zip")
|
29
|
+
user_export.expires_at = Decidim.download_your_data_expiry_time.from_now
|
30
|
+
user_export.metadata = {}
|
31
|
+
user_export.save!
|
32
|
+
user_export
|
34
33
|
end
|
35
34
|
|
36
35
|
private
|
37
36
|
|
38
|
-
attr_reader :user, :export_format
|
37
|
+
attr_reader :user, :export_format, :name
|
38
|
+
|
39
|
+
def data
|
40
|
+
user_data, user_attachments = data_and_attachments_for_user
|
41
|
+
buffer = Zip::OutputStream.write_buffer do |out|
|
42
|
+
save_user_data(out, user_data)
|
43
|
+
save_user_attachments(out, user_attachments)
|
44
|
+
save_readme(out)
|
45
|
+
end
|
46
|
+
|
47
|
+
buffer.rewind
|
48
|
+
buffer
|
49
|
+
end
|
39
50
|
|
40
51
|
def data_and_attachments_for_user
|
41
52
|
export_data = []
|
@@ -43,7 +54,8 @@ module Decidim
|
|
43
54
|
|
44
55
|
download_your_data_entities.each do |object|
|
45
56
|
klass = Object.const_get(object)
|
46
|
-
|
57
|
+
exporter = Exporters.find_exporter(export_format).new(klass.user_collection(user), klass.export_serializer)
|
58
|
+
export_data << [klass.model_name.name.parameterize.pluralize, exporter.export]
|
47
59
|
attachments = klass.download_your_data_images(user)
|
48
60
|
export_attachments << [klass.model_name.name.parameterize.pluralize, attachments.flatten] unless attachments.nil?
|
49
61
|
end
|
@@ -55,30 +67,52 @@ module Decidim
|
|
55
67
|
@download_your_data_entities ||= DownloadYourDataSerializers.data_entities
|
56
68
|
end
|
57
69
|
|
58
|
-
def save_user_data(
|
70
|
+
def save_user_data(output, user_data)
|
59
71
|
user_data.each do |entity, exporter_data|
|
60
72
|
next if exporter_data.read == "\n"
|
61
73
|
|
62
|
-
|
63
|
-
|
74
|
+
output.put_next_entry("#{entity}-#{exporter_data.filename}")
|
75
|
+
output.write exporter_data.read
|
64
76
|
end
|
65
77
|
end
|
66
78
|
|
67
|
-
def save_user_attachments(
|
79
|
+
def save_user_attachments(output, user_attachments)
|
68
80
|
user_attachments.each do |entity, attachment_block|
|
69
81
|
attachment_block.each do |attachment|
|
70
82
|
next unless attachment.attached?
|
71
83
|
|
72
84
|
blobs = attachment.is_a?(ActiveStorage::Attached::One) ? [attachment.blob] : attachment.blobs
|
73
85
|
blobs.each do |blob|
|
74
|
-
Dir.mkdir(File.join(tmpdir, entity.parameterize))
|
75
|
-
file_name = File.join(tmpdir, entity.parameterize, blob.filename.to_s)
|
76
86
|
blob.open do |blob_file|
|
77
|
-
|
87
|
+
output.put_next_entry("#{entity.parameterize}/#{blob.filename}")
|
88
|
+
output.write blob_file.read.force_encoding("UTF-8")
|
78
89
|
end
|
79
90
|
end
|
80
91
|
end
|
81
92
|
end
|
82
93
|
end
|
94
|
+
|
95
|
+
def save_readme(output)
|
96
|
+
output.put_next_entry("README.md")
|
97
|
+
output.write readme
|
98
|
+
end
|
99
|
+
|
100
|
+
def readme
|
101
|
+
readme_file = "# #{I18n.t("decidim.download_your_data.help.core.title", organization: translated_attribute(user.organization.name))}\n\n"
|
102
|
+
readme_file << "#{I18n.t("decidim.download_your_data.help.core.description", user_name: "#{user.name} (#{user.nickname})")}\n\n"
|
103
|
+
help_definition = DownloadYourDataSerializers.help_definitions_for(user)
|
104
|
+
|
105
|
+
help_definition.each do |entity, headers|
|
106
|
+
next if headers.empty?
|
107
|
+
|
108
|
+
readme_file << "\n\n## #{entity}\n\n"
|
109
|
+
|
110
|
+
headers.each do |header, help_value|
|
111
|
+
readme_file << "* #{header}: #{help_value}\n"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
readme_file
|
116
|
+
end
|
83
117
|
end
|
84
118
|
end
|
@@ -0,0 +1,272 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
# This class is used to manage the onboarding funnel for users that
|
5
|
+
# intended to perform an action in the platform but it requires some
|
6
|
+
# verification steps to be completed.
|
7
|
+
#
|
8
|
+
# The flow is as follows:
|
9
|
+
#
|
10
|
+
# 1. A visitor (logged out) tries to perform an action that requires to be logged in
|
11
|
+
# 2. The intended action is stored in a cookie (onboarding key)
|
12
|
+
# 3. The visitor logs in and the onboarding cookie data is merged into the User#extended_data column.
|
13
|
+
# 4. After logging in, the user is redirected to the onboarding pending authorizations page
|
14
|
+
# if there is any pending action stored in the User#extended_data column
|
15
|
+
# 5. The user completes the required authorizations
|
16
|
+
# 6. When the onboarding authorizations page detects that all the verification steps have been
|
17
|
+
# completed, it will remove the pending action from the User#extended_data column and redirect
|
18
|
+
# the user to the intended action.
|
19
|
+
#
|
20
|
+
class OnboardingManager
|
21
|
+
# The same key is set in onboarding_pending_action js file to manage the
|
22
|
+
# onboarding data in the cookie
|
23
|
+
DATA_KEY = "onboarding"
|
24
|
+
|
25
|
+
attr_reader :user
|
26
|
+
|
27
|
+
def initialize(user)
|
28
|
+
@user = user
|
29
|
+
end
|
30
|
+
|
31
|
+
delegate :ephemeral?, to: :user
|
32
|
+
|
33
|
+
# Checks if the onboarding data has an action and a model.
|
34
|
+
#
|
35
|
+
# Returns a boolean
|
36
|
+
def valid?
|
37
|
+
return if action.blank?
|
38
|
+
|
39
|
+
permissions_holder.present?
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the action to be performed.
|
43
|
+
#
|
44
|
+
# Returns a string
|
45
|
+
def action
|
46
|
+
onboarding_action
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns the translation of the action to be performed if translation
|
50
|
+
# is found, otherwise the untranslated literal action key
|
51
|
+
#
|
52
|
+
# Returns a string
|
53
|
+
def action_text
|
54
|
+
@action_text ||= if component && I18n.exists?("#{component.manifest.name}.actions.#{action}", scope: "decidim.components")
|
55
|
+
I18n.t("#{component.manifest.name}.actions.#{action}", scope: "decidim.components")
|
56
|
+
elsif permissions_holder.respond_to?(:resource_manifest) &&
|
57
|
+
I18n.exists?("#{permissions_holder.resource_manifest.name}.actions.#{action}", scope: "decidim.resources")
|
58
|
+
I18n.t("#{permissions_holder.resource_manifest.name}.actions.#{action}", scope: "decidim.resources")
|
59
|
+
else
|
60
|
+
action
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Checks if there is any pending action for the user.
|
65
|
+
#
|
66
|
+
# Returns a boolean
|
67
|
+
def pending_action?
|
68
|
+
onboarding_data.present?
|
69
|
+
end
|
70
|
+
|
71
|
+
# Checks if the user has completed all the required authorizations.
|
72
|
+
#
|
73
|
+
# active_authorization_methods - A list of the active authorization methods for the user.
|
74
|
+
#
|
75
|
+
# Returns a boolean
|
76
|
+
def finished_verifications?(authorization_methods = active_authorization_methods)
|
77
|
+
(authorization_handlers - authorization_methods).empty?
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns the model related to the action in the onboarding process.
|
81
|
+
#
|
82
|
+
# Returns an ActiveRecord model
|
83
|
+
def model
|
84
|
+
return if onboarding_model.blank?
|
85
|
+
|
86
|
+
@model ||= GlobalID::Locator.locate(onboarding_model)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns the permissions_holder if present related to the action in the
|
90
|
+
# onboarding process.
|
91
|
+
#
|
92
|
+
# Returns an ActiveRecord model
|
93
|
+
def permissions_holder
|
94
|
+
return model if onboarding_permissions_holder.blank?
|
95
|
+
|
96
|
+
@permissions_holder ||= GlobalID::Locator.locate(onboarding_permissions_holder)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the model name related to the action in the onboarding process.
|
100
|
+
#
|
101
|
+
# Returns a string
|
102
|
+
def model_name
|
103
|
+
return unless valid?
|
104
|
+
|
105
|
+
@model_name ||= (model.presence || permissions_holder).class.model_name
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns the resource title associated to the action. If the model is defined
|
109
|
+
# its title is used, if not the permissions holder title
|
110
|
+
#
|
111
|
+
# Returns a translations Hash or a String
|
112
|
+
def model_title
|
113
|
+
return unless valid?
|
114
|
+
|
115
|
+
@model_title ||= begin
|
116
|
+
resource = model.presence || permissions_holder
|
117
|
+
|
118
|
+
method = [:title, :name].find { |m| resource.respond_to?(m) }
|
119
|
+
|
120
|
+
resource.send(method) if method
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Filters the given authorizations that are required for the onboarding process.
|
125
|
+
#
|
126
|
+
# authorizations - An array of Decidim::Authorization objects
|
127
|
+
#
|
128
|
+
# Returns an array of Decidim::Authorization objects
|
129
|
+
def filter_authorizations(authorizations)
|
130
|
+
filtered_authorizations = authorizations.select { |authorization| authorization_handlers.include?(authorization.name) }
|
131
|
+
|
132
|
+
# By calling authorize on each authorization the path generated for each
|
133
|
+
# one will include the specific options of the action if available
|
134
|
+
filtered_authorizations.each do |authorization|
|
135
|
+
next unless authorization.is_a? Decidim::Verifications::Adapter
|
136
|
+
|
137
|
+
authorization.authorize(nil, permissions.dig("authorization_handlers", authorization.name, "options") || {}, model, permissions_holder)
|
138
|
+
end
|
139
|
+
filtered_authorizations
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns a hash which can be passed to action_authorized_to helper method
|
143
|
+
# to determine the permissions status of the action
|
144
|
+
#
|
145
|
+
# Returns a Hash
|
146
|
+
def action_authorized_resources
|
147
|
+
return {} unless valid?
|
148
|
+
|
149
|
+
{
|
150
|
+
resource: model,
|
151
|
+
permissions_holder: onboarding_permissions_holder.presence && permissions_holder
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns the path to redirect after finishing the verification process. The path
|
156
|
+
# can be obtained from the user onboarding redirect_path data or if a resource is
|
157
|
+
# present using a ResourceLocatorPresenter
|
158
|
+
#
|
159
|
+
# Returns a String
|
160
|
+
def finished_redirect_path
|
161
|
+
@finished_redirect_path ||= onboarding_data["redirect_path"].presence || model_path
|
162
|
+
end
|
163
|
+
|
164
|
+
def root_path
|
165
|
+
component_path || Decidim::Core::Engine.routes.url_helpers.root_path
|
166
|
+
end
|
167
|
+
|
168
|
+
def component_path
|
169
|
+
return if component.blank?
|
170
|
+
|
171
|
+
EngineRouter.main_proxy(component).root_path
|
172
|
+
end
|
173
|
+
|
174
|
+
def expired?
|
175
|
+
return unless ephemeral?
|
176
|
+
|
177
|
+
session_duration > Decidim.config.expire_session_after.to_i
|
178
|
+
end
|
179
|
+
|
180
|
+
# Time in seconds since the last login or creation of the user
|
181
|
+
#
|
182
|
+
# Returns an Integer
|
183
|
+
def session_duration
|
184
|
+
Time.current.to_i - (user.last_sign_in_at || user.created_at).to_i
|
185
|
+
end
|
186
|
+
|
187
|
+
# This method is used to determine if an ephemeral user has an onboarding
|
188
|
+
# page to be redirected or only an authorization is required to complete the
|
189
|
+
# verification
|
190
|
+
#
|
191
|
+
# Returns a Boolean
|
192
|
+
def available_authorization_selection_page?
|
193
|
+
return true unless valid? && ephemeral?
|
194
|
+
|
195
|
+
authorization_handlers.count > 1
|
196
|
+
end
|
197
|
+
|
198
|
+
private
|
199
|
+
|
200
|
+
def active_authorization_methods
|
201
|
+
@active_authorization_methods ||= Verifications::Authorizations.new(organization: user.organization, user:).pluck(:name)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Returns the permissions for the action and model in the onboarding process.
|
205
|
+
#
|
206
|
+
# Returns a hash
|
207
|
+
def permissions
|
208
|
+
@permissions ||= permissions_holder&.permissions&.fetch(action, nil) || component&.permissions&.fetch(action, nil)
|
209
|
+
end
|
210
|
+
|
211
|
+
# Returns the authorization handlers for the action and model in the onboarding process.
|
212
|
+
#
|
213
|
+
# Returns an array of strings
|
214
|
+
def authorization_handlers
|
215
|
+
return [] unless permissions
|
216
|
+
|
217
|
+
permissions["authorization_handlers"]&.keys&.map(&:to_s) || []
|
218
|
+
end
|
219
|
+
|
220
|
+
# Returns the model component or the permissions holder when it is a component.
|
221
|
+
#
|
222
|
+
# Returns a Decidim::Component
|
223
|
+
def component
|
224
|
+
return permissions_holder if permissions_holder.is_a?(Decidim::Component)
|
225
|
+
return if model.blank?
|
226
|
+
return unless model.respond_to?(:component)
|
227
|
+
|
228
|
+
model.component
|
229
|
+
end
|
230
|
+
|
231
|
+
# Returns the onboarding data from the user's extended_data related to the model in gid format.
|
232
|
+
#
|
233
|
+
# Returns a string
|
234
|
+
def onboarding_model
|
235
|
+
onboarding_data["model"]
|
236
|
+
end
|
237
|
+
|
238
|
+
# Returns the onboarding data from the user's extended_data related to the permissions_holder
|
239
|
+
# in gid format. This attribute is optional and may not be present
|
240
|
+
#
|
241
|
+
# Returns a string
|
242
|
+
def onboarding_permissions_holder
|
243
|
+
onboarding_data["permissions_holder"]
|
244
|
+
end
|
245
|
+
|
246
|
+
# Returns the onboarding data from the user's extended_data related to the action.
|
247
|
+
#
|
248
|
+
# Returns a string
|
249
|
+
def onboarding_action
|
250
|
+
onboarding_data["action"]
|
251
|
+
end
|
252
|
+
|
253
|
+
# Returns the onboarding data from the user's extended_data.
|
254
|
+
#
|
255
|
+
# Returns a hash
|
256
|
+
def onboarding_data
|
257
|
+
user.extended_data[DATA_KEY] || {}
|
258
|
+
end
|
259
|
+
|
260
|
+
# Returns the path associated to the model using ResourceLocatorPresenter. If model is not
|
261
|
+
# present returns the root path
|
262
|
+
#
|
263
|
+
# Returns a String
|
264
|
+
def model_path
|
265
|
+
return Decidim::Core::Engine.routes.url_helpers.root_path if model.blank?
|
266
|
+
|
267
|
+
ResourceLocatorPresenter.new(model).url
|
268
|
+
rescue NoMethodError
|
269
|
+
Decidim::Core::Engine.routes.url_helpers.root_path
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
@@ -9,48 +9,86 @@ module Decidim
|
|
9
9
|
class OpenDataExporter
|
10
10
|
FILE_NAME_PATTERN = "%{host}-open-data-%{entity}.csv"
|
11
11
|
|
12
|
-
attr_reader :organization, :path
|
12
|
+
attr_reader :organization, :path, :resource, :help_definition
|
13
|
+
|
14
|
+
include Decidim::TranslatableAttributes
|
13
15
|
|
14
16
|
# Public: Initializes the class.
|
15
17
|
#
|
16
18
|
# organization - The Organization to export the data from.
|
17
19
|
# path - The String path where to write the zip file.
|
18
|
-
|
20
|
+
# resource - The String of the component or participatory space to export. If nil, it will export all.
|
21
|
+
def initialize(organization, path, resource = nil)
|
19
22
|
@organization = organization
|
20
23
|
@path = File.expand_path path
|
24
|
+
@resource = resource
|
25
|
+
@help_definition = {}
|
21
26
|
end
|
22
27
|
|
23
28
|
def export
|
24
29
|
dirname = File.dirname(path)
|
25
30
|
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
26
|
-
|
31
|
+
if resource.nil?
|
32
|
+
File.binwrite(path, data_for_all_resources)
|
33
|
+
else
|
34
|
+
File.write(path, data_for_resource(resource))
|
35
|
+
end
|
27
36
|
end
|
28
37
|
|
29
38
|
private
|
30
39
|
|
31
|
-
def
|
40
|
+
def data_for_all_resources
|
32
41
|
buffer = Zip::OutputStream.write_buffer do |out|
|
42
|
+
core_data_manifests.each do |manifest|
|
43
|
+
add_file_to_output(out, format(FILE_NAME_PATTERN, { host: organization.host, entity: manifest.name }), data_for_core(manifest).read)
|
44
|
+
end
|
33
45
|
open_data_component_manifests.each do |manifest|
|
34
|
-
add_file_to_output(out, format(FILE_NAME_PATTERN, { host: organization.host, entity: manifest.name }), data_for_component(manifest))
|
46
|
+
add_file_to_output(out, format(FILE_NAME_PATTERN, { host: organization.host, entity: manifest.name }), data_for_component(manifest).read)
|
35
47
|
end
|
36
48
|
open_data_participatory_space_manifests.each do |manifest|
|
37
|
-
add_file_to_output(out, format(FILE_NAME_PATTERN, { host: organization.host, entity: manifest.name }), data_for_participatory_space(manifest))
|
49
|
+
add_file_to_output(out, format(FILE_NAME_PATTERN, { host: organization.host, entity: manifest.name }), data_for_participatory_space(manifest).read)
|
38
50
|
end
|
51
|
+
|
52
|
+
add_file_to_output(out, "README.md", readme)
|
53
|
+
add_file_to_output(out, "LICENSE.md", license)
|
39
54
|
end
|
40
55
|
|
41
56
|
buffer.string
|
42
57
|
end
|
43
58
|
|
59
|
+
def data_for_core(export_manifest)
|
60
|
+
collection = export_manifest.collection.call(organization)
|
61
|
+
exporter = Decidim::Exporters::CSV.new(collection, export_manifest.serializer)
|
62
|
+
|
63
|
+
get_help_definition(:core, exporter, export_manifest) unless collection.empty?
|
64
|
+
|
65
|
+
exporter.export
|
66
|
+
end
|
67
|
+
|
68
|
+
def data_for_resource(resource)
|
69
|
+
export_manifest = (core_data_manifests + open_data_component_manifests + open_data_participatory_space_manifests)
|
70
|
+
.select { |manifest| manifest.name == resource.to_sym }.first
|
71
|
+
|
72
|
+
case export_manifest.respond_to?(:manifest) && export_manifest.manifest
|
73
|
+
when Decidim::ComponentManifest
|
74
|
+
data_for_component(export_manifest).read
|
75
|
+
when Decidim::ParticipatorySpaceManifest
|
76
|
+
data_for_participatory_space(export_manifest).read
|
77
|
+
else
|
78
|
+
data_for_core(export_manifest).read
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
44
82
|
def data_for_component(export_manifest, col_sep = Decidim.default_csv_col_sep)
|
45
83
|
headers = []
|
46
84
|
collection = []
|
47
85
|
ActiveRecord::Base.uncached do
|
48
|
-
components.where(manifest_name: export_manifest.manifest.name).find_each do |component|
|
86
|
+
components.where(manifest_name: export_manifest.manifest.name).unscope(:order).find_each do |component|
|
49
87
|
export_manifest.collection.call(component).find_in_batches(batch_size: 100) do |batch|
|
50
|
-
|
88
|
+
serializer = export_manifest.open_data_serializer.nil? ? export_manifest.serializer : export_manifest.open_data_serializer
|
89
|
+
exporter = Decidim::Exporters::CSV.new(batch, serializer)
|
51
90
|
headers.push(*exporter.headers)
|
52
91
|
exported = exporter.export
|
53
|
-
|
54
92
|
tmpdir = Dir::Tmpname.create(export_manifest.name.to_s) do
|
55
93
|
# just get an empty file name
|
56
94
|
end
|
@@ -59,6 +97,8 @@ module Decidim
|
|
59
97
|
File.write(filename, exported.read)
|
60
98
|
|
61
99
|
collection.push(filename)
|
100
|
+
|
101
|
+
get_help_definition(:components, exporter, export_manifest) unless collection.empty?
|
62
102
|
end
|
63
103
|
end
|
64
104
|
end
|
@@ -76,16 +116,102 @@ module Decidim
|
|
76
116
|
end
|
77
117
|
|
78
118
|
def data_for_participatory_space(export_manifest)
|
79
|
-
collection = participatory_spaces.
|
119
|
+
collection = participatory_spaces.flat_map do |participatory_space|
|
80
120
|
export_manifest.collection.call(participatory_space)
|
81
121
|
end
|
122
|
+
serializer = export_manifest.open_data_serializer.nil? ? export_manifest.serializer : export_manifest.open_data_serializer
|
123
|
+
exporter = Decidim::Exporters::CSV.new(collection, serializer)
|
124
|
+
get_help_definition(:spaces, exporter, export_manifest) unless collection.empty?
|
125
|
+
|
126
|
+
exporter.export
|
127
|
+
end
|
128
|
+
|
129
|
+
def get_help_definition(manifest_type, exporter, export_manifest)
|
130
|
+
help_definition[manifest_type] = {} if help_definition[manifest_type].nil?
|
131
|
+
help_definition[manifest_type][export_manifest.name] = {} if help_definition[manifest_type][export_manifest.name].blank?
|
132
|
+
exporter.headers_without_locales.each do |header|
|
133
|
+
help_definition[manifest_type][export_manifest.name][header] = I18n.t("decidim.open_data.help.#{export_manifest.name}.#{header}")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def readme
|
138
|
+
"# #{I18n.t("decidim.open_data.help.core.title", organization: translated_attribute(organization.name))}\n\n
|
139
|
+
#{I18n.t("decidim.open_data.help.core.description")}\n\n
|
140
|
+
#{core_readme}
|
141
|
+
#{space_readme}
|
142
|
+
#{component_readme}
|
143
|
+
"
|
144
|
+
end
|
145
|
+
|
146
|
+
def core_readme
|
147
|
+
return unless help_definition.fetch(:core, false)
|
148
|
+
|
149
|
+
readme_file = "## #{I18n.t("decidim.open_data.help.core.main")}\n\n"
|
150
|
+
help_definition.fetch(:core, []).each do |element, headers|
|
151
|
+
readme_file << "### #{element}\n\n"
|
152
|
+
|
153
|
+
headers.each do |header, help_value|
|
154
|
+
readme_file << "* #{header}: #{help_value}\n"
|
155
|
+
end
|
156
|
+
|
157
|
+
readme_file << "\n\n"
|
158
|
+
end
|
159
|
+
readme_file
|
160
|
+
end
|
161
|
+
|
162
|
+
def space_readme
|
163
|
+
return unless help_definition.fetch(:spaces, false)
|
164
|
+
|
165
|
+
readme_file = "## #{I18n.t("decidim.open_data.help.core.spaces")}\n\n"
|
166
|
+
|
167
|
+
help_definition.fetch(:spaces, []).each do |space, headers|
|
168
|
+
readme_file << "### #{space}\n\n"
|
169
|
+
|
170
|
+
headers.each do |header, help_value|
|
171
|
+
readme_file << "* #{header}: #{help_value}\n"
|
172
|
+
end
|
173
|
+
|
174
|
+
readme_file << "\n\n"
|
175
|
+
end
|
176
|
+
readme_file
|
177
|
+
end
|
178
|
+
|
179
|
+
def component_readme
|
180
|
+
return unless help_definition.fetch(:components, false)
|
181
|
+
|
182
|
+
readme_file = "## #{I18n.t("decidim.open_data.help.core.components")}\n\n"
|
183
|
+
|
184
|
+
help_definition.fetch(:components, []).each do |component, headers|
|
185
|
+
readme_file << "### #{component}\n\n"
|
186
|
+
|
187
|
+
headers.each do |header, help_value|
|
188
|
+
readme_file << "* #{header}: #{help_value}\n"
|
189
|
+
end
|
190
|
+
|
191
|
+
readme_file << "\n\n"
|
192
|
+
end
|
82
193
|
|
83
|
-
|
194
|
+
readme_file
|
84
195
|
end
|
85
196
|
|
86
|
-
def
|
197
|
+
def license
|
198
|
+
link_database = "#{I18n.t("license_database_name", scope: "decidim.open_data.index.license")}: #{I18n.t("license_database_link", scope: "decidim.open_data.index.license")}"
|
199
|
+
link_contents = "#{I18n.t("license_contents_name", scope: "decidim.open_data.index.license")}: #{I18n.t("license_contents_link", scope: "decidim.open_data.index.license")}"
|
200
|
+
|
201
|
+
license_file = I18n.t("title", scope: "decidim.open_data.index.license")
|
202
|
+
license_file << "\n\n"
|
203
|
+
license_file << I18n.t("body_1_html", scope: "decidim.open_data.index.license", organization_name: translated_attribute(organization.name), link_database:, link_contents:)
|
204
|
+
|
205
|
+
license_file
|
206
|
+
end
|
207
|
+
|
208
|
+
def add_file_to_output(output, file_name, string)
|
87
209
|
output.put_next_entry(file_name)
|
88
|
-
output.write
|
210
|
+
output.write string
|
211
|
+
end
|
212
|
+
|
213
|
+
def core_data_manifests
|
214
|
+
@core_data_manifests ||= Decidim.open_data_manifests.select(&:include_in_open_data)
|
89
215
|
end
|
90
216
|
|
91
217
|
def open_data_component_manifests
|
@@ -69,6 +69,19 @@ module Decidim
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
# Performs the given block and sets the author of the action without log.
|
73
|
+
#
|
74
|
+
# author - An object that implements `to_gid` or a String
|
75
|
+
#
|
76
|
+
# Returns whatever the given block returns.
|
77
|
+
def perform_action_without_log!(author)
|
78
|
+
PaperTrail.request(whodunnit: gid(author)) do
|
79
|
+
Decidim::ApplicationRecord.transaction do
|
80
|
+
block_given? ? yield : nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
72
85
|
# Updates the `resource` with `update!` and sets the author of the version.
|
73
86
|
#
|
74
87
|
# resource - An ActiveRecord instance that implements `Decidim::Traceable`
|
@@ -6,9 +6,11 @@ class EtiquetteValidator < ActiveModel::EachValidator
|
|
6
6
|
include ActionView::Helpers::SanitizeHelper
|
7
7
|
|
8
8
|
def validate_each(record, attribute, value)
|
9
|
+
return unless Decidim.enable_etiquette_validator
|
9
10
|
return if value.blank?
|
10
11
|
|
11
|
-
|
12
|
+
# remove HTML tags, from WYSIWYG editor
|
13
|
+
text_value = clean_value(value)
|
12
14
|
|
13
15
|
validate_caps(record, attribute, text_value)
|
14
16
|
validate_marks(record, attribute, text_value)
|
@@ -17,8 +19,13 @@ class EtiquetteValidator < ActiveModel::EachValidator
|
|
17
19
|
|
18
20
|
private
|
19
21
|
|
22
|
+
def clean_value(value)
|
23
|
+
ActionController::Base.helpers.strip_tags(value).to_s.strip
|
24
|
+
end
|
25
|
+
|
20
26
|
def validate_caps(record, attribute, value)
|
21
|
-
|
27
|
+
number_of_caps = value.scan(/[A-Z]/).length
|
28
|
+
return if number_of_caps.zero? || number_of_caps < value.length / 2 # 50%
|
22
29
|
|
23
30
|
record.errors.add(attribute, options[:message] || :too_much_caps)
|
24
31
|
end
|
@@ -33,7 +33,7 @@ class PassthruValidator < ActiveModel::EachValidator
|
|
33
33
|
value = dummy.public_send(dummy_attr)
|
34
34
|
elsif dummy.respond_to? :file
|
35
35
|
dummy.public_send("file=", value)
|
36
|
-
value = dummy.
|
36
|
+
value = dummy.file
|
37
37
|
end
|
38
38
|
|
39
39
|
target_validators(attribute).each do |validator|
|