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

ability to set phone number optional or required

also: show stars on required fields in new admin form
This commit is contained in:
Sylvain 2019-11-19 11:44:32 +01:00
parent 9ec736e6b5
commit ad928bd4e6
13 changed files with 48 additions and 26 deletions

View File

@ -1,13 +1,17 @@
# Changelog Fab Manager
- Ability to create and delete periodic calendar availabilities (recurrence)
- An administrator can delete a member
- Ability to configure the duration of a reservation slot. Previously, only 60 minutes slots were allowed
- Display indications on required fields in new administrator form
- Configuration of phone number in members registration forms: can be required or optional, depending on `PHONE_REQUIRED` configuration
- Improved user experience in defining slots in the calendar management
- Improved notification email to the member when a rolling subscription is taken
- Handle Ctrl^C in upgrade scripts
- Updated moment-timezone
- Fix a security issue: fixed [CVE-2019-15587](https://github.com/advisories/GHSA-c3gv-9cxf-6f57)
- [TODO DEPLOY] add the `SLOT_DURATION` environment variable (see [doc/environment.md](doc/environment.md#SLOT_DURATION) for configuration details)
- [TODO DEPLOY] add the `PHONE_REQUIRED` environment variable (see [doc/environment.md](doc/environment.md#PHONE_REQUIRED) for configuration details)
- [TODO DEPLOY] -> (only dev) `bundle install`
- [TODO DEPLOY] `rake db:migrate`

View File

@ -86,6 +86,8 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
$rootScope.fablabWithoutOnlinePayment = Fablab.withoutOnlinePayment;
// Global config: if true, no invoices will be generated
$rootScope.fablabWithoutInvoices = Fablab.withoutInvoices;
// Global config: if true, the phone number is required to create an account
$rootScope.phoneRequired = Fablab.phoneRequired;
// Global function to allow the user to navigate to the previous screen (ie. $state).
// If no previous $state were recorded, navigate to the home page

View File

@ -20,7 +20,7 @@
<form role="form" name="adminForm" class="form-horizontal" novalidate>
<section class="panel panel-default bg-light m-lg">
<div class="panel-body m-r">
<ng-include src="'<%= asset_path 'shared/_admin_form.html' %>'"></ng-include>
<ng-include src="'<%= asset_path "shared/_admin_form.html" %>'"></ng-include>
</div>

View File

@ -1,26 +1,27 @@
<div class="row m-t">
<div class="col-sm-offset-3 col-sm-6">
<div class="form-group" ng-class="{'has-error': adminForm['admin[statistic_profile_attributes][gender]'].$dirty && adminForm['admin[statistic_profile_attributes][gender]'].$invalid}">
<label class="checkbox-inline btn btn-default">
<input type="radio"
name="admin[statistic_profile_attributes][gender]"
ng-model="admin.statistic_profile_attributes.gender"
ng-value="true"
required/>
<i class="fa fa-male m-l-sm"></i> {{ 'man' | translate }}
</label>
<label class="checkbox-inline btn btn-default">
<input type="radio"
name="admin[statistic_profile_attributes][gender]"
ng-model="admin.statistic_profile_attributes.gender"
ng-value="false"/>
<i class="fa fa-female m-l-sm"></i> {{ 'woman' | translate }}
</label>
<label class="checkbox-inline btn btn-default">
<input type="radio"
name="admin[statistic_profile_attributes][gender]"
ng-model="admin.statistic_profile_attributes.gender"
ng-value="true"
required/>
<i class="fa fa-male m-l-sm"></i> {{ 'man' | translate }}
</label>
<label class="checkbox-inline btn btn-default">
<input type="radio"
name="admin[statistic_profile_attributes][gender]"
ng-model="admin.statistic_profile_attributes.gender"
ng-value="false"/>
<i class="fa fa-female m-l-sm"></i> {{ 'woman' | translate }}
</label>
<span class="exponent m-l-xs help-cursor"><i class="fa fa-asterisk" aria-hidden="true"></i></span>
</div>
<div class="form-group" ng-class="{'has-error': adminForm['admin[username]'].$dirty && adminForm['admin[username]'].$invalid}">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-user"></i></span>
<span class="input-group-addon"><i class="fa fa-user"></i> <span class="exponent"><i class="fa fa-asterisk" aria-hidden="true"></i></span></span>
<input ng-model="admin.username"
type="text" name="admin[username]"
class="form-control"
@ -33,7 +34,7 @@
<div class="form-group" ng-class="{'has-error': adminForm['admin[profile_attributes][last_name]'].$dirty && adminForm['admin[profile_attributes][last_name]'].$invalid}">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-user"></i></span>
<span class="input-group-addon"><i class="fa fa-user"></i> <span class="exponent"><i class="fa fa-asterisk" aria-hidden="true"></i></span></span>
<input ng-model="admin.profile_attributes.last_name"
type="text"
name="admin[profile_attributes][last_name]"
@ -47,7 +48,7 @@
<div class="form-group" ng-class="{'has-error': adminForm['admin[profile_attributes][first_name]'].$dirty && adminForm['admin[profile_attributes][first_name]'].$invalid}">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-user"></i></span>
<span class="input-group-addon"><i class="fa fa-user"></i> <span class="exponent"><i class="fa fa-asterisk" aria-hidden="true"></i></span></span>
<input ng-model="admin.profile_attributes.first_name"
type="text"
name="admin[profile_attributes][first_name]"
@ -61,7 +62,7 @@
<div class="form-group" ng-class="{'has-error': adminForm['admin[email]'].$dirty && adminForm['admin[email]'].$invalid}">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-envelope"></i> </span>
<span class="input-group-addon"><i class="fa fa-envelope"></i> <span class="exponent"><i class="fa fa-asterisk" aria-hidden="true"></i></span></span>
<input ng-model="admin.email"
type="email"
name="admin[email]"

View File

@ -240,7 +240,7 @@
<div class="form-group" ng-class="{'has-error': userForm['user[profile_attributes][phone]'].$dirty && userForm['user[profile_attributes][phone]'].$invalid}">
<div class="input-group">
<span class="input-group-addon help-cursor" title="{{ 'used_for_reservation' | translate }}"><i class="fa fa-phone"></i> <span class="exponent"><i class="fa fa-asterisk" aria-hidden="true"></i></span></span>
<span class="input-group-addon help-cursor" title="{{ 'used_for_reservation' | translate }}"><i class="fa fa-phone"></i> <span class="exponent" ng-show="phoneRequired"><i class="fa fa-asterisk" aria-hidden="true"></i></span></span>
<input type="text"
name="user[profile_attributes][phone]"
ng-model="user.profile.phone"
@ -248,7 +248,7 @@
id="user_phone"
placeholder="{{ 'phone_number' | translate }}"
ng-disabled="preventField['profile.phone'] && user.profile.phone && !userForm['user[profile_attributes][phone]'].$dirty"
required/>
ng-required="phoneRequired"/>
</div>
<span class="help-block" ng-show="userForm['user[profile_attributes][phone]'].$dirty && userForm['user[profile_attributes][phone]'].$error.required" translate>{{ 'phone_number_is_required' }}</span>
</div>

View File

@ -204,9 +204,11 @@
name="phone"
class="form-control"
placeholder="{{ 'phone_number' | translate }}"
required>
ng-required="phoneRequired">
</div>
<span class="exponent help-cursor" title="{{ 'used_for_reservation' | translate }}"><i class="fa fa-asterisk" aria-hidden="true"></i></span>
<span ng-show="phoneRequired" class="exponent help-cursor" title="{{ 'used_for_reservation' | translate }}">
<i class="fa fa-asterisk" aria-hidden="true"></i>
</span>
<span class="help-block" ng-show="signupForm.phone.$dirty && signupForm.phone.$error.required" translate>{{ 'phone_number_is_required' }}</span>
</div>
</div>

View File

@ -10,7 +10,7 @@ class Profile < ActiveRecord::Base
validates :first_name, presence: true, length: { maximum: 30 }
validates :last_name, presence: true, length: { maximum: 30 }
validates_numericality_of :phone, only_integer: true, allow_blank: false
validates_numericality_of :phone, only_integer: true, allow_blank: false, if: -> { Rails.application.secrets.phone_required }
after_commit :update_invoicing_profile, if: :invoicing_data_was_modified?, on: [:update]

View File

@ -160,7 +160,8 @@ class User < ActiveRecord::Base
def need_completion?
statistic_profile.gender.nil? || profile.first_name.blank? || profile.last_name.blank? || username.blank? ||
email.blank? || encrypted_password.blank? || group_id.nil? || statistic_profile.birthday.blank? || profile.phone.blank?
email.blank? || encrypted_password.blank? || group_id.nil? || statistic_profile.birthday.blank? ||
(Rails.application.secrets.phone_required && profile.phone.blank?)
end
## Retrieve the requested data in the User and user's Profile tables

View File

@ -20,6 +20,7 @@
Fablab.withoutSpaces = ('<%= Rails.application.secrets.fablab_without_spaces %>' !== 'false');
Fablab.withoutOnlinePayment = ('<%= Rails.application.secrets.fablab_without_online_payments %>' === 'true');
Fablab.withoutInvoices = ('<%= Rails.application.secrets.fablab_without_invoices %>' === 'true');
Fablab.phoneRequired = ('<%= Rails.application.secrets.phone_required %>' === 'true');
Fablab.slotDuration = parseInt("<%= ApplicationHelper::SLOT_DURATION %>", 10);
Fablab.disqusShortname = "<%= Rails.application.secrets.disqus_shortname %>";
Fablab.defaultHost = "<%= Rails.application.secrets.default_host %>";

View File

@ -20,6 +20,7 @@ FABLAB_WITHOUT_PLANS: 'false'
FABLAB_WITHOUT_SPACES: 'true'
FABLAB_WITHOUT_ONLINE_PAYMENT: 'false'
FABLAB_WITHOUT_INVOICES: 'false'
PHONE_REQUIRED: 'true'
SLOT_DURATION: '60'

View File

@ -20,6 +20,7 @@ development:
fablab_without_spaces: <%= ENV["FABLAB_WITHOUT_SPACES"] %>
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
phone_required: <%= ENV["PHONE_REQUIRED"] %>
slot_duration: <%= ENV["SLOT_DURATION"] %>
default_host: <%= ENV["DEFAULT_HOST"] %>
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
@ -63,6 +64,7 @@ test:
fablab_without_spaces: false
fablab_without_online_payments: false
fablab_without_invoices: false
phone_required: true
slot_duration: <%= ENV["SLOT_DURATION"] %>
default_host: <%= ENV["DEFAULT_HOST"] %>
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
@ -106,6 +108,7 @@ staging:
fablab_without_spaces: <%= ENV["FABLAB_WITHOUT_SPACES"] %>
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
phone_required: <%= ENV["PHONE_REQUIRED"] %>
slot_duration: <%= ENV["SLOT_DURATION"] %>
default_host: <%= ENV["DEFAULT_HOST"] %>
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
@ -160,6 +163,7 @@ production:
fablab_without_spaces: <%= ENV["FABLAB_WITHOUT_SPACES"] %>
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
phone_required: <%= ENV["PHONE_REQUIRED"] %>
slot_duration: <%= ENV["SLOT_DURATION"] %>
default_host: <%= ENV["DEFAULT_HOST"] %>
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>

View File

@ -102,6 +102,11 @@ Valid stripe API keys are still required, even if you don't require online payme
If set to 'true', the invoices will be disabled.
This is useful if you have your own invoicing system and you want to prevent Fab-manager from generating and sending invoices to members.
**Very important**: if you disable invoices, you still have to configure VAT in the interface to prevent errors in accounting and prices.
<a name="PHONE_REQUIRED"></a>
PHONE_REQUIRED
If set to 'false' the phone number won't be required to register a new user on the software.
<a name="SLOT_DURATION"></a>
SLOT_DURATION

View File

@ -13,6 +13,7 @@ FABLAB_WITHOUT_PLANS=false
FABLAB_WITHOUT_SPACES=true
FABLAB_WITHOUT_ONLINE_PAYMENT=true
FABLAB_WITHOUT_INVOICES=false
PHONE_REQUIRED=false
SLOT_DURATION=60