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

Ability to disable public account creation

This commit is contained in:
Sylvain 2022-01-04 15:27:58 +01:00
parent a120296402
commit e1256ec551
14 changed files with 58 additions and 13 deletions

View File

@ -2,8 +2,10 @@
- Ability to cancel a payement schedule from the interface - Ability to cancel a payement schedule from the interface
- Ability to create slots in the past - Ability to create slots in the past
- Ability to disable public account creation
- Updated caniuse db - Updated caniuse db
- Optimized the load time of the payment schedules list - Optimized the load time of the payment schedules list
- [TODO DEPLOY] `rails db:seed`
# v5.3.0 2021 December 29 # v5.3.0 2021 December 29

View File

@ -4,6 +4,11 @@
class RegistrationsController < Devise::RegistrationsController class RegistrationsController < Devise::RegistrationsController
# POST /users.json # POST /users.json
def create def create
# Is public registration allowed?
unless Setting.get('public_registrations')
render json: { errors: { signup: [t('errors.messages.registration_disabled')] } }, status: :forbidden and return
end
# first check the recaptcha # first check the recaptcha
check = RecaptchaService.verify(params[:user][:recaptcha]) check = RecaptchaService.verify(params[:user][:recaptcha])
render json: check['error-codes'], status: :unprocessable_entity and return unless check['success'] render json: check['error-codes'], status: :unprocessable_entity and return unless check['success']

View File

@ -1,11 +1,18 @@
'use strict'; 'use strict';
Application.Controllers.controller('HeaderController', ['$scope', '$rootScope', '$state', Application.Controllers.controller('HeaderController', ['$scope', '$rootScope', '$state', 'settingsPromise',
function ($scope, $rootScope, $state) { function ($scope, $rootScope, $state, settingsPromise) {
$scope.aboutPage = ($state.current.name === 'app.public.about'); $scope.aboutPage = ($state.current.name === 'app.public.about');
$rootScope.$on('$stateChangeStart', function (event, toState) { $rootScope.$on('$stateChangeStart', function (event, toState) {
$scope.aboutPage = (toState.name === 'app.public.about'); $scope.aboutPage = (toState.name === 'app.public.about');
}); });
/**
* Returns the current state of the public registration setting (allowed/blocked).
*/
$scope.registrationEnabled = function () {
return settingsPromise.public_registrations === 'true';
};
} }
]); ]);

View File

@ -13,7 +13,7 @@
/** /**
* Navigation controller. List the links availables in the left navigation pane and their icon. * Navigation controller. List the links availables in the left navigation pane and their icon.
*/ */
Application.Controllers.controller('MainNavController', ['$scope', function ($scope) { Application.Controllers.controller('MainNavController', ['$scope', 'settingsPromise', function ($scope, settingsPromise) {
// Common links (public application) // Common links (public application)
$scope.navLinks = [ $scope.navLinks = [
{ {
@ -172,5 +172,12 @@ Application.Controllers.controller('MainNavController', ['$scope', function ($sc
authorizedRoles: ['admin'] authorizedRoles: ['admin']
}); });
} }
/**
* Returns the current state of the public registration setting (allowed/blocked).
*/
$scope.registrationEnabled = function () {
return settingsPromise.public_registrations === 'true';
};
} }
]); ]);

View File

@ -117,7 +117,8 @@ export enum SettingName {
RenewPackThreshold = 'renew_pack_threshold', RenewPackThreshold = 'renew_pack_threshold',
PackOnlyForSubscription = 'pack_only_for_subscription', PackOnlyForSubscription = 'pack_only_for_subscription',
OverlappingCategories = 'overlapping_categories', OverlappingCategories = 'overlapping_categories',
ExtendedPricesInSameDay = 'extended_prices_in_same_day' ExtendedPricesInSameDay = 'extended_prices_in_same_day',
PublicRegistrations = 'public_registrations'
} }
export type SettingValue = string|boolean|number; export type SettingValue = string|boolean|number;

View File

