1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-22 11:52:21 +01:00

Merge branch 'dev' into staging

This commit is contained in:
Du Peng 2023-09-11 18:18:37 +02:00
commit 19b6bd8d8a
54 changed files with 409 additions and 132 deletions

View File

@ -2,9 +2,16 @@
## next deploy ## 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: 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 update status to paid for latest payment schedule item
- Fix a bug: unable to generate statistic - 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 - Feature: add a filter in members list (admin) to show only "not validated" members
- Concerning statistics: - Concerning statistics:
- removes age and type column from all statistics tabs (only in web, not in xlsx export file) - removes age and type column from all statistics tabs (only in web, not in xlsx export file)

View File

@ -99,7 +99,7 @@ class API::AuthProvidersController < API::APIController
providable_attributes: [:id, :issuer, :discovery, :client_auth_method, :prompt, :send_scope_to_token_endpoint, 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__identifier, :client__secret, :client__authorization_endpoint, :client__token_endpoint,
:client__userinfo_endpoint, :client__jwks_uri, :client__end_session_endpoint, :profile_url, :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, auth_provider_mappings_attributes: [:id, :local_model, :local_field, :api_field, :api_endpoint, :api_data_type,
:_destroy, { transformation: [:type, :format, :true_value, :false_value, :_destroy, { transformation: [:type, :format, :true_value, :false_value,
{ mapping: %i[from to] }] }]) { mapping: %i[from to] }] }])

View File

@ -15,6 +15,7 @@ class API::NotificationsController < API::APIController
def index def index
loop do loop do
@notifications = current_user.notifications @notifications = current_user.notifications
.with_valid_notification_type
.delivered_in_system(current_user) .delivered_in_system(current_user)
.includes(:attached_object) .includes(:attached_object)
.page(params[:page]) .page(params[:page])
@ -24,8 +25,8 @@ class API::NotificationsController < API::APIController
break unless delete_obsoletes(@notifications) break unless delete_obsoletes(@notifications)
end end
@totals = { @totals = {
total: current_user.notifications.delivered_in_system(current_user).count, total: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).count,
unread: current_user.notifications.delivered_in_system(current_user).where(is_read: false).count unread: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).where(is_read: false).count
} }
render :index render :index
end end
@ -33,6 +34,7 @@ class API::NotificationsController < API::APIController
def last_unread def last_unread
loop do loop do
@notifications = current_user.notifications @notifications = current_user.notifications
.with_valid_notification_type
.delivered_in_system(current_user) .delivered_in_system(current_user)
.includes(:attached_object) .includes(:attached_object)
.where(is_read: false) .where(is_read: false)
@ -42,19 +44,20 @@ class API::NotificationsController < API::APIController
break unless delete_obsoletes(@notifications) break unless delete_obsoletes(@notifications)
end end
@totals = { @totals = {
total: current_user.notifications.delivered_in_system(current_user).count, total: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).count,
unread: current_user.notifications.delivered_in_system(current_user).where(is_read: false).count unread: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).where(is_read: false).count
} }
render :index render :index
end end
def polling def polling
@notifications = current_user.notifications @notifications = current_user.notifications
.where('is_read = false AND created_at >= :date', date: params[:last_poll]) .with_valid_notification_type
.order('created_at DESC') .where('notifications.is_read = false AND notifications.created_at >= :date', date: params[:last_poll])
.order('notifications.created_at DESC')
@totals = { @totals = {
total: current_user.notifications.delivered_in_system(current_user).count, total: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).count,
unread: current_user.notifications.delivered_in_system(current_user).where(is_read: false).count unread: current_user.notifications.with_valid_notification_type.delivered_in_system(current_user).where(is_read: false).count
} }
render :index render :index
end end

View File

