diff --git a/CHANGELOG.md b/CHANGELOG.md index add0e6c5c..68fe2b4a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,16 @@ ## next deploy +- improves api/notification controller to avoid failing when there is a notification with wrong notification_type in db +- Add extra_authorize_params to OpenIdConnect config +- Improvement : add a notification to remind users to upload their supporting documents + +## v6.0.14 2023 September 6 + - Fix a bug: for project categories, if there is no category : do not show categories panel in show view, do not show categories input field in edit view - Fix a bug: unable to update status to paid for latest payment schedule item - Fix a bug: unable to generate statistic +- Fix a bug: unable to update user profile by admin - Feature: add a filter in members list (admin) to show only "not validated" members - Concerning statistics: - removes age and type column from all statistics tabs (only in web, not in xlsx export file) diff --git a/app/controllers/api/auth_providers_controller.rb b/app/controllers/api/auth_providers_controller.rb index 97a5c0ceb..82fa50388 100644 --- a/app/controllers/api/auth_providers_controller.rb +++ b/app/controllers/api/auth_providers_controller.rb @@ -99,7 +99,7 @@ class API::AuthProvidersController < API::APIController providable_attributes: [:id, :issuer, :discovery, :client_auth_method, :prompt, :send_scope_to_token_endpoint, :client__identifier, :client__secret, :client__authorization_endpoint, :client__token_endpoint, :client__userinfo_endpoint, :client__jwks_uri, :client__end_session_endpoint, :profile_url, - { scope: [] }], + :extra_authorize_params, { scope: [] }], auth_provider_mappings_attributes: [:id, :local_model, :local_field, :api_field, :api_endpoint, :api_data_type, :_destroy, { transformation: [:type, :format, :true_value, :false_value, { mapping: %i[from to] }] }]) diff --git a/app/controllers/api/notifications_controller.rb b/app/controllers/api/notifications_controller.rb index 919d1aa5a..c226d2b82 100644 --- a/app/controllers/api/notifications_controller.rb +++ b/app/controllers/api/notifications_controller.rb @@ -15,6 +15,7 @@ class API::NotificationsController < API::APIController def index loop do @notifications = current_user.notifications + .with_valid_notification_type .delivered_in_system(current_user) .includes(:attached_object) .page(params[:page]) @@ -24,8 +25,8 @@ class API::NotificationsController < API::APIController break unless delete_obsoletes(@notifications) end @totals = { - total: current_user.notifications.delivered_in_system(current_user).count, - unread: current_user.notifications.delivered_in_system(current_user).where(is_read: false).count + total: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).count, + unread: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).where(is_read: false).count } render :index end @@ -33,6 +34,7 @@ class API::NotificationsController < API::APIController def last_unread loop do @notifications = current_user.notifications + .with_valid_notification_type .delivered_in_system(current_user) .includes(:attached_object) .where(is_read: false) @@ -42,19 +44,20 @@ class API::NotificationsController < API::APIController break unless delete_obsoletes(@notifications) end @totals = { - total: current_user.notifications.delivered_in_system(current_user).count, - unread: current_user.notifications.delivered_in_system(current_user).where(is_read: false).count + total: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).count, + unread: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).where(is_read: false).count } render :index end def polling @notifications = current_user.notifications - .where('is_read = false AND created_at >= :date', date: params[:last_poll]) - .order('created_at DESC') + .with_valid_notification_type + .where('notifications.is_read = false AND notifications.created_at >= :date', date: params[:last_poll]) + .order('notifications.created_at DESC') @totals = { - total: current_user.notifications.delivered_in_system(current_user).count, - unread: current_user.notifications.delivered_in_system(current_user).where(is_read: false).count + total: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).count, + unread: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).where(is_read: false).count } render :index end diff --git a/app/frontend/src/javascript/components/authentication-provider/openid-connect-form.tsx b/app/frontend/src/javascript/components/authentication-provider/openid-connect-form.tsx index 58fd7041a..467f3cd09 100644 --- a/app/frontend/src/javascript/components/authentication-provider/openid-connect-form.tsx +++ b/app/frontend/src/javascript/components/authentication-provider/openid-connect-form.tsx @@ -34,6 +34,15 @@ export const OpenidConnectForm = (0); + useEffect(() => { + if (!currentFormValues?.extra_authorize_params) { + setValue( + 'providable_attributes.extra_authorize_params' as Path, + '{}' as UnpackNestedValue>> + ); + } + }, []); + // when we have detected a discovery endpoint, we mark it as available useEffect(() => { setValue( @@ -160,6 +169,12 @@ export const OpenidConnectForm = +

{t('app.admin.authentication.openid_connect_form.client_options')}