@ -38,7 +38,8 @@ angular.module('application.router', ['ui.router'])
logoFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-file' }).$promise; }], logoFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-file' }).$promise; }],
logoBlackFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-black-file' }).$promise; }], logoBlackFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-black-file' }).$promise; }],
sharedTranslations: ['Translations', function (Translations) { return Translations.query(['app.shared', 'app.public.common']).$promise; }], sharedTranslations: ['Translations', function (Translations) { return Translations.query(['app.shared', 'app.public.common']).$promise; }],
modulesPromise: ['Setting', function (Setting) { return Setting.query({ names: "['spaces_module', 'plans_module', 'invoicing_module', 'wallet_module', 'statistics_module', 'trainings_module', 'public_agenda_module']" }).$promise; }] modulesPromise: ['Setting', function (Setting) { return Setting.query({ names: "['spaces_module', 'plans_module', 'invoicing_module', 'wallet_module', 'statistics_module', 'trainings_module', 'public_agenda_module']" }).$promise; }],
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['public_registrations']" }).$promise; }]
}, },
onEnter: ['$rootScope', 'logoFile', 'logoBlackFile', 'modulesPromise', 'CSRF', function ($rootScope, logoFile, logoBlackFile, modulesPromise, CSRF) { onEnter: ['$rootScope', 'logoFile', 'logoBlackFile', 'modulesPromise', 'CSRF', function ($rootScope, logoFile, logoBlackFile, modulesPromise, CSRF) {
// Retrieve Anti-CSRF tokens from cookies // Retrieve Anti-CSRF tokens from cookies
@ -1081,7 +1082,8 @@ angular.module('application.router', ['ui.router'])
"'reminder_delay', 'visibility_yearly', 'visibility_others', 'wallet_module', 'trainings_module', " + "'reminder_delay', 'visibility_yearly', 'visibility_others', 'wallet_module', 'trainings_module', " +
"'display_name_enable', 'machines_sort_by', 'fab_analytics', 'statistics_module', 'address_required', " + "'display_name_enable', 'machines_sort_by', 'fab_analytics', 'statistics_module', 'address_required', " +
"'link_name', 'home_content', 'home_css', 'phone_required', 'upcoming_events_shown', 'public_agenda_module'," + "'link_name', 'home_content', 'home_css', 'phone_required', 'upcoming_events_shown', 'public_agenda_module'," +
"'renew_pack_threshold', 'pack_only_for_subscription', 'overlapping_categories', 'extended_prices_in_same_day']" "'renew_pack_threshold', 'pack_only_for_subscription', 'overlapping_categories', 'public_registrations'," +
"'extended_prices_in_same_day']"
}).$promise; }).$promise;
}], }],
privacyDraftsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'privacy_draft', history: true }).$promise; }], privacyDraftsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'privacy_draft', history: true }).$promise; }],

View File

@ -412,6 +412,18 @@
<span class="font-sbold" translate>{{ 'app.admin.settings.account_creation' }}</span> <span class="font-sbold" translate>{{ 'app.admin.settings.account_creation' }}</span>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div class="row">
<h3 class="m-l" translate>{{ 'app.admin.settings.general.public_registrations' }}</h3>
<p class="alert alert-warning m-h-md" translate>
{{ 'app.admin.settings.general.public_registrations_info' }}
</p>
<div class="col-md-10 col-md-offset-1">
<boolean-setting name="public_registrations"
settings="allSettings"
label="app.admin.settings.general.public_registrations_allowed">
</boolean-setting>
</div>
</div>
<div class="row"> <div class="row">
<h3 class="m-l" translate>{{ 'app.admin.settings.phone' }}</h3> <h3 class="m-l" translate>{{ 'app.admin.settings.phone' }}</h3>
<p class="alert alert-warning m-h-md" translate> <p class="alert alert-warning m-h-md" translate>

View File

