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:
commit
19b6bd8d8a
@ -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)
|
||||
|
@ -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] }] }])
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
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
|
||||
useEffect(() => {
|
||||
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')}
|
||||
rules={{ required: false, pattern: ValidationLib.urlRegex }}
|
||||
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>
|
||||
<FormInput id="providable_attributes.client__identifier"
|
||||
label={t('app.admin.authentication.openid_connect_form.client__identifier')}
|
||||
|
@ -136,6 +136,7 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ 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);
|
||||
|
@ -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 {
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -288,7 +288,7 @@
|
||||
<td ng-repeat="field in selectedIndex.additional_fields">
|
||||
<ng-switch on="field.data_type">
|
||||
<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>
|
||||
</ul>
|
||||
<span ng-switch-default>{{datum._source[field.key]}}</span>
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -0,0 +1,4 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.title notification.notification_type
|
||||
json.description t('.reminder_message')
|
@ -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
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
<%= render 'notifications_mailer/shared/hello', recipient: @recipient %>
|
||||
|
||||
<p>
|
||||
<%= t('.body.user_supporting_document_reminder') %>
|
||||
</p>
|
27
app/workers/supporting_documents_reminder_worker.rb
Normal file
27
app/workers/supporting_documents_reminder_worker.rb
Normal 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
|
81
config/initializers/notification_types.rb
Normal file
81
config/initializers/notification_types.rb
Normal 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
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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 !<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."
|
||||
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"
|
||||
|
@ -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 <strong><em>%{NAME}</strong></em> 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:
|
||||
|
@ -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 <strong><em>%{NAME}</strong></em> was refused."
|
||||
notify_user_child_supporting_document_refusal:
|
||||
|
@ -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 <strong><em>%{NAME}</em></strong> 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:
|
||||
|
@ -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 <strong><em>%{NAME}</strong></em> a été refusé."
|
||||
notify_user_child_supporting_document_refusal:
|
||||
|
@ -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 <strong><em>%{NAME}</strong></em> è 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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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 <strong><em>%{NAME}</strong></em> 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:
|
||||
|
@ -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 <strong><em>%{NAME}</strong></em> 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:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -0,0 +1,5 @@
|
||||
class AddSupportingDocumentsReminderSentAtToUsers < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :users, :supporting_documents_reminder_sent_at, :datetime
|
||||
end
|
||||
end
|
@ -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
|
@ -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])
|
||||
|
||||
|
@ -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');
|
||||
|
||||
|
||||
|
@ -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",
|
||||
|
8
test/fixtures/notification_types.yml
vendored
8
test/fixtures/notification_types.yml
vendored
@ -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
|
@ -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)
|
||||
|
83
test/workers/supporting_documents_reminder_worker_test.rb
Normal file
83
test/workers/supporting_documents_reminder_worker_test.rb
Normal 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
|
Loading…
x
Reference in New Issue
Block a user