= ({ action, size, } return handleSubmit((data: User) => { + ['events_reservations', 'space_reservations', 'training_reservations', 'machine_reservations', 'all_projects', 'invoices', 'subscribed_plan', 'subscription'].forEach(key => delete data[key]); MemberAPI[action](data) .then(res => { reset(res); diff --git a/app/frontend/src/javascript/models/authentication-provider.ts b/app/frontend/src/javascript/models/authentication-provider.ts index 6cfebd092..a8c34d63c 100644 --- a/app/frontend/src/javascript/models/authentication-provider.ts +++ b/app/frontend/src/javascript/models/authentication-provider.ts @@ -61,7 +61,8 @@ export interface OpenIdConnectProvider { client__userinfo_endpoint?: string, client__jwks_uri?: string, client__end_session_endpoint?: string, - profile_url?: string + profile_url?: string, + extra_authorize_parameters?: string, } export interface MappingFields { diff --git a/app/frontend/src/javascript/models/notification-type.ts b/app/frontend/src/javascript/models/notification-type.ts index 906320abc..4089b03a1 100644 --- a/app/frontend/src/javascript/models/notification-type.ts +++ b/app/frontend/src/javascript/models/notification-type.ts @@ -74,6 +74,7 @@ export const notificationTypeNames = [ 'notify_user_is_validated', 'notify_user_is_invalidated', 'notify_user_supporting_document_refusal', + 'notify_user_supporting_document_reminder', 'notify_admin_user_supporting_document_refusal', 'notify_user_order_is_ready', 'notify_user_order_is_canceled', diff --git a/app/frontend/src/stylesheets/app.utilities.scss b/app/frontend/src/stylesheets/app.utilities.scss index 999d0ee4d..b69f33737 100644 --- a/app/frontend/src/stylesheets/app.utilities.scss +++ b/app/frontend/src/stylesheets/app.utilities.scss @@ -989,6 +989,11 @@ p, .widget p { cursor: pointer; } +.list-none { + list-style-type: none; + padding-inline-start: 0; +} + @media screen and (min-width: $screen-lg-min) { .b-r-lg { border-right: 1px solid $border-color; diff --git a/app/frontend/templates/admin/statistics/index.html b/app/frontend/templates/admin/statistics/index.html index 2a19a017b..7a85e3f04 100644 --- a/app/frontend/templates/admin/statistics/index.html +++ b/app/frontend/templates/admin/statistics/index.html @@ -288,7 +288,7 @@ {{formatDate(datum._source[field.key])}} -
    +
    • {{elem.name}}
    {{datum._source[field.key]}} diff --git a/app/models/notification.rb b/app/models/notification.rb index e89f36691..dfcc90ac1 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -19,6 +19,8 @@ class Notification < ApplicationRecord SQL } + scope :with_valid_notification_type, -> { joins(:notification_type).where(notification_types: { name: NOTIFICATIONS_TYPES.map { |nt| nt[:name] } }) } + validates :receiver_id, :receiver_type, :attached_object_id, diff --git a/app/models/notification_type.rb b/app/models/notification_type.rb index 135cb513c..b6531b0e7 100644 --- a/app/models/notification_type.rb +++ b/app/models/notification_type.rb @@ -2,7 +2,7 @@ # NotificationType defines the different types of Notification. # To add a new notification type in db, you must add it in: -# - db/seeds/notification_types.rb +# - config/initializers/notification_types.rb # - app/views/api/notifications/_XXXXXX.json.jbuilder # - app/views/notifications_mailer/XXXXXX.html.erb # - app/frontend/src/javascript/models/notification-type.ts diff --git a/app/models/user.rb b/app/models/user.rb index feec3625c..1c5c7643d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -93,6 +93,7 @@ class User < ApplicationRecord scope :not_confirmed, -> { where(confirmed_at: nil) } scope :inactive_for_3_years, -> { where('users.last_sign_in_at < ?', 3.years.ago) } scope :not_validated, -> { where(validated_at: nil) } + scope :supporting_documents_reminder_not_sent, -> { where(supporting_documents_reminder_sent_at: nil) } def to_json(*) ApplicationController.new.view_context.render( diff --git a/app/services/members/members_service.rb b/app/services/members/members_service.rb index 46c8f06da..e84966e12 100644 --- a/app/services/members/members_service.rb +++ b/app/services/members/members_service.rb @@ -27,6 +27,7 @@ class Members::MembersService if @member.validated_at? && !(new_types - current_types).empty? validated_at_changed = true @member.validated_at = nil + @member.supporting_documents_reminder_sent_at = nil end end diff --git a/app/services/statistics/fetcher_service.rb b/app/services/statistics/fetcher_service.rb index d6b3867ed..81e79f287 100644 --- a/app/services/statistics/fetcher_service.rb +++ b/app/services/statistics/fetcher_service.rb @@ -50,7 +50,6 @@ class Statistics::FetcherService .eager_load(:slots, :slots_reservations, :invoice_items, :reservation_context, statistic_profile: [:group]) .find_each do |r| next unless r.reservable - next unless r.original_invoice next if r.slots.empty? profile = r.statistic_profile @@ -63,7 +62,7 @@ class Statistics::FetcherService nb_hours: (r.slots.map(&:duration).map(&:to_i).reduce(:+) / 3600.0).to_f, ca: calcul_ca(r.original_invoice), reservation_context_id: r.reservation_context_id, - coupon: r.original_invoice.coupon&.code }.merge(user_info(profile)) + coupon: r&.original_invoice&.coupon&.code }.merge(user_info(profile)) yield result end end @@ -78,7 +77,6 @@ class Statistics::FetcherService .eager_load(:slots, :slots_reservations, :invoice_items, :reservation_context, statistic_profile: [:group]) .find_each do |r| next unless r.reservable - next unless r.original_invoice next if r.slots.empty? profile = r.statistic_profile @@ -91,7 +89,7 @@ class Statistics::FetcherService nb_hours: (r.slots.map(&:duration).map(&:to_i).reduce(:+) / 3600.0).to_f, ca: calcul_ca(r.original_invoice), reservation_context_id: r.reservation_context_id, - coupon: r.original_invoice.coupon&.code }.merge(user_info(profile)) + coupon: r&.original_invoice&.coupon&.code }.merge(user_info(profile)) yield result end end @@ -106,7 +104,7 @@ class Statistics::FetcherService .eager_load(:slots, :slots_reservations, :invoice_items, :reservation_context, statistic_profile: [:group]) .find_each do |r| next unless r.reservable - next unless r.original_invoice + next if r.slots.empty? profile = r.statistic_profile slot = r.slots.first @@ -119,7 +117,7 @@ class Statistics::FetcherService nb_hours: difference_in_hours(slot.start_at, slot.end_at), ca: calcul_ca(r.original_invoice), reservation_context_id: r.reservation_context_id, - coupon: r.original_invoice&.coupon&.code }.merge(user_info(profile)) + coupon: r&.original_invoice&.coupon&.code }.merge(user_info(profile)) yield result end end @@ -134,7 +132,7 @@ class Statistics::FetcherService .eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group]) .find_each do |r| next unless r.reservable - next unless r.original_invoice + next if r.slots.empty? profile = r.statistic_profile slot = r.slots.first @@ -148,7 +146,7 @@ class Statistics::FetcherService age_range: (r.reservable.age_range_id ? r.reservable.age_range.name : ''), nb_places: r.total_booked_seats, nb_hours: difference_in_hours(slot.start_at, slot.end_at), - coupon: r.original_invoice.coupon&.code, + coupon: r&.original_invoice&.coupon&.code, ca: calcul_ca(r.original_invoice) }.merge(user_info(profile)) yield result end diff --git a/app/views/api/auth_providers/show.json.jbuilder b/app/views/api/auth_providers/show.json.jbuilder index fec6b4e78..44cebfa0b 100644 --- a/app/views/api/auth_providers/show.json.jbuilder +++ b/app/views/api/auth_providers/show.json.jbuilder @@ -16,6 +16,6 @@ if @provider.providable_type == OpenIdConnectProvider.name :prompt, :send_scope_to_token_endpoint, :client__identifier, :client__secret, :client__authorization_endpoint, :client__token_endpoint, :client__userinfo_endpoint, :client__jwks_uri, :client__end_session_endpoint, :profile_url json.scope @provider.providable[:scope] + json.extra_authorize_params @provider.providable[:extra_authorize_params] end end - diff --git a/app/views/api/notifications/_notify_user_supporting_document_reminder.json.jbuilder b/app/views/api/notifications/_notify_user_supporting_document_reminder.json.jbuilder new file mode 100644 index 000000000..279b0fe0a --- /dev/null +++ b/app/views/api/notifications/_notify_user_supporting_document_reminder.json.jbuilder @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +json.title notification.notification_type +json.description t('.reminder_message') diff --git a/app/views/auth_provider/provider.json.jbuilder b/app/views/auth_provider/provider.json.jbuilder index 135f082a5..30bcd2fef 100644 --- a/app/views/auth_provider/provider.json.jbuilder +++ b/app/views/auth_provider/provider.json.jbuilder @@ -16,7 +16,7 @@ if provider.providable_type == 'OpenIdConnectProvider' json.extract! provider.providable, :id, :issuer, :discovery, :client_auth_method, :scope, :response_type, :response_mode, :display, :prompt, :send_scope_to_token_endpoint, :client__identifier, :client__secret, :client__authorization_endpoint, :client__token_endpoint, :client__userinfo_endpoint, :client__jwks_uri, :client__end_session_endpoint, :profile_url, - :post_logout_redirect_uri, :uid_field, :client__redirect_uri, :client__scheme, :client__host, :client__port + :post_logout_redirect_uri, :uid_field, :client__redirect_uri, :client__scheme, :client__host, :client__port, + :extra_authorize_params end end - diff --git a/app/views/notifications_mailer/notify_user_supporting_document_reminder.html.erb b/app/views/notifications_mailer/notify_user_supporting_document_reminder.html.erb new file mode 100644 index 000000000..dfa3ed300 --- /dev/null +++ b/app/views/notifications_mailer/notify_user_supporting_document_reminder.html.erb @@ -0,0 +1,5 @@ +<%= render 'notifications_mailer/shared/hello', recipient: @recipient %> + +

    + <%= t('.body.user_supporting_document_reminder') %> +

    \ No newline at end of file diff --git a/app/workers/supporting_documents_reminder_worker.rb b/app/workers/supporting_documents_reminder_worker.rb new file mode 100644 index 000000000..dfe9ca42c --- /dev/null +++ b/app/workers/supporting_documents_reminder_worker.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# Send a notification to users who did not upload their supporting document files yet +class SupportingDocumentsReminderWorker + include Sidekiq::Worker + + def perform + users_to_notify = User.members + .supporting_documents_reminder_not_sent + .where("users.created_at < ?", 2.days.ago) + .left_outer_joins(supporting_document_files: { supporting_document_type: :groups }) + .where("groups.id = users.group_id OR groups.id IS NULL") + .select("users.*, count(supporting_document_files.id)") + .group("users.id") + .having("(count(supporting_document_files.id)) < (SELECT count(supporting_document_types.id) "\ + "FROM supporting_document_types "\ + "INNER JOIN supporting_document_types_groups "\ + "ON supporting_document_types_groups.supporting_document_type_id = supporting_document_types.id "\ + "WHERE supporting_document_types_groups.group_id = users.group_id)") + users_to_notify.each do |user| + NotificationCenter.call type: 'notify_user_supporting_document_reminder', + receiver: user, + attached_object: user + user.update_column(:supporting_documents_reminder_sent_at, DateTime.current) + end + end +end diff --git a/config/initializers/notification_types.rb b/config/initializers/notification_types.rb new file mode 100644 index 000000000..395928db5 --- /dev/null +++ b/config/initializers/notification_types.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +NOTIFICATIONS_TYPES = [ + { name: 'notify_admin_when_project_published', category: 'projects', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_project_collaborator_to_valid', category: 'projects', is_configurable: false }, + { name: 'notify_project_author_when_collaborator_valid', category: 'projects', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_user_training_valid', category: 'trainings', is_configurable: false }, + { name: 'notify_member_subscribed_plan', category: 'subscriptions', is_configurable: false }, + { name: 'notify_member_create_reservation', category: 'agenda', is_configurable: false }, + { name: 'notify_member_subscribed_plan_is_changed', category: 'deprecated', is_configurable: false }, + { name: 'notify_admin_member_create_reservation', category: 'agenda', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_member_slot_is_modified', category: 'agenda', is_configurable: false }, + { name: 'notify_admin_slot_is_modified', category: 'agenda', is_configurable: true, roles: ['admin', 'manager'] }, + + { name: 'notify_admin_when_user_is_created', category: 'users_accounts', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admin_subscribed_plan', category: 'subscriptions', is_configurable: true, roles: ['admin'] }, + { name: 'notify_user_when_invoice_ready', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_member_subscription_will_expire_in_7_days', category: 'subscriptions', is_configurable: false }, + { name: 'notify_member_subscription_is_expired', category: 'subscriptions', is_configurable: false }, + { name: 'notify_admin_subscription_will_expire_in_7_days', category: 'subscriptions', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admin_subscription_is_expired', category: 'subscriptions', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admin_subscription_canceled', category: 'subscriptions', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_member_subscription_canceled', category: 'subscriptions', is_configurable: false }, + { name: 'notify_user_when_avoir_ready', category: 'wallet', is_configurable: false }, + + { name: 'notify_member_slot_is_canceled', category: 'agenda', is_configurable: false }, + { name: 'notify_admin_slot_is_canceled', category: 'agenda', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_partner_subscribed_plan', category: 'subscriptions', is_configurable: false }, + { name: 'notify_member_subscription_extended', category: 'subscriptions', is_configurable: false }, + { name: 'notify_admin_subscription_extended', category: 'subscriptions', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admin_user_group_changed', category: 'users_accounts', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_user_user_group_changed', category: 'users_accounts', is_configurable: false }, + { name: 'notify_admin_when_user_is_imported', category: 'users_accounts', is_configurable: true, roles: ['admin'] }, + { name: 'notify_user_profile_complete', category: 'users_accounts', is_configurable: false }, + { name: 'notify_user_auth_migration', category: 'user', is_configurable: false }, + + { name: 'notify_admin_user_merged', category: 'users_accounts', is_configurable: true, roles: ['admin'] }, + { name: 'notify_admin_profile_complete', category: 'users_accounts', is_configurable: true, roles: ['admin'] }, + { name: 'notify_admin_abuse_reported', category: 'projects', is_configurable: true, roles: ['admin'] }, + { name: 'notify_admin_invoicing_changed', category: 'deprecated', is_configurable: false }, + { name: 'notify_user_wallet_is_credited', category: 'wallet', is_configurable: false }, + { name: 'notify_admin_user_wallet_is_credited', category: 'wallet', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admin_export_complete', category: 'exports', is_configurable: false }, + { name: 'notify_member_about_coupon', category: 'agenda', is_configurable: false }, + { name: 'notify_member_reservation_reminder', category: 'agenda', is_configurable: false }, + + { name: 'notify_admin_free_disk_space', category: 'app_management', is_configurable: false }, + { name: 'notify_admin_close_period_reminder', category: 'accountings', is_configurable: true, roles: ['admin'] }, + { name: 'notify_admin_archive_complete', category: 'accountings', is_configurable: true, roles: ['admin'] }, + { name: 'notify_privacy_policy_changed', category: 'app_management', is_configurable: false }, + { name: 'notify_admin_import_complete', category: 'app_management', is_configurable: false }, + { name: 'notify_admin_refund_created', category: 'wallet', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admins_role_update', category: 'users_accounts', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_user_role_update', category: 'users_accounts', is_configurable: false }, + { name: 'notify_admin_objects_stripe_sync', category: 'payments', is_configurable: false }, + { name: 'notify_user_when_payment_schedule_ready', category: 'payments', is_configurable: false }, + + { name: 'notify_admin_payment_schedule_failed', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_member_payment_schedule_failed', category: 'payments', is_configurable: false }, + { name: 'notify_admin_payment_schedule_check_deadline', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admin_payment_schedule_transfer_deadline', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admin_payment_schedule_error', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_member_payment_schedule_error', category: 'payments', is_configurable: false }, + { name: 'notify_admin_payment_schedule_gateway_canceled', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_member_payment_schedule_gateway_canceled', category: 'payments', is_configurable: false }, + { name: 'notify_admin_user_supporting_document_files_created', category: 'supporting_documents', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admin_user_supporting_document_files_updated', category: 'supporting_documents', is_configurable: true, roles: ['admin', 'manager'] }, + + { name: 'notify_user_is_validated', category: 'users_accounts', is_configurable: false }, + { name: 'notify_user_is_invalidated', category: 'users_accounts', is_configurable: false }, + { name: 'notify_user_supporting_document_refusal', category: 'supporting_documents', is_configurable: false }, + { name: 'notify_admin_user_supporting_document_refusal', category: 'supporting_documents', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admin_order_is_paid', category: 'shop', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_user_order_is_ready', category: 'shop', is_configurable: false }, + { name: 'notify_user_order_is_canceled', category: 'shop', is_configurable: false }, + { name: 'notify_user_order_is_refunded', category: 'shop', is_configurable: false }, + { name: 'notify_admin_low_stock_threshold', category: 'shop', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_admin_training_auto_cancelled', category: 'trainings', is_configurable: true, roles: ['admin', 'manager'] }, + { name: 'notify_member_training_auto_cancelled', category: 'trainings', is_configurable: false }, + { name: 'notify_user_supporting_document_reminder', category: 'supporting_documents', is_configurable: false } +].freeze diff --git a/config/locales/app.admin.de.yml b/config/locales/app.admin.de.yml index ab649287d..f36a5662a 100644 --- a/config/locales/app.admin.de.yml +++ b/config/locales/app.admin.de.yml @@ -111,6 +111,10 @@ de: save: "Speichern" create_success: "Der Raum wurde erfolgreich erstellt" update_success: "Der Raum wurde erfolgreich aktualisiert" + associated_machines: "Included machines" + children_spaces: "Included spaces" + associated_objects: "Associated objects" + associated_objects_warning: "Only use these fields if you want interblocking reservation between spaces, child spaces and machines. If you want machine and space reservations to remain independent, please leave the following fields blank." event_form: ACTION_title: "{ACTION, select, create{Neue} other{Aktualisiere die}} Veranstaltung" title: "Titel" @@ -1477,6 +1481,8 @@ de: client__jwks_uri: "JWKS URI" client__end_session_endpoint: "End session endpoint" client__end_session_endpoint_help: "The url to call to log the user out at the authorization server." + extra_authorize_params: "Extra authorize parameters" + extra_authorize_params_help: "A hash of extra fixed parameters that will be merged to the authorization request" provider_form: name: "Name" authentication_type: "Authentifizierungsart" diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 543c19cef..a57ff4be8 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1544,6 +1544,8 @@ en: client__jwks_uri: "JWKS URI" client__end_session_endpoint: "End session endpoint" client__end_session_endpoint_help: "The url to call to log the user out at the authorization server." + extra_authorize_params: "Extra authorize parameters" + extra_authorize_params_help: "A hash of extra fixed parameters that will be merged to the authorization request" provider_form: name: "Name" authentication_type: "Authentication type" diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index 8d1d86e92..35f294d4f 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -111,6 +111,10 @@ es: save: "Guardar" create_success: "El espacio se ha creado correctamente" update_success: "El espacio se ha actualizado correctamente" + associated_machines: "Included machines" + children_spaces: "Included spaces" + associated_objects: "Associated objects" + associated_objects_warning: "Only use these fields if you want interblocking reservation between spaces, child spaces and machines. If you want machine and space reservations to remain independent, please leave the following fields blank." event_form: ACTION_title: "{ACTION, select, create{Nuevo} other{Actualiza el}} evento" title: "Título" @@ -1477,6 +1481,8 @@ es: client__jwks_uri: "JWKS URI" client__end_session_endpoint: "Endpoint de fin de sesión" client__end_session_endpoint_help: "La URL a llamar para cerrar la sesión del usuario en el servidor de autorización." + extra_authorize_params: "Extra authorize parameters" + extra_authorize_params_help: "A hash of extra fixed parameters that will be merged to the authorization request" provider_form: name: "Nombre" authentication_type: "Tipo de autenticación" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 26830c543..9e17f9374 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -111,10 +111,10 @@ fr: save: "Enregistrer" create_success: "L'espace a bien été créé" update_success: "L'espace a bien été mis à jour" - associated_machines: "Machines" - children_spaces: "Espaces" - associated_objects: "Machines et sous-espaces" - associated_objects_warning: "Utilisez ces champs uniquement si vous souhaitez que la réservation de l'espace bloque la réservation des machines associées et des sous-espaces (et vice-versa). Si vous souhaitez que les réservations restent indépendantes, veuillez laisser les champs suivants vides." + associated_machines: "Machines incluses" + children_spaces: "Espaces inclus" + associated_objects: "Objet associé" + associated_objects_warning: "Utilisez uniquement ces champs si vous souhaitez une réservation d'interblocage entre les espaces, les sous-espaces et les machines. Si vous voulez que les réservations de machines et d'espaces restent indépendantes, veuillez laisser les champs suivants vides." event_form: ACTION_title: "{ACTION, select, create{Nouvel } other{Mettre à jour l''}}événement" title: "Titre" @@ -1536,6 +1536,8 @@ fr: client__jwks_uri: "URI JWKS" client__end_session_endpoint: "Point d'accès pour terminer la session" client__end_session_endpoint_help: "L'url à appeler pour déconnecter l'utilisateur sur le serveur d'autorisation." + extra_authorize_params: "Paramètres d'autorisation supplémentaires" + extra_authorize_params_help: "Un hachage de paramètres supplémentaires fixes qui seront fusionnés à la demande d'autorisation" provider_form: name: "Nom" authentication_type: "Type d'authentification" diff --git a/config/locales/app.admin.it.yml b/config/locales/app.admin.it.yml index 70153af11..258a6fbe5 100644 --- a/config/locales/app.admin.it.yml +++ b/config/locales/app.admin.it.yml @@ -111,6 +111,10 @@ it: save: "Salva" create_success: "Lo spazio è stato creato correttamente" update_success: "Lo spazio è stato aggiornato correttamente" + associated_machines: "Included machines" + children_spaces: "Included spaces" + associated_objects: "Associated objects" + associated_objects_warning: "Only use these fields if you want interblocking reservation between spaces, child spaces and machines. If you want machine and space reservations to remain independent, please leave the following fields blank." event_form: ACTION_title: "{ACTION, select, create{Nuovo} other{Aggiorna}} evento" title: "Titolo" @@ -1477,6 +1481,8 @@ it: client__jwks_uri: "JWKS URI" client__end_session_endpoint: "Endpoint di fine sessione" client__end_session_endpoint_help: "L'url da chiamare per effettuare il log out dell'utente al server di autorizzazione." + extra_authorize_params: "Extra authorize parameters" + extra_authorize_params_help: "A hash of extra fixed parameters that will be merged to the authorization request" provider_form: name: "Nome" authentication_type: "Tipo di autenticazione" diff --git a/config/locales/app.admin.no.yml b/config/locales/app.admin.no.yml index 094c426d0..708ece1ca 100644 --- a/config/locales/app.admin.no.yml +++ b/config/locales/app.admin.no.yml @@ -111,6 +111,10 @@ save: "Save" create_success: "The space was created successfully" update_success: "The space was updated successfully" + associated_machines: "Included machines" + children_spaces: "Included spaces" + associated_objects: "Associated objects" + associated_objects_warning: "Only use these fields if you want interblocking reservation between spaces, child spaces and machines. If you want machine and space reservations to remain independent, please leave the following fields blank." event_form: ACTION_title: "{ACTION, select, create{New} other{Update the}} event" title: "Title" @@ -1477,6 +1481,8 @@ client__jwks_uri: "JWKS URI" client__end_session_endpoint: "End session endpoint" client__end_session_endpoint_help: "The url to call to log the user out at the authorization server." + extra_authorize_params: "Extra authorize parameters" + extra_authorize_params_help: "A hash of extra fixed parameters that will be merged to the authorization request" provider_form: name: "Name" authentication_type: "Authentication type" diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index 5c64afd23..680842515 100644 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -111,6 +111,10 @@ pt: save: "Save" create_success: "The space was created successfully" update_success: "The space was updated successfully" + associated_machines: "Included machines" + children_spaces: "Included spaces" + associated_objects: "Associated objects" + associated_objects_warning: "Only use these fields if you want interblocking reservation between spaces, child spaces and machines. If you want machine and space reservations to remain independent, please leave the following fields blank." event_form: ACTION_title: "{ACTION, select, create{New} other{Update the}} event" title: "Title" @@ -1477,6 +1481,8 @@ pt: client__jwks_uri: "JWKS URI" client__end_session_endpoint: "Endpoint de término de sessão" client__end_session_endpoint_help: "O Url para efetuar uma chamada para desconectar o usuário no servidor de autorização." + extra_authorize_params: "Extra authorize parameters" + extra_authorize_params_help: "A hash of extra fixed parameters that will be merged to the authorization request" provider_form: name: "Nome" authentication_type: "Tipo de autenticação" diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index b212ea06e..257ec281c 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -111,6 +111,10 @@ zu: save: "crwdns36885:0crwdne36885:0" create_success: "crwdns31813:0crwdne31813:0" update_success: "crwdns31815:0crwdne31815:0" + associated_machines: "crwdns37729:0crwdne37729:0" + children_spaces: "crwdns37731:0crwdne37731:0" + associated_objects: "crwdns37733:0crwdne37733:0" + associated_objects_warning: "crwdns37735:0crwdne37735:0" event_form: ACTION_title: "crwdns36887:0ACTION={ACTION}crwdne36887:0" title: "crwdns31817:0crwdne31817:0" @@ -1477,6 +1481,8 @@ zu: client__jwks_uri: "crwdns26198:0crwdne26198:0" client__end_session_endpoint: "crwdns26200:0crwdne26200:0" client__end_session_endpoint_help: "crwdns26202:0crwdne26202:0" + extra_authorize_params: "crwdns37725:0crwdne37725:0" + extra_authorize_params_help: "crwdns37727:0crwdne37727:0" provider_form: name: "crwdns26204:0crwdne26204:0" authentication_type: "crwdns26206:0crwdne26206:0" diff --git a/config/locales/app.public.fr.yml b/config/locales/app.public.fr.yml index 83355a75a..ea7ca1246 100644 --- a/config/locales/app.public.fr.yml +++ b/config/locales/app.public.fr.yml @@ -100,7 +100,7 @@ fr: _the_fablab_policy: "les conditions d'utilisation" field_required: "Champ requis" profile_custom_field_is_required: "{FEILD} est requis" - user_supporting_documents_required: "Attention !
    Vous avez déclarez être \"{GROUP}\", des pièces justificatives pourront vous être demandées." + user_supporting_documents_required: "Attention !
    Vous avez déclaré être \"{GROUP}\", des pièces justificatives pourront vous être demandées." unexpected_error_occurred: "Une erreur inattendue s'est produite. Veuillez réessayer ultérieurement." used_for_statistics: "Cette donnée sera utilisée à des fins statistiques" used_for_invoicing: "Cette donnée sera utilisée à des fins de facturation" diff --git a/config/locales/de.yml b/config/locales/de.yml index 101773e34..a91036804 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -65,6 +65,7 @@ de: not_available: "Nicht verfügbar" reserving: "Ich reserviere" i_ve_reserved: "Ich reservierte" + blocked: "Blocked" length_must_be_slot_multiple: "muss mindestens %{MIN} Minuten nach dem Startdatum liegen" must_be_associated_with_at_least_1_machine: "muss mindestens einer Maschine zugeordnet sein" deleted_user: "Gelöschte Benutzer" @@ -446,6 +447,8 @@ de: account_invalidated: "Dein Account ist ungültig." notify_user_supporting_document_refusal: refusal: "Your supporting documents were refused" + notify_user_supporting_document_reminder: + reminder_message: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: refusal: "Member's supporting document %{NAME} was refused." notify_user_order_is_ready: @@ -538,6 +541,7 @@ de: space: "Dieser Space ist deaktiviert" machine: "Diese Maschine ist deaktiviert" reservable: "Diese Maschine ist nicht reservierbar" + blocked_by_another_reservation: "This slot is blocked by another reservation" cart_validation: select_user: "Please select a user before continuing" settings: diff --git a/config/locales/en.yml b/config/locales/en.yml index 95fbc9588..7596607d5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -462,6 +462,8 @@ en: child_invalidated: "Your account child is invalid." notify_user_supporting_document_refusal: refusal: "Your supporting documents were refused" + notify_user_supporting_document_reminder: + reminder_message: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: refusal: "Member's supporting document %{NAME} was refused." notify_user_child_supporting_document_refusal: diff --git a/config/locales/es.yml b/config/locales/es.yml index b1f1918ec..637a2c531 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -65,6 +65,7 @@ es: not_available: "No disponible" reserving: "Me reservo" i_ve_reserved: "He reservado" + blocked: "Blocked" length_must_be_slot_multiple: "Debe ser al menos %{MIN} minutos después de la fecha de inicio" must_be_associated_with_at_least_1_machine: "debe estar asociado con al menos 1 máquina" deleted_user: "Usuario eliminado" @@ -446,6 +447,8 @@ es: account_invalidated: "Su cuenta no es válida." notify_user_supporting_document_refusal: refusal: "Sus justificantes han sido rechazados" + notify_user_supporting_document_reminder: + reminder_message: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: refusal: "El justificante del afiliado %{NAME} ha sido rechazado." notify_user_order_is_ready: @@ -538,6 +541,7 @@ es: space: "Este espacio está desactivado" machine: "Esta máquina está desactivada" reservable: "Esta máquina no se puede reservar" + blocked_by_another_reservation: "This slot is blocked by another reservation" cart_validation: select_user: "Por favor, seleccione un usuario antes de continuar" settings: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 07194ad5b..8c8ad30fd 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -66,7 +66,7 @@ fr: not_available: "Non disponible" reserving: "Je réserve" i_ve_reserved: "J'ai réservé" - blocked: "Bloquée" + blocked: "Bloqué" length_must_be_slot_multiple: "doit être au moins %{MIN} minutes après la date de début" must_be_associated_with_at_least_1_machine: "doit être associé avec au moins 1 machine" deleted_user: "Utilisateur supprimé" @@ -462,6 +462,8 @@ fr: child_invalidated: "Votre compte enfant est invalide." notify_user_supporting_document_refusal: refusal: "Vos pièces justificatives ont été refusées" + notify_user_supporting_document_reminder: + reminder_message: "Ceci est un rappel pour vous demander de télécharger vos documents justificatifs." notify_admin_user_supporting_document_refusal: refusal: "Le justificatif du membre %{NAME} a été refusé." notify_user_child_supporting_document_refusal: diff --git a/config/locales/it.yml b/config/locales/it.yml index 5e3cd0173..106244325 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -65,6 +65,7 @@ it: not_available: "Non disponibile" reserving: "Sto prenotando" i_ve_reserved: "Ho prenotato" + blocked: "Blocked" length_must_be_slot_multiple: "deve essere almeno %{MIN} minuti dopo la data di inizio" must_be_associated_with_at_least_1_machine: "deve essere associata ad almeno 1 macchina" deleted_user: "Utente eliminato" @@ -446,6 +447,8 @@ it: account_invalidated: "Il tuo account non è valido." notify_user_supporting_document_refusal: refusal: "I tuoi documenti aggiuntivi sono stati rifiutati" + notify_user_supporting_document_reminder: + reminder_message: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: refusal: "Il documento aggiuntivo del membro %{NAME} è stato rifiutato." notify_user_order_is_ready: @@ -538,6 +541,7 @@ it: space: "Questo spazio è disabilitato" machine: "Questa macchina è disabilitata" reservable: "Questa macchina non è prenotabile" + blocked_by_another_reservation: "This slot is blocked by another reservation" cart_validation: select_user: "Seleziona un utente prima di continuare" settings: diff --git a/config/locales/mails.de.yml b/config/locales/mails.de.yml index 0d29d6ec9..1ca61c7c1 100644 --- a/config/locales/mails.de.yml +++ b/config/locales/mails.de.yml @@ -402,6 +402,10 @@ de: body: user_supporting_document_files_refusal: "Your supporting documents were refused:" action: "Please re-upload some new supporting documents." + notify_user_supporting_document_reminder: + subject: "Reminder to upload your supporting documents" + body: + user_supporting_document_reminder: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: subject: "A member's supporting documents were refused" body: diff --git a/config/locales/mails.en.yml b/config/locales/mails.en.yml index 20f6bc39d..5a66d9098 100644 --- a/config/locales/mails.en.yml +++ b/config/locales/mails.en.yml @@ -434,6 +434,10 @@ en: body: user_supporting_document_files_refusal: "Your supporting documents were refused:" action: "Please re-upload some new supporting documents." + notify_user_supporting_document_reminder: + subject: "Reminder to upload your supporting documents" + body: + user_supporting_document_reminder: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: subject: "A member's supporting documents were refused" body: diff --git a/config/locales/mails.es.yml b/config/locales/mails.es.yml index 8d2d6f563..7f1406c21 100644 --- a/config/locales/mails.es.yml +++ b/config/locales/mails.es.yml @@ -402,6 +402,10 @@ es: body: user_supporting_document_files_refusal: "Sus justificantes han sido rechazados:" action: "Por favor, vuelva a subir nuevos documentos justificativos." + notify_user_supporting_document_reminder: + subject: "Reminder to upload your supporting documents" + body: + user_supporting_document_reminder: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: subject: "Los justificantes del afiliado de un miembro han sido rechazados" body: diff --git a/config/locales/mails.fr.yml b/config/locales/mails.fr.yml index d96269518..e4f2ef4bf 100644 --- a/config/locales/mails.fr.yml +++ b/config/locales/mails.fr.yml @@ -434,6 +434,10 @@ fr: body: user_supporting_document_files_refusal: "Vos pièces justificatives ont été refusées :" action: "Veuillez téléverser de nouvelles pièces justificatives." + notify_user_supporting_document_reminder: + subject: "Rappel de télécharger vos documents justificatifs" + body: + user_supporting_document_reminder: "Ceci est un rappel pour vous demander de télécharger vos documents justificatifs." notify_admin_user_supporting_document_refusal: subject: "Les justificatifs d'un membre ont été refusés" body: diff --git a/config/locales/mails.it.yml b/config/locales/mails.it.yml index c0d842a27..1b17ef14b 100644 --- a/config/locales/mails.it.yml +++ b/config/locales/mails.it.yml @@ -402,6 +402,10 @@ it: body: user_supporting_document_files_refusal: "I tuoi documenti aggiuntivi sono stati rifiutati:" action: "Si prega di ricaricare nuovi documenti di supporto." + notify_user_supporting_document_reminder: + subject: "Reminder to upload your supporting documents" + body: + user_supporting_document_reminder: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: subject: "I documenti aggiuntivi di un membro sono stati rifiutati" body: diff --git a/config/locales/mails.no.yml b/config/locales/mails.no.yml index a4ed1ec5e..4d69e9d83 100644 --- a/config/locales/mails.no.yml +++ b/config/locales/mails.no.yml @@ -402,6 +402,10 @@ body: user_supporting_document_files_refusal: "Your supporting documents were refused:" action: "Please re-upload some new supporting documents." + notify_user_supporting_document_reminder: + subject: "Reminder to upload your supporting documents" + body: + user_supporting_document_reminder: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: subject: "A member's supporting documents were refused" body: diff --git a/config/locales/mails.pt.yml b/config/locales/mails.pt.yml index 99eb43143..c1408a120 100644 --- a/config/locales/mails.pt.yml +++ b/config/locales/mails.pt.yml @@ -402,6 +402,10 @@ pt: body: user_supporting_document_files_refusal: "Os seus documentos de apoio foram recusados:" action: "Por favor, recarregue novos documentos de apoio." + notify_user_supporting_document_reminder: + subject: "Reminder to upload your supporting documents" + body: + user_supporting_document_reminder: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: subject: "Documentos de apoio de um membro foram recusados" body: diff --git a/config/locales/mails.zu.yml b/config/locales/mails.zu.yml index 6aca672d6..7d831a98e 100644 --- a/config/locales/mails.zu.yml +++ b/config/locales/mails.zu.yml @@ -402,6 +402,10 @@ zu: body: user_supporting_document_files_refusal: "crwdns37363:0crwdne37363:0" action: "crwdns37365:0crwdne37365:0" + notify_user_supporting_document_reminder: + subject: "crwdns37743:0crwdne37743:0" + body: + user_supporting_document_reminder: "crwdns37745:0crwdne37745:0" notify_admin_user_supporting_document_refusal: subject: "crwdns37367:0crwdne37367:0" body: diff --git a/config/locales/no.yml b/config/locales/no.yml index 3ea449d2f..22e5e5c53 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -65,6 +65,7 @@ not_available: "Ikke tilgjengelig" reserving: "I'm reserving" i_ve_reserved: "Jeg har reservert" + blocked: "Blocked" length_must_be_slot_multiple: "må være minst %{MIN} minutter etter startdatoen" must_be_associated_with_at_least_1_machine: "må være tilknyttet minst 1 maskin" deleted_user: "Deleted user" @@ -446,6 +447,8 @@ account_invalidated: "Your account is invalid." notify_user_supporting_document_refusal: refusal: "Your supporting documents were refused" + notify_user_supporting_document_reminder: + reminder_message: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: refusal: "Member's supporting document %{NAME} was refused." notify_user_order_is_ready: @@ -538,6 +541,7 @@ space: "This space is disabled" machine: "This machine is disabled" reservable: "This machine is not reservable" + blocked_by_another_reservation: "This slot is blocked by another reservation" cart_validation: select_user: "Please select a user before continuing" settings: diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 1c02c1c9a..584a3b76c 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -65,6 +65,7 @@ pt: not_available: "Não disponível " reserving: "I'm reserving" i_ve_reserved: "Eu reservei" + blocked: "Blocked" length_must_be_slot_multiple: "deve ser pelo menos %{MIN} minutos após a data de início" must_be_associated_with_at_least_1_machine: "deve estar associada a pelo menos uma máquina" deleted_user: "Usuário deletado" @@ -446,6 +447,8 @@ pt: account_invalidated: "Sua conta é inválida." notify_user_supporting_document_refusal: refusal: "Your supporting documents were refused" + notify_user_supporting_document_reminder: + reminder_message: "This is a reminder for you to upload your supporting documents." notify_admin_user_supporting_document_refusal: refusal: "Member's supporting document %{NAME} was refused." notify_user_order_is_ready: @@ -538,6 +541,7 @@ pt: space: "Este espaço está desativado" machine: "Esta máquina está desativada" reservable: "Esta máquina não é reservável" + blocked_by_another_reservation: "This slot is blocked by another reservation" cart_validation: select_user: "Por favor, selecione um usuário antes de continuar" settings: diff --git a/config/locales/zu.yml b/config/locales/zu.yml index 9e9b08728..5d4ed4b32 100644 --- a/config/locales/zu.yml +++ b/config/locales/zu.yml @@ -65,6 +65,7 @@ zu: not_available: "crwdns3267:0crwdne3267:0" reserving: "crwdns37199:0crwdne37199:0" i_ve_reserved: "crwdns3269:0crwdne3269:0" + blocked: "crwdns37737:0crwdne37737:0" length_must_be_slot_multiple: "crwdns3271:0%{MIN}crwdne3271:0" must_be_associated_with_at_least_1_machine: "crwdns3273:0crwdne3273:0" deleted_user: "crwdns22460:0crwdne22460:0" @@ -446,6 +447,8 @@ zu: account_invalidated: "crwdns23006:0crwdne23006:0" notify_user_supporting_document_refusal: refusal: "crwdns37345:0crwdne37345:0" + notify_user_supporting_document_reminder: + reminder_message: "crwdns37739:0crwdne37739:0" notify_admin_user_supporting_document_refusal: refusal: "crwdns37347:0%{NAME}crwdne37347:0" notify_user_order_is_ready: @@ -538,6 +541,7 @@ zu: space: "crwdns36283:0crwdne36283:0" machine: "crwdns36285:0crwdne36285:0" reservable: "crwdns36287:0crwdne36287:0" + blocked_by_another_reservation: "crwdns37741:0crwdne37741:0" cart_validation: select_user: "crwdns37211:0crwdne37211:0" settings: diff --git a/config/schedule.yml b/config/schedule.yml index 93b45c9e9..988dcd45d 100644 --- a/config/schedule.yml +++ b/config/schedule.yml @@ -62,6 +62,10 @@ auto_cancel_authorizations: class: TrainingAuthorizationWorker queue: default +supporting_documents_reminder_worker: + cron: "0 8 * * *" # every day, at 8 + class: SupportingDocumentsReminderWorker + child_age_will_be_18: cron: "0 0 0 * * *" # every day, at midnight class: ChildAgeWorker diff --git a/db/migrate/20230901090637_add_supporting_documents_reminder_sent_at_to_users.rb b/db/migrate/20230901090637_add_supporting_documents_reminder_sent_at_to_users.rb new file mode 100644 index 000000000..d7842242e --- /dev/null +++ b/db/migrate/20230901090637_add_supporting_documents_reminder_sent_at_to_users.rb @@ -0,0 +1,5 @@ +class AddSupportingDocumentsReminderSentAtToUsers < ActiveRecord::Migration[7.0] + def change + add_column :users, :supporting_documents_reminder_sent_at, :datetime + end +end diff --git a/db/migrate/20230907124230_add_extra_authorize_params_to_open_id_connect_provider.rb b/db/migrate/20230907124230_add_extra_authorize_params_to_open_id_connect_provider.rb new file mode 100644 index 000000000..6c8b84052 --- /dev/null +++ b/db/migrate/20230907124230_add_extra_authorize_params_to_open_id_connect_provider.rb @@ -0,0 +1,5 @@ +class AddExtraAuthorizeParamsToOpenIdConnectProvider < ActiveRecord::Migration[7.0] + def change + add_column :open_id_connect_providers, :extra_authorize_params, :jsonb, default: {} + end +end diff --git a/db/seeds/notification_types.rb b/db/seeds/notification_types.rb index 936595948..9308d897f 100644 --- a/db/seeds/notification_types.rb +++ b/db/seeds/notification_types.rb @@ -1,104 +1,5 @@ # frozen_string_literal: true -NOTIFICATIONS_TYPES = [ - { name: 'notify_admin_when_project_published', category: 'projects', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_project_collaborator_to_valid', category: 'projects', is_configurable: false }, - { name: 'notify_project_author_when_collaborator_valid', category: 'projects', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_user_training_valid', category: 'trainings', is_configurable: false }, - { name: 'notify_member_subscribed_plan', category: 'subscriptions', is_configurable: false }, - { name: 'notify_member_create_reservation', category: 'agenda', is_configurable: false }, - { name: 'notify_member_subscribed_plan_is_changed', category: 'deprecated', is_configurable: false }, - { name: 'notify_admin_member_create_reservation', category: 'agenda', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_member_slot_is_modified', category: 'agenda', is_configurable: false }, - { name: 'notify_admin_slot_is_modified', category: 'agenda', is_configurable: true, roles: ['admin', 'manager'] }, - - { name: 'notify_admin_when_user_is_created', category: 'users_accounts', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_subscribed_plan', category: 'subscriptions', is_configurable: true, roles: ['admin'] }, - { name: 'notify_user_when_invoice_ready', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_member_subscription_will_expire_in_7_days', category: 'subscriptions', is_configurable: false }, - { name: 'notify_member_subscription_is_expired', category: 'subscriptions', is_configurable: false }, - { name: 'notify_admin_subscription_will_expire_in_7_days', category: 'subscriptions', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_subscription_is_expired', category: 'subscriptions', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_subscription_canceled', category: 'subscriptions', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_member_subscription_canceled', category: 'subscriptions', is_configurable: false }, - { name: 'notify_user_when_avoir_ready', category: 'wallet', is_configurable: false }, - - { name: 'notify_member_slot_is_canceled', category: 'agenda', is_configurable: false }, - { name: 'notify_admin_slot_is_canceled', category: 'agenda', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_partner_subscribed_plan', category: 'subscriptions', is_configurable: false }, - { name: 'notify_member_subscription_extended', category: 'subscriptions', is_configurable: false }, - { name: 'notify_admin_subscription_extended', category: 'subscriptions', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_user_group_changed', category: 'users_accounts', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_user_user_group_changed', category: 'users_accounts', is_configurable: false }, - { name: 'notify_admin_when_user_is_imported', category: 'users_accounts', is_configurable: true, roles: ['admin'] }, - { name: 'notify_user_profile_complete', category: 'users_accounts', is_configurable: false }, - { name: 'notify_user_auth_migration', category: 'user', is_configurable: false }, - - { name: 'notify_admin_user_merged', category: 'users_accounts', is_configurable: true, roles: ['admin'] }, - { name: 'notify_admin_profile_complete', category: 'users_accounts', is_configurable: true, roles: ['admin'] }, - { name: 'notify_admin_abuse_reported', category: 'projects', is_configurable: true, roles: ['admin'] }, - { name: 'notify_admin_invoicing_changed', category: 'deprecated', is_configurable: false }, - { name: 'notify_user_wallet_is_credited', category: 'wallet', is_configurable: false }, - { name: 'notify_admin_user_wallet_is_credited', category: 'wallet', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_export_complete', category: 'exports', is_configurable: false }, - { name: 'notify_member_about_coupon', category: 'agenda', is_configurable: false }, - { name: 'notify_member_reservation_reminder', category: 'agenda', is_configurable: false }, - - { name: 'notify_admin_free_disk_space', category: 'app_management', is_configurable: false }, - { name: 'notify_admin_close_period_reminder', category: 'accountings', is_configurable: true, roles: ['admin'] }, - { name: 'notify_admin_archive_complete', category: 'accountings', is_configurable: true, roles: ['admin'] }, - { name: 'notify_privacy_policy_changed', category: 'app_management', is_configurable: false }, - { name: 'notify_admin_import_complete', category: 'app_management', is_configurable: false }, - { name: 'notify_admin_refund_created', category: 'wallet', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admins_role_update', category: 'users_accounts', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_user_role_update', category: 'users_accounts', is_configurable: false }, - { name: 'notify_admin_objects_stripe_sync', category: 'payments', is_configurable: false }, - { name: 'notify_user_when_payment_schedule_ready', category: 'payments', is_configurable: false }, - - { name: 'notify_admin_payment_schedule_failed', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_member_payment_schedule_failed', category: 'payments', is_configurable: false }, - { name: 'notify_admin_payment_schedule_check_deadline', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_payment_schedule_transfer_deadline', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_payment_schedule_error', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_member_payment_schedule_error', category: 'payments', is_configurable: false }, - { name: 'notify_admin_payment_schedule_gateway_canceled', category: 'payments', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_member_payment_schedule_gateway_canceled', category: 'payments', is_configurable: false }, - { name: 'notify_admin_user_supporting_document_files_created', category: 'supporting_documents', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_user_supporting_document_files_updated', category: 'supporting_documents', is_configurable: true, roles: ['admin', 'manager'] }, - - { name: 'notify_user_is_validated', category: 'users_accounts', is_configurable: false }, - { name: 'notify_user_is_invalidated', category: 'users_accounts', is_configurable: false }, - { name: 'notify_user_supporting_document_refusal', category: 'supporting_documents', is_configurable: false }, - { name: 'notify_admin_user_supporting_document_refusal', category: 'supporting_documents', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_order_is_paid', category: 'shop', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_user_order_is_ready', category: 'shop', is_configurable: false }, - { name: 'notify_user_order_is_canceled', category: 'shop', is_configurable: false }, - { name: 'notify_user_order_is_refunded', category: 'shop', is_configurable: false }, - { name: 'notify_admin_low_stock_threshold', category: 'shop', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_training_auto_cancelled', category: 'trainings', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_member_training_auto_cancelled', category: 'trainings', is_configurable: false }, - - { name: 'notify_member_training_authorization_expired', category: 'trainings', is_configurable: false }, - { name: 'notify_member_training_invalidated', category: 'trainings', is_configurable: false }, - { name: 'notify_member_reservation_limit_reached', category: 'agenda', is_configurable: false }, - { name: 'notify_admin_user_child_supporting_document_refusal', category: 'supporting_documents', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_user_child_supporting_document_refusal', category: 'supporting_documents', is_configurable: false }, - { name: 'notify_admin_child_created', category: 'users_accounts', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_user_child_is_validated', category: 'users_accounts', is_configurable: false }, - { name: 'notify_user_child_is_invalidated', category: 'users_accounts', is_configurable: false }, - { name: 'notify_admin_user_child_supporting_document_files_updated', category: 'supporting_documents', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_admin_user_child_supporting_document_files_created', category: 'supporting_documents', is_configurable: true, roles: ['admin', 'manager'] }, - - { name: 'notify_member_reservation_validated', category: 'agenda', is_configurable: false }, - { name: 'notify_admin_reservation_validated', category: 'agenda', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_member_pre_booked_reservation', category: 'agenda', is_configurable: false }, - { name: 'notify_admin_member_pre_booked_reservation', category: 'agenda', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_member_reservation_invalidated', category: 'agenda', is_configurable: false }, - { name: 'notify_admin_reservation_invalidated', category: 'agenda', is_configurable: true, roles: ['admin', 'manager'] }, - { name: 'notify_user_when_child_age_will_be_18', category: 'users_accounts', is_configurable: false } - -].freeze - NOTIFICATIONS_TYPES.each do |notification_type_attrs| notification_type = NotificationType.find_by(name: notification_type_attrs[:name]) diff --git a/db/structure.sql b/db/structure.sql index 7ff9441d9..81acd320f 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -2039,7 +2039,8 @@ CREATE TABLE public.open_id_connect_providers ( client__end_session_endpoint character varying, profile_url character varying, created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + updated_at timestamp without time zone NOT NULL, + extra_authorize_params jsonb DEFAULT '{}'::jsonb ); @@ -4354,7 +4355,8 @@ CREATE TABLE public.users ( current_sign_in_ip inet, last_sign_in_ip inet, validated_at timestamp without time zone, - mapped_from_sso character varying + mapped_from_sso character varying, + supporting_documents_reminder_sent_at timestamp(6) without time zone ); @@ -9261,6 +9263,8 @@ INSERT INTO "schema_migrations" (version) VALUES ('20230728090257'), ('20230825101952'), ('20230828073428'), -('20230831103208'); +('20230831103208'), +('20230901090637'), +('20230907124230'); diff --git a/package.json b/package.json index e9d45480c..fb7e247d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fab-manager", - "version": "6.0.13", + "version": "6.0.14", "description": "Fab-manager is the FabLab management solution. It provides a comprehensive, web-based, open-source tool to simplify your administrative tasks and your marker's projects.", "keywords": [ "fablab", diff --git a/test/fixtures/notification_types.yml b/test/fixtures/notification_types.yml index 81d3715ea..c7fa28b4e 100644 --- a/test/fixtures/notification_types.yml +++ b/test/fixtures/notification_types.yml @@ -607,3 +607,11 @@ notification_type_72: is_configurable: false created_at: 2023-02-16 10:42:39.143888000 Z updated_at: 2023-02-16 10:42:39.143888000 Z + +notification_type_73: + id: 73 + name: notify_user_supporting_document_reminder + category: supporting_documents + is_configurable: false + created_at: 2023-02-02 08:25:33.439078000 Z + updated_at: 2023-02-02 08:25:33.439078000 Z \ No newline at end of file diff --git a/test/integration/notifications/notifications_test.rb b/test/integration/notifications/notifications_test.rb index 69b6ce9d2..840573fd5 100644 --- a/test/integration/notifications/notifications_test.rb +++ b/test/integration/notifications/notifications_test.rb @@ -39,6 +39,21 @@ class NotificationsTest < ActionDispatch::IntegrationTest assert_equal (Notification.where(receiver_id: @admin.id).count - 1), notifications_total end + test 'polling endpoint' do + @admin = User.find_by(username: 'admin') + login_as(@admin, scope: :user) + + get '/api/notifications/polling', params: { last_poll: Notification.order(:created_at).pick(:created_at) } + + # Check response format & status + assert_equal 200, response.status, response.body + assert_match Mime[:json].to_s, response.content_type + + # Check the list items are ok + notifications_total = json_response(response.body)[:totals][:total] + assert_not_equal notifications.count, 0 + end + test 'Last unread returns last 3 unread notifications' do @member = User.find(4) login_as(@member, scope: :user) diff --git a/test/workers/supporting_documents_reminder_worker_test.rb b/test/workers/supporting_documents_reminder_worker_test.rb new file mode 100644 index 000000000..a8be8c007 --- /dev/null +++ b/test/workers/supporting_documents_reminder_worker_test.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +require 'test_helper' +require 'minitest/autorun' +#require 'sidekiq/testing' + +class SupportingDocumentsReminderWorkerTest < ActiveSupport::TestCase + include ActionMailer::TestHelper + setup do + @worker = SupportingDocumentsReminderWorker.new + + group = groups(:group_1) + @users = User.where(group_id: group.id).members + @supporting_document_type_1 = SupportingDocumentType.create!(name: "doc1", groups: [group]) + @supporting_document_type_2 = SupportingDocumentType.create!(name: "doc2", groups: [group]) + end + + test 'do nothing if it concerns another group' do + group = Group.create!(name: 'test', slug: 'test') + SupportingDocumentType.destroy_all + supporting_document_type = SupportingDocumentType.create!(name: "doc3", groups: [group]) + + @users.each do |user| + assert_nil user.supporting_documents_reminder_sent_at + end + assert_enqueued_emails 0 do + @worker.perform + end + @users.reload.each do |user| + assert_nil user.supporting_documents_reminder_sent_at + end + end + + test 'notify every users who did not upload supporting document files' do + @users.each do |user| + assert_nil user.supporting_documents_reminder_sent_at + end + + assert_enqueued_emails @users.length do + @worker.perform + end + + @users.reload.each do |user| + assert user.supporting_documents_reminder_sent_at + end + + assert_enqueued_emails 0 do + @worker.perform + end + end + + test 'notify users even if they have uploaded 1 document of the 2' do + @users.each do |user| + user.supporting_document_files.create!(supporting_document_type: @supporting_document_type_1, + attachment: fixture_file_upload('document.pdf')) + end + + assert_enqueued_emails @users.length do + @worker.perform + end + end + + test 'do not notify users if they have uploaded all documents' do + @users.each do |user| + user.supporting_document_files.create!(supporting_document_type: @supporting_document_type_1, + attachment: fixture_file_upload('document.pdf')) + user.supporting_document_files.create!(supporting_document_type: @supporting_document_type_2, + attachment: fixture_file_upload('document.pdf')) + end + + assert_enqueued_emails 0 do + @worker.perform + end + end + + test 'do not notify users if they were created too recently' do + @users.update_all(created_at: 2.minutes.ago) + + assert_enqueued_emails 0 do + @worker.perform + end + end +end