@ -53,7 +53,7 @@
<li><a class="text-black pointer" ng-click="logout($event)"><i class="fa fa-power-off"></i> {{ 'app.public.common.sign_out' | translate }}</a></li> <li><a class="text-black pointer" ng-click="logout($event)"><i class="fa fa-power-off"></i> {{ 'app.public.common.sign_out' | translate }}</a></li>
</ul> </ul>
</li> </li>
<li ng-if="!isAuthenticated()"><a class="font-sbold label text-md pointer" ng-click="signup($event)"><i class="fa fa-rocket"></i> {{ 'app.public.common.sign_up' | translate }}</a></li> <li ng-if="!isAuthenticated() && registrationEnabled()"><a class="font-sbold label text-md pointer" ng-click="signup($event)"><i class="fa fa-rocket"></i> {{ 'app.public.common.sign_up' | translate }}</a></li>
<li ng-if="!isAuthenticated()"> <li ng-if="!isAuthenticated()">
<a class="font-sbold label text-md pointer" ng-click="login($event)"><i class="fa fa-sign-in"></i> {{ 'app.public.common.sign_in' | translate }}</a> <a class="font-sbold label text-md pointer" ng-click="login($event)"><i class="fa fa-sign-in"></i> {{ 'app.public.common.sign_in' | translate }}</a>
</li> </li>

View File

@ -7,12 +7,12 @@
<nav class="nav-primary hidden-xs"> <nav class="nav-primary hidden-xs">
<ul class="nav nav-main m-t-xs" data-ride="collapse"> <ul class="nav nav-main m-t-xs" data-ride="collapse">
<!-- Disconnected user menu for small devices --> <!-- Disconnected user menu for small devices -->
<li class="hidden-sm hidden-md hidden-lg" ng-if-start="!isAuthenticated()"> <li class="hidden-sm hidden-md hidden-lg" ng-if="!isAuthenticated() && registrationEnabled()">
<a class="auto pointer" ng-click="signup($event)"> <a class="auto pointer" ng-click="signup($event)">
<i class="fa fa-rocket"></i> <span translate>{{ 'app.public.common.sign_up' }}</span> <i class="fa fa-rocket"></i> <span translate>{{ 'app.public.common.sign_up' }}</span>
</a> </a>
</li> </li>
<li class="hidden-sm hidden-md hidden-lg" ng-if-end> <li class="hidden-sm hidden-md hidden-lg" ng-if="!isAuthenticated()">
<a class="auto pointer" ng-click="login($event)"> <a class="auto pointer" ng-click="login($event)">
<i class="fa fa-sign-in"></i> <span translate>{{ 'app.public.common.sign_in' }}</span> <i class="fa fa-sign-in"></i> <span translate>{{ 'app.public.common.sign_in' }}</span>
</a> </a>

View File

@ -127,7 +127,8 @@ class Setting < ApplicationRecord
renew_pack_threshold renew_pack_threshold
pack_only_for_subscription pack_only_for_subscription
overlapping_categories overlapping_categories
extended_prices_in_same_day] } extended_prices_in_same_day
public_registrations] }
# WARNING: when adding a new key, you may also want to add it in: # WARNING: when adding a new key, you may also want to add it in:
# - config/locales/en.yml#settings # - config/locales/en.yml#settings
# - app/frontend/src/javascript/models/setting.ts#SettingName # - app/frontend/src/javascript/models/setting.ts#SettingName

View File

@ -28,7 +28,7 @@ class SettingPolicy < ApplicationPolicy
end end
## ##
# Every settings that anyone can read. The other settings are restricted for admins. # List of settings that anyone can read. The other settings are restricted for admins.
# This list must be manually updated if a new setting should be world-readable # This list must be manually updated if a new setting should be world-readable
## ##
def self.public_whitelist def self.public_whitelist
@ -40,11 +40,11 @@ class SettingPolicy < ApplicationPolicy
recaptcha_site_key feature_tour_display disqus_shortname allowed_cad_extensions openlab_app_id openlab_default recaptcha_site_key feature_tour_display disqus_shortname allowed_cad_extensions openlab_app_id openlab_default
online_payment_module stripe_public_key confirmation_required wallet_module trainings_module address_required online_payment_module stripe_public_key confirmation_required wallet_module trainings_module address_required
payment_gateway payzen_endpoint payzen_public_key public_agenda_module renew_pack_threshold statistics_module payment_gateway payzen_endpoint payzen_public_key public_agenda_module renew_pack_threshold statistics_module
pack_only_for_subscription overlapping_categories] pack_only_for_subscription overlapping_categories public_registrations]
end end
## ##
# Every settings that only admins can read. # List of settings that only admins can read.
# This blacklist is automatically generated from the public_whitelist above. # This blacklist is automatically generated from the public_whitelist above.
## ##
def self.public_blacklist def self.public_blacklist