@ -34,6 +34,15 @@ export const OpenidConnectForm = <TFieldValues extends FieldValues, TContext ext
// this is a workaround for https://github.com/JedWatson/react-select/issues/1879 // this is a workaround for https://github.com/JedWatson/react-select/issues/1879
const [selectKey, setSelectKey] = useState<number>(0); const [selectKey, setSelectKey] = useState<number>(0);
useEffect(() => {
if (!currentFormValues?.extra_authorize_params) {
setValue(
'providable_attributes.extra_authorize_params' as Path<TFieldValues>,
'{}' as UnpackNestedValue<FieldPathValue<TFieldValues, Path<TFieldValues>>>
);
}
}, []);
// when we have detected a discovery endpoint, we mark it as available // when we have detected a discovery endpoint, we mark it as available
useEffect(() => { useEffect(() => {
setValue( setValue(
@ -160,6 +169,12 @@ export const OpenidConnectForm = <TFieldValues extends FieldValues, TContext ext
tooltip={t('app.admin.authentication.openid_connect_form.profile_edition_url_help')} tooltip={t('app.admin.authentication.openid_connect_form.profile_edition_url_help')}
rules={{ required: false, pattern: ValidationLib.urlRegex }} rules={{ required: false, pattern: ValidationLib.urlRegex }}
formState={formState} /> formState={formState} />
<FormInput id="providable_attributes.extra_authorize_params"
register={register}
label={t('app.admin.authentication.openid_connect_form.extra_authorize_params')}
tooltip={t('app.admin.authentication.openid_connect_form.extra_authorize_params_help')}
rules={{ required: false }}
formState={formState} />
<h4>{t('app.admin.authentication.openid_connect_form.client_options')}</h4> <h4>{t('app.admin.authentication.openid_connect_form.client_options')}</h4>
<FormInput id="providable_attributes.client__identifier" <FormInput id="providable_attributes.client__identifier"
label={t('app.admin.authentication.openid_connect_form.client__identifier')} label={t('app.admin.authentication.openid_connect_form.client__identifier')}

View File

@ -136,6 +136,7 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
} }
return handleSubmit((data: User) => { 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) MemberAPI[action](data)
.then(res => { .then(res => {
reset(res); reset(res);

View File

@ -61,7 +61,8 @@ export interface OpenIdConnectProvider {
client__userinfo_endpoint?: string, client__userinfo_endpoint?: string,
client__jwks_uri?: string, client__jwks_uri?: string,
client__end_session_endpoint?: string, client__end_session_endpoint?: string,
profile_url?: string profile_url?: string,
extra_authorize_parameters?: string,
} }
export interface MappingFields { export interface MappingFields {

View File

@ -74,6 +74,7 @@ export const notificationTypeNames = [
'notify_user_is_validated', 'notify_user_is_validated',
'notify_user_is_invalidated', 'notify_user_is_invalidated',
'notify_user_supporting_document_refusal', 'notify_user_supporting_document_refusal',
'notify_user_supporting_document_reminder',
'notify_admin_user_supporting_document_refusal', 'notify_admin_user_supporting_document_refusal',
'notify_user_order_is_ready', 'notify_user_order_is_ready',
'notify_user_order_is_canceled', 'notify_user_order_is_canceled',

View File

@ -989,6 +989,11 @@ p, .widget p {
cursor: pointer; cursor: pointer;
} }
.list-none {
list-style-type: none;
padding-inline-start: 0;
}
@media screen and (min-width: $screen-lg-min) { @media screen and (min-width: $screen-lg-min) {
.b-r-lg { .b-r-lg {
border-right: 1px solid $border-color; border-right: 1px solid $border-color;

View File

@ -288,7 +288,7 @@
<td ng-repeat="field in selectedIndex.additional_fields"> <td ng-repeat="field in selectedIndex.additional_fields">
<ng-switch on="field.data_type"> <ng-switch on="field.data_type">
<span ng-switch-when="date">{{formatDate(datum._source[field.key])}}</span> <span ng-switch-when="date">{{formatDate(datum._source[field.key])}}</span>
<ul ng-switch-when="list"> <ul ng-switch-when="list" class="list-none">
<li ng-repeat="elem in uniq(datum._source[field.key])">{{elem.name}}</li> <li ng-repeat="elem in uniq(datum._source[field.key])">{{elem.name}}</li>
</ul> </ul>
<span ng-switch-default>{{datum._source[field.key]}}</span> <span ng-switch-default>{{datum._source[field.key]}}</span>

View File

@ -19,6 +19,8 @@ class Notification < ApplicationRecord
SQL SQL
} }
scope :with_valid_notification_type, -> { joins(:notification_type).where(notification_types: { name: NOTIFICATIONS_TYPES.map { |nt| nt[:name] } }) }
validates :receiver_id, validates :receiver_id,
:receiver_type, :receiver_type,
:attached_object_id, :attached_object_id,

View File

@ -2,7 +2,7 @@
# NotificationType defines the different types of Notification. # NotificationType defines the different types of Notification.
# To add a new notification type in db, you must add it in: # 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/api/notifications/_XXXXXX.json.jbuilder
# - app/views/notifications_mailer/XXXXXX.html.erb # - app/views/notifications_mailer/XXXXXX.html.erb
# - app/frontend/src/javascript/models/notification-type.ts # - app/frontend/src/javascript/models/notification-type.ts

View File

@ -93,6 +93,7 @@ class User < ApplicationRecord
scope :not_confirmed, -> { where(confirmed_at: nil) } scope :not_confirmed, -> { where(confirmed_at: nil) }
scope :inactive_for_3_years, -> { where('users.last_sign_in_at < ?', 3.years.ago) } scope :inactive_for_3_years, -> { where('users.last_sign_in_at < ?', 3.years.ago) }
scope :not_validated, -> { where(validated_at: nil) } scope :not_validated, -> { where(validated_at: nil) }
scope :supporting_documents_reminder_not_sent, -> { where(supporting_documents_reminder_sent_at: nil) }
def to_json(*) def to_json(*)
ApplicationController.new.view_context.render( ApplicationController.new.view_context.render(

View File

@ -27,6 +27,7 @@ class Members::MembersService
if @member.validated_at? && !(new_types - current_types).empty? if @member.validated_at? && !(new_types - current_types).empty?
validated_at_changed = true validated_at_changed = true
@member.validated_at = nil @member.validated_at = nil
@member.supporting_documents_reminder_sent_at = nil
end end
end end

View File

@ -50,7 +50,6 @@ class Statistics::FetcherService
.eager_load(:slots, :slots_reservations, :invoice_items, :reservation_context, statistic_profile: [:group]) .eager_load(:slots, :slots_reservations, :invoice_items, :reservation_context, statistic_profile: [:group])
.find_each do |r| .find_each do |r|
next unless r.reservable next unless r.reservable
next unless r.original_invoice
next if r.slots.empty? next if r.slots.empty?
profile = r.statistic_profile 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, nb_hours: (r.slots.map(&:duration).map(&:to_i).reduce(:+) / 3600.0).to_f,
ca: calcul_ca(r.original_invoice), ca: calcul_ca(r.original_invoice),
reservation_context_id: r.reservation_context_id, 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 yield result
end end
end end
@ -78,7 +77,6 @@ class Statistics::FetcherService
.eager_load(:slots, :slots_reservations, :invoice_items, :reservation_context, statistic_profile: [:group]) .eager_load(:slots, :slots_reservations, :invoice_items, :reservation_context, statistic_profile: [:group])
.find_each do |r| .find_each do |r|
next unless r.reservable next unless r.reservable
next unless r.original_invoice
next if r.slots.empty? next if r.slots.empty?
profile = r.statistic_profile 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, nb_hours: (r.slots.map(&:duration).map(&:to_i).reduce(:+) / 3600.0).to_f,
ca: calcul_ca(r.original_invoice), ca: calcul_ca(r.original_invoice),
reservation_context_id: r.reservation_context_id, 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 yield result
end end
end end
@ -106,7 +104,7 @@ class Statistics::FetcherService
.eager_load(:slots, :slots_reservations, :invoice_items, :reservation_context, statistic_profile: [:group]) .eager_load(:slots, :slots_reservations, :invoice_items, :reservation_context, statistic_profile: [:group])
.find_each do |r| .find_each do |r|
next unless r.reservable next unless r.reservable
next unless r.original_invoice next if r.slots.empty?
profile = r.statistic_profile profile = r.statistic_profile
slot = r.slots.first slot = r.slots.first
@ -119,7 +117,7 @@ class Statistics::FetcherService
nb_hours: difference_in_hours(slot.start_at, slot.end_at), nb_hours: difference_in_hours(slot.start_at, slot.end_at),
ca: calcul_ca(r.original_invoice), ca: calcul_ca(r.original_invoice),
reservation_context_id: r.reservation_context_id, 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 yield result
end end
end end
@ -134,7 +132,7 @@ class Statistics::FetcherService
.eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group]) .eager_load(:slots, :slots_reservations, :invoice_items, statistic_profile: [:group])
.find_each do |r| .find_each do |r|
next unless r.reservable next unless r.reservable
next unless r.original_invoice next if r.slots.empty?
profile = r.statistic_profile profile = r.statistic_profile
slot = r.slots.first slot = r.slots.first
@ -148,7 +146,7 @@ class Statistics::FetcherService
age_range: (r.reservable.age_range_id ? r.reservable.age_range.name : ''), age_range: (r.reservable.age_range_id ? r.reservable.age_range.name : ''),
nb_places: r.total_booked_seats, nb_places: r.total_booked_seats,
nb_hours: difference_in_hours(slot.start_at, slot.end_at), 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)) ca: calcul_ca(r.original_invoice) }.merge(user_info(profile))
yield result yield result
end end

View File

@ -16,6 +16,6 @@ if @provider.providable_type == OpenIdConnectProvider.name
:prompt, :send_scope_to_token_endpoint, :client__identifier, :client__secret, :client__authorization_endpoint, :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 :client__token_endpoint, :client__userinfo_endpoint, :client__jwks_uri, :client__end_session_endpoint, :profile_url
json.scope @provider.providable[:scope] json.scope @provider.providable[:scope]
json.extra_authorize_params @provider.providable[:extra_authorize_params]
end end
end end

View File

@ -0,0 +1,4 @@
# frozen_string_literal: true
json.title notification.notification_type
json.description t('.reminder_message')

View File

@ -16,7 +16,7 @@ if provider.providable_type == 'OpenIdConnectProvider'
json.extract! provider.providable, :id, :issuer, :discovery, :client_auth_method, :scope, :response_type, :response_mode, 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, :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, :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
end end

View File

@ -0,0 +1,5 @@
<%= render 'notifications_mailer/shared/hello', recipient: @recipient %>
<p>
<%= t('.body.user_supporting_document_reminder') %>
</p>

View File

@ -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

View File

@ -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

View File

@ -111,6 +111,10 @@ de:
save: "Speichern" save: "Speichern"
create_success: "Der Raum wurde erfolgreich erstellt" create_success: "Der Raum wurde erfolgreich erstellt"
update_success: "Der Raum wurde erfolgreich aktualisiert" 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: event_form:
ACTION_title: "{ACTION, select, create{Neue} other{Aktualisiere die}} Veranstaltung" ACTION_title: "{ACTION, select, create{Neue} other{Aktualisiere die}} Veranstaltung"
title: "Titel" title: "Titel"
@ -1477,6 +1481,8 @@ de:
client__jwks_uri: "JWKS URI" client__jwks_uri: "JWKS URI"
client__end_session_endpoint: "End session endpoint" 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." 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: provider_form:
name: "Name" name: "Name"
authentication_type: "Authentifizierungsart" authentication_type: "Authentifizierungsart"

View File

@ -1544,6 +1544,8 @@ en:
client__jwks_uri: "JWKS URI" client__jwks_uri: "JWKS URI"
client__end_session_endpoint: "End session endpoint" 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." 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: provider_form:
name: "Name" name: "Name"
authentication_type: "Authentication type" authentication_type: "Authentication type"

View File

@ -111,6 +111,10 @@ es:
save: "Guardar" save: "Guardar"
create_success: "El espacio se ha creado correctamente" create_success: "El espacio se ha creado correctamente"
update_success: "El espacio se ha actualizado 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: event_form:
ACTION_title: "{ACTION, select, create{Nuevo} other{Actualiza el}} evento" ACTION_title: "{ACTION, select, create{Nuevo} other{Actualiza el}} evento"
title: "Título" title: "Título"
@ -1477,6 +1481,8 @@ es:
client__jwks_uri: "JWKS URI" client__jwks_uri: "JWKS URI"
client__end_session_endpoint: "Endpoint de fin de sesión" 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." 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: provider_form:
name: "Nombre" name: "Nombre"
authentication_type: "Tipo de autenticación" authentication_type: "Tipo de autenticación"

View File

@ -111,10 +111,10 @@ fr:
save: "Enregistrer" save: "Enregistrer"
create_success: "L'espace a bien été créé" create_success: "L'espace a bien été créé"
update_success: "L'espace a bien été mis à jour" update_success: "L'espace a bien été mis à jour"
associated_machines: "Machines" associated_machines: "Machines incluses"
children_spaces: "Espaces" children_spaces: "Espaces inclus"
associated_objects: "Machines et sous-espaces" associated_objects: "Objet associé"
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_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: event_form:
ACTION_title: "{ACTION, select, create{Nouvel } other{Mettre à jour l''}}événement" ACTION_title: "{ACTION, select, create{Nouvel } other{Mettre à jour l''}}événement"
title: "Titre" title: "Titre"
@ -1536,6 +1536,8 @@ fr:
client__jwks_uri: "URI JWKS" client__jwks_uri: "URI JWKS"
client__end_session_endpoint: "Point d'accès pour terminer la session" 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." 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: provider_form:
name: "Nom" name: "Nom"
authentication_type: "Type d'authentification" authentication_type: "Type d'authentification"

View File

@ -111,6 +111,10 @@ it:
save: "Salva" save: "Salva"
create_success: "Lo spazio è stato creato correttamente" create_success: "Lo spazio è stato creato correttamente"
update_success: "Lo spazio è stato aggiornato 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: event_form:
ACTION_title: "{ACTION, select, create{Nuovo} other{Aggiorna}} evento" ACTION_title: "{ACTION, select, create{Nuovo} other{Aggiorna}} evento"
title: "Titolo" title: "Titolo"
@ -1477,6 +1481,8 @@ it:
client__jwks_uri: "JWKS URI" client__jwks_uri: "JWKS URI"
client__end_session_endpoint: "Endpoint di fine sessione" 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." 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: provider_form:
name: "Nome" name: "Nome"
authentication_type: "Tipo di autenticazione" authentication_type: "Tipo di autenticazione"

View File

@ -111,6 +111,10 @@
save: "Save" save: "Save"
create_success: "The space was created successfully" create_success: "The space was created successfully"
update_success: "The space was updated 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: event_form:
ACTION_title: "{ACTION, select, create{New} other{Update the}} event" ACTION_title: "{ACTION, select, create{New} other{Update the}} event"
title: "Title" title: "Title"
@ -1477,6 +1481,8 @@
client__jwks_uri: "JWKS URI" client__jwks_uri: "JWKS URI"
client__end_session_endpoint: "End session endpoint" 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." 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: provider_form:
name: "Name" name: "Name"
authentication_type: "Authentication type" authentication_type: "Authentication type"

View File

@ -111,6 +111,10 @@ pt:
save: "Save" save: "Save"
create_success: "The space was created successfully" create_success: "The space was created successfully"
update_success: "The space was updated 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: event_form:
ACTION_title: "{ACTION, select, create{New} other{Update the}} event" ACTION_title: "{ACTION, select, create{New} other{Update the}} event"
title: "Title" title: "Title"
@ -1477,6 +1481,8 @@ pt:
client__jwks_uri: "JWKS URI" client__jwks_uri: "JWKS URI"
client__end_session_endpoint: "Endpoint de término de sessão" 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." 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: provider_form:
name: "Nome" name: "Nome"
authentication_type: "Tipo de autenticação" authentication_type: "Tipo de autenticação"

View File

@ -111,6 +111,10 @@ zu:
save: "crwdns36885:0crwdne36885:0" save: "crwdns36885:0crwdne36885:0"
create_success: "crwdns31813:0crwdne31813:0" create_success: "crwdns31813:0crwdne31813:0"
update_success: "crwdns31815:0crwdne31815: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: event_form:
ACTION_title: "crwdns36887:0ACTION={ACTION}crwdne36887:0" ACTION_title: "crwdns36887:0ACTION={ACTION}crwdne36887:0"
title: "crwdns31817:0crwdne31817:0" title: "crwdns31817:0crwdne31817:0"
@ -1477,6 +1481,8 @@ zu:
client__jwks_uri: "crwdns26198:0crwdne26198:0" client__jwks_uri: "crwdns26198:0crwdne26198:0"
client__end_session_endpoint: "crwdns26200:0crwdne26200:0" client__end_session_endpoint: "crwdns26200:0crwdne26200:0"
client__end_session_endpoint_help: "crwdns26202:0crwdne26202:0" client__end_session_endpoint_help: "crwdns26202:0crwdne26202:0"
extra_authorize_params: "crwdns37725:0crwdne37725:0"
extra_authorize_params_help: "crwdns37727:0crwdne37727:0"
provider_form: provider_form:
name: "crwdns26204:0crwdne26204:0" name: "crwdns26204:0crwdne26204:0"
authentication_type: "crwdns26206:0crwdne26206:0" authentication_type: "crwdns26206:0crwdne26206:0"

View File

@ -100,7 +100,7 @@ fr:
_the_fablab_policy: "les conditions d'utilisation" _the_fablab_policy: "les conditions d'utilisation"
field_required: "Champ requis" field_required: "Champ requis"
profile_custom_field_is_required: "{FEILD} est requis" profile_custom_field_is_required: "{FEILD} est requis"
user_supporting_documents_required: "Attention !<br>Vous avez déclarez être \"{GROUP}\", des pièces justificatives pourront vous être demandées." user_supporting_documents_required: "Attention !<br>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." 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_statistics: "Cette donnée sera utilisée à des fins statistiques"
used_for_invoicing: "Cette donnée sera utilisée à des fins de facturation" used_for_invoicing: "Cette donnée sera utilisée à des fins de facturation"

View File

@ -65,6 +65,7 @@ de:
not_available: "Nicht verfügbar" not_available: "Nicht verfügbar"
reserving: "Ich reserviere" reserving: "Ich reserviere"
i_ve_reserved: "Ich reservierte" i_ve_reserved: "Ich reservierte"
blocked: "Blocked"
length_must_be_slot_multiple: "muss mindestens %{MIN} Minuten nach dem Startdatum liegen" 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" must_be_associated_with_at_least_1_machine: "muss mindestens einer Maschine zugeordnet sein"
deleted_user: "Gelöschte Benutzer" deleted_user: "Gelöschte Benutzer"
@ -446,6 +447,8 @@ de:
account_invalidated: "Dein Account ist ungültig." account_invalidated: "Dein Account ist ungültig."
notify_user_supporting_document_refusal: notify_user_supporting_document_refusal:
refusal: "Your supporting documents were refused" 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: notify_admin_user_supporting_document_refusal:
refusal: "Member's supporting document <strong><em>%{NAME}</strong></em> was refused." refusal: "Member's supporting document <strong><em>%{NAME}</strong></em> was refused."
notify_user_order_is_ready: notify_user_order_is_ready:
@ -538,6 +541,7 @@ de:
space: "Dieser Space ist deaktiviert" space: "Dieser Space ist deaktiviert"
machine: "Diese Maschine ist deaktiviert" machine: "Diese Maschine ist deaktiviert"
reservable: "Diese Maschine ist nicht reservierbar" reservable: "Diese Maschine ist nicht reservierbar"
blocked_by_another_reservation: "This slot is blocked by another reservation"
cart_validation: cart_validation:
select_user: "Please select a user before continuing" select_user: "Please select a user before continuing"
settings: settings:

View File

@ -462,6 +462,8 @@ en:
child_invalidated: "Your account child is invalid." child_invalidated: "Your account child is invalid."
notify_user_supporting_document_refusal: notify_user_supporting_document_refusal:
refusal: "Your supporting documents were refused" 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: notify_admin_user_supporting_document_refusal:
refusal: "Member's supporting document <strong><em>%{NAME}</strong></em> was refused." refusal: "Member's supporting document <strong><em>%{NAME}</strong></em> was refused."
notify_user_child_supporting_document_refusal: notify_user_child_supporting_document_refusal:

View File

@ -65,6 +65,7 @@ es:
not_available: "No disponible" not_available: "No disponible"
reserving: "Me reservo" reserving: "Me reservo"
i_ve_reserved: "He reservado" 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" 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" must_be_associated_with_at_least_1_machine: "debe estar asociado con al menos 1 máquina"
deleted_user: "Usuario eliminado" deleted_user: "Usuario eliminado"
@ -446,6 +447,8 @@ es:
account_invalidated: "Su cuenta no es válida." account_invalidated: "Su cuenta no es válida."
notify_user_supporting_document_refusal: notify_user_supporting_document_refusal:
refusal: "Sus justificantes han sido rechazados" 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: notify_admin_user_supporting_document_refusal:
refusal: "El justificante del afiliado <strong><em>%{NAME}</em></strong> ha sido rechazado." refusal: "El justificante del afiliado <strong><em>%{NAME}</em></strong> ha sido rechazado."
notify_user_order_is_ready: notify_user_order_is_ready:
@ -538,6 +541,7 @@ es:
space: "Este espacio está desactivado" space: "Este espacio está desactivado"
machine: "Esta máquina está desactivada" machine: "Esta máquina está desactivada"
reservable: "Esta máquina no se puede reservar" reservable: "Esta máquina no se puede reservar"
blocked_by_another_reservation: "This slot is blocked by another reservation"
cart_validation: cart_validation:
select_user: "Por favor, seleccione un usuario antes de continuar" select_user: "Por favor, seleccione un usuario antes de continuar"
settings: settings:

View File

@ -66,7 +66,7 @@ fr:
not_available: "Non disponible" not_available: "Non disponible"
reserving: "Je réserve" reserving: "Je réserve"
i_ve_reserved: "J'ai réservé" 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" 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" must_be_associated_with_at_least_1_machine: "doit être associé avec au moins 1 machine"
deleted_user: "Utilisateur supprimé" deleted_user: "Utilisateur supprimé"
@ -462,6 +462,8 @@ fr:
child_invalidated: "Votre compte enfant est invalide." child_invalidated: "Votre compte enfant est invalide."
notify_user_supporting_document_refusal: notify_user_supporting_document_refusal:
refusal: "Vos pièces justificatives ont été refusées" 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: notify_admin_user_supporting_document_refusal:
refusal: "Le justificatif du membre <strong><em>%{NAME}</strong></em> a été refusé." refusal: "Le justificatif du membre <strong><em>%{NAME}</strong></em> a été refusé."
notify_user_child_supporting_document_refusal: notify_user_child_supporting_document_refusal:

View File

@ -65,6 +65,7 @@ it:
not_available: "Non disponibile" not_available: "Non disponibile"
reserving: "Sto prenotando" reserving: "Sto prenotando"
i_ve_reserved: "Ho prenotato" i_ve_reserved: "Ho prenotato"
blocked: "Blocked"
length_must_be_slot_multiple: "deve essere almeno %{MIN} minuti dopo la data di inizio" 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" must_be_associated_with_at_least_1_machine: "deve essere associata ad almeno 1 macchina"
deleted_user: "Utente eliminato" deleted_user: "Utente eliminato"
@ -446,6 +447,8 @@ it:
account_invalidated: "Il tuo account non è valido." account_invalidated: "Il tuo account non è valido."
notify_user_supporting_document_refusal: notify_user_supporting_document_refusal:
refusal: "I tuoi documenti aggiuntivi sono stati rifiutati" 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: notify_admin_user_supporting_document_refusal:
refusal: "Il documento aggiuntivo del membro <strong><em>%{NAME}</strong></em> è stato rifiutato." refusal: "Il documento aggiuntivo del membro <strong><em>%{NAME}</strong></em> è stato rifiutato."
notify_user_order_is_ready: notify_user_order_is_ready:
@ -538,6 +541,7 @@ it:
space: "Questo spazio è disabilitato" space: "Questo spazio è disabilitato"
machine: "Questa macchina è disabilitata" machine: "Questa macchina è disabilitata"
reservable: "Questa macchina non è prenotabile" reservable: "Questa macchina non è prenotabile"
blocked_by_another_reservation: "This slot is blocked by another reservation"
cart_validation: cart_validation:
select_user: "Seleziona un utente prima di continuare" select_user: "Seleziona un utente prima di continuare"
settings: settings:

View File

@ -402,6 +402,10 @@ de:
body: body:
user_supporting_document_files_refusal: "Your supporting documents were refused:" user_supporting_document_files_refusal: "Your supporting documents were refused:"
action: "Please re-upload some new supporting documents." 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: notify_admin_user_supporting_document_refusal:
subject: "A member's supporting documents were refused" subject: "A member's supporting documents were refused"
body: body:

View File

@ -434,6 +434,10 @@ en:
body: body:
user_supporting_document_files_refusal: "Your supporting documents were refused:" user_supporting_document_files_refusal: "Your supporting documents were refused:"
action: "Please re-upload some new supporting documents." 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: notify_admin_user_supporting_document_refusal:
subject: "A member's supporting documents were refused" subject: "A member's supporting documents were refused"
body: body:

View File

@ -402,6 +402,10 @@ es:
body: body:
user_supporting_document_files_refusal: "Sus justificantes han sido rechazados:" user_supporting_document_files_refusal: "Sus justificantes han sido rechazados:"
action: "Por favor, vuelva a subir nuevos documentos justificativos." 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: notify_admin_user_supporting_document_refusal:
subject: "Los justificantes del afiliado de un miembro han sido rechazados" subject: "Los justificantes del afiliado de un miembro han sido rechazados"
body: body:

View File

@ -434,6 +434,10 @@ fr:
body: body:
user_supporting_document_files_refusal: "Vos pièces justificatives ont été refusées :" user_supporting_document_files_refusal: "Vos pièces justificatives ont été refusées :"
action: "Veuillez téléverser de nouvelles pièces justificatives." 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: notify_admin_user_supporting_document_refusal:
subject: "Les justificatifs d'un membre ont été refusés" subject: "Les justificatifs d'un membre ont été refusés"
body: body:

View File

@ -402,6 +402,10 @@ it:
body: body:
user_supporting_document_files_refusal: "I tuoi documenti aggiuntivi sono stati rifiutati:" user_supporting_document_files_refusal: "I tuoi documenti aggiuntivi sono stati rifiutati:"
action: "Si prega di ricaricare nuovi documenti di supporto." 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: notify_admin_user_supporting_document_refusal:
subject: "I documenti aggiuntivi di un membro sono stati rifiutati" subject: "I documenti aggiuntivi di un membro sono stati rifiutati"
body: body:

View File

@ -402,6 +402,10 @@
body: body:
user_supporting_document_files_refusal: "Your supporting documents were refused:" user_supporting_document_files_refusal: "Your supporting documents were refused:"
action: "Please re-upload some new supporting documents." 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: notify_admin_user_supporting_document_refusal:
subject: "A member's supporting documents were refused" subject: "A member's supporting documents were refused"
body: body:

View File

@ -402,6 +402,10 @@ pt:
body: body:
user_supporting_document_files_refusal: "Os seus documentos de apoio foram recusados:" user_supporting_document_files_refusal: "Os seus documentos de apoio foram recusados:"
action: "Por favor, recarregue novos documentos de apoio." 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: notify_admin_user_supporting_document_refusal:
subject: "Documentos de apoio de um membro foram recusados" subject: "Documentos de apoio de um membro foram recusados"
body: body:

View File

@ -402,6 +402,10 @@ zu:
body: body:
user_supporting_document_files_refusal: "crwdns37363:0crwdne37363:0" user_supporting_document_files_refusal: "crwdns37363:0crwdne37363:0"
action: "crwdns37365:0crwdne37365: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: notify_admin_user_supporting_document_refusal:
subject: "crwdns37367:0crwdne37367:0" subject: "crwdns37367:0crwdne37367:0"
body: body:

View File

@ -65,6 +65,7 @@
not_available: "Ikke tilgjengelig" not_available: "Ikke tilgjengelig"
reserving: "I'm reserving" reserving: "I'm reserving"
i_ve_reserved: "Jeg har reservert" i_ve_reserved: "Jeg har reservert"
blocked: "Blocked"
length_must_be_slot_multiple: "må være minst %{MIN} minutter etter startdatoen" 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" must_be_associated_with_at_least_1_machine: "må være tilknyttet minst 1 maskin"
deleted_user: "Deleted user" deleted_user: "Deleted user"
@ -446,6 +447,8 @@
account_invalidated: "Your account is invalid." account_invalidated: "Your account is invalid."
notify_user_supporting_document_refusal: notify_user_supporting_document_refusal:
refusal: "Your supporting documents were refused" 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: notify_admin_user_supporting_document_refusal:
refusal: "Member's supporting document <strong><em>%{NAME}</strong></em> was refused." refusal: "Member's supporting document <strong><em>%{NAME}</strong></em> was refused."
notify_user_order_is_ready: notify_user_order_is_ready:
@ -538,6 +541,7 @@
space: "This space is disabled" space: "This space is disabled"
machine: "This machine is disabled" machine: "This machine is disabled"
reservable: "This machine is not reservable" reservable: "This machine is not reservable"
blocked_by_another_reservation: "This slot is blocked by another reservation"
cart_validation: cart_validation:
select_user: "Please select a user before continuing" select_user: "Please select a user before continuing"
settings: settings:

View File

@ -65,6 +65,7 @@ pt:
not_available: "Não disponível " not_available: "Não disponível "
reserving: "I'm reserving" reserving: "I'm reserving"
i_ve_reserved: "Eu reservei" 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" 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" must_be_associated_with_at_least_1_machine: "deve estar associada a pelo menos uma máquina"
deleted_user: "Usuário deletado" deleted_user: "Usuário deletado"
@ -446,6 +447,8 @@ pt:
account_invalidated: "Sua conta é inválida." account_invalidated: "Sua conta é inválida."
notify_user_supporting_document_refusal: notify_user_supporting_document_refusal:
refusal: "Your supporting documents were refused" 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: notify_admin_user_supporting_document_refusal:
refusal: "Member's supporting document <strong><em>%{NAME}</strong></em> was refused." refusal: "Member's supporting document <strong><em>%{NAME}</strong></em> was refused."
notify_user_order_is_ready: notify_user_order_is_ready:
@ -538,6 +541,7 @@ pt:
space: "Este espaço está desativado" space: "Este espaço está desativado"
machine: "Esta máquina está desativada" machine: "Esta máquina está desativada"
reservable: "Esta máquina não é reservável" reservable: "Esta máquina não é reservável"
blocked_by_another_reservation: "This slot is blocked by another reservation"
cart_validation: cart_validation:
select_user: "Por favor, selecione um usuário antes de continuar" select_user: "Por favor, selecione um usuário antes de continuar"
settings: settings:

View File

@ -65,6 +65,7 @@ zu:
not_available: "crwdns3267:0crwdne3267:0" not_available: "crwdns3267:0crwdne3267:0"
reserving: "crwdns37199:0crwdne37199:0" reserving: "crwdns37199:0crwdne37199:0"
i_ve_reserved: "crwdns3269:0crwdne3269:0" i_ve_reserved: "crwdns3269:0crwdne3269:0"
blocked: "crwdns37737:0crwdne37737:0"
length_must_be_slot_multiple: "crwdns3271:0%{MIN}crwdne3271:0" length_must_be_slot_multiple: "crwdns3271:0%{MIN}crwdne3271:0"
must_be_associated_with_at_least_1_machine: "crwdns3273:0crwdne3273:0" must_be_associated_with_at_least_1_machine: "crwdns3273:0crwdne3273:0"
deleted_user: "crwdns22460:0crwdne22460:0" deleted_user: "crwdns22460:0crwdne22460:0"
@ -446,6 +447,8 @@ zu:
account_invalidated: "crwdns23006:0crwdne23006:0" account_invalidated: "crwdns23006:0crwdne23006:0"
notify_user_supporting_document_refusal: notify_user_supporting_document_refusal:
refusal: "crwdns37345:0crwdne37345:0" refusal: "crwdns37345:0crwdne37345:0"
notify_user_supporting_document_reminder:
reminder_message: "crwdns37739:0crwdne37739:0"
notify_admin_user_supporting_document_refusal: notify_admin_user_supporting_document_refusal:
refusal: "crwdns37347:0%{NAME}crwdne37347:0" refusal: "crwdns37347:0%{NAME}crwdne37347:0"
notify_user_order_is_ready: notify_user_order_is_ready:
@ -538,6 +541,7 @@ zu:
space: "crwdns36283:0crwdne36283:0" space: "crwdns36283:0crwdne36283:0"
machine: "crwdns36285:0crwdne36285:0" machine: "crwdns36285:0crwdne36285:0"
reservable: "crwdns36287:0crwdne36287:0" reservable: "crwdns36287:0crwdne36287:0"
blocked_by_another_reservation: "crwdns37741:0crwdne37741:0"
cart_validation: cart_validation:
select_user: "crwdns37211:0crwdne37211:0" select_user: "crwdns37211:0crwdne37211:0"
settings: settings:

View File

@ -62,6 +62,10 @@ auto_cancel_authorizations:
class: TrainingAuthorizationWorker class: TrainingAuthorizationWorker
queue: default queue: default
supporting_documents_reminder_worker:
cron: "0 8 * * *" # every day, at 8
class: SupportingDocumentsReminderWorker
child_age_will_be_18: child_age_will_be_18:
cron: "0 0 0 * * *" # every day, at midnight cron: "0 0 0 * * *" # every day, at midnight
class: ChildAgeWorker class: ChildAgeWorker

View File

@ -0,0 +1,5 @@
class AddSupportingDocumentsReminderSentAtToUsers < ActiveRecord::Migration[7.0]
def change
add_column :users, :supporting_documents_reminder_sent_at, :datetime
end
end

View File

@ -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

View File

@ -1,104 +1,5 @@
# frozen_string_literal: true # 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| NOTIFICATIONS_TYPES.each do |notification_type_attrs|
notification_type = NotificationType.find_by(name: notification_type_attrs[:name]) notification_type = NotificationType.find_by(name: notification_type_attrs[:name])

View File

@ -2039,7 +2039,8 @@ CREATE TABLE public.open_id_connect_providers (
client__end_session_endpoint character varying, client__end_session_endpoint character varying,
profile_url character varying, profile_url character varying,
created_at timestamp without time zone NOT NULL, 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, current_sign_in_ip inet,
last_sign_in_ip inet, last_sign_in_ip inet,
validated_at timestamp without time zone, 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'), ('20230728090257'),
('20230825101952'), ('20230825101952'),
('20230828073428'), ('20230828073428'),
('20230831103208'); ('20230831103208'),
('20230901090637'),
('20230907124230');

View File

@ -1,6 +1,6 @@
{ {
"name": "fab-manager", "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.", "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": [ "keywords": [
"fablab", "fablab",

View File

@ -607,3 +607,11 @@ notification_type_72:
is_configurable: false is_configurable: false
created_at: 2023-02-16 10:42:39.143888000 Z created_at: 2023-02-16 10:42:39.143888000 Z
updated_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

View File

@ -39,6 +39,21 @@ class NotificationsTest < ActionDispatch::IntegrationTest
assert_equal (Notification.where(receiver_id: @admin.id).count - 1), notifications_total assert_equal (Notification.where(receiver_id: @admin.id).count - 1), notifications_total
end 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 test 'Last unread returns last 3 unread notifications' do
@member = User.find(4) @member = User.find(4)
login_as(@member, scope: :user) login_as(@member, scope: :user)

View File

@ -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