View File

@ -1283,6 +1283,7 @@ en:
extended_prices: "Extended prices" extended_prices: "Extended prices"
extended_prices_info_html: "Spaces can have different prices depending on the cumulated duration of the booking. You can choose if this apply to all bookings or only to those starting within the same day." extended_prices_info_html: "Spaces can have different prices depending on the cumulated duration of the booking. You can choose if this apply to all bookings or only to those starting within the same day."
extended_prices_in_same_day: "Extended prices in the same day" extended_prices_in_same_day: "Extended prices in the same day"
public_registrations: "Public registrations"
overlapping_options: overlapping_options:
training_reservations: "Trainings" training_reservations: "Trainings"
machine_reservations: "Machines" machine_reservations: "Machines"
@ -1309,6 +1310,9 @@ en:
name: "Name" name: "Name"
created_at: "Creation date" created_at: "Creation date"
updated_at: "Last update date" updated_at: "Last update date"
public_registrations: "Public registrations"
public_registrations_info: "Allow everyone to register a new account on the platform. If disabled, only administrators and managers can create new accounts."
public_registrations_allowed: "Public registrations allowed"
help: "Help" help: "Help"
feature_tour: "Feature tour" feature_tour: "Feature tour"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he/she visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>" feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he/she visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"

View File

@ -37,6 +37,7 @@ en:
end_before_start: "The end date can't be before the start date. Pick a date after %{START}" end_before_start: "The end date can't be before the start date. Pick a date after %{START}"
invalid_duration: "The allowed duration must be between 1 day and 1 year. Your period is %{DAYS} days long." invalid_duration: "The allowed duration must be between 1 day and 1 year. Your period is %{DAYS} days long."
must_be_in_the_past: "The period must be strictly prior to today's date." must_be_in_the_past: "The period must be strictly prior to today's date."
registration_disabled: "Registration is disabled"
apipie: apipie:
api_documentation: "API Documentation" api_documentation: "API Documentation"
code: "HTTP code" code: "HTTP code"
@ -542,3 +543,4 @@ en:
pack_only_for_subscription: "Restrict packs for subscribers" pack_only_for_subscription: "Restrict packs for subscribers"
overlapping_categories: "Categories for overlapping booking prevention" overlapping_categories: "Categories for overlapping booking prevention"
extended_prices_in_same_day: "Extended prices in the same day" extended_prices_in_same_day: "Extended prices in the same day"
public_registrations: "Public registrations"

View File

@ -901,6 +901,8 @@ Setting.set('renew_pack_threshold', 0.2) unless Setting.find_by(name: 'renew_pac
Setting.set('pack_only_for_subscription', true) unless Setting.find_by(name: 'pack_only_for_subscription').try(:value) Setting.set('pack_only_for_subscription', true) unless Setting.find_by(name: 'pack_only_for_subscription').try(:value)
Setting.set('public_registrations', true) unless Setting.find_by(name: 'public_registrations').try(:value)
unless Setting.find_by(name: 'overlapping_categories').try(:value) unless Setting.find_by(name: 'overlapping_categories').try(:value)
Setting.set('overlapping_categories', 'training_reservations,machine_reservations,space_reservations,events_reservations') Setting.set('overlapping_categories', 'training_reservations,machine_reservations,space_reservations,events_reservations')
end end