From 654d4b1cb418783f344f6959f8dfb516f34ce720 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 12 May 2020 15:04:06 +0200 Subject: [PATCH 001/209] setting: phone_required --- .../controllers/admin/settings.js.erb | 5 +++ .../templates/admin/settings/privacy.html | 37 ++++++++++++++++--- app/models/setting.rb | 3 +- config/locales/app.admin.en.yml | 7 +++- config/locales/app.admin.es.yml | 3 +- config/locales/app.admin.fr.yml | 7 +++- config/locales/app.admin.pt.yml | 3 +- 7 files changed, 55 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/controllers/admin/settings.js.erb b/app/assets/javascripts/controllers/admin/settings.js.erb index e48d2c2e6..91f61a357 100644 --- a/app/assets/javascripts/controllers/admin/settings.js.erb +++ b/app/assets/javascripts/controllers/admin/settings.js.erb @@ -134,6 +134,11 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope' value: (settingsPromise.fab_analytics === 'true') }; + $scope.phoneRequired = { + name: 'phone_required', + value: (settingsPromise.phone_required === 'true') + }; + // By default, we display the currently published privacy policy $scope.privacyPolicy = { version: null, diff --git a/app/assets/templates/admin/settings/privacy.html b/app/assets/templates/admin/settings/privacy.html index b57df6b55..fb3232313 100644 --- a/app/assets/templates/admin/settings/privacy.html +++ b/app/assets/templates/admin/settings/privacy.html @@ -1,11 +1,11 @@
- {{ 'app.admin.settings.privacy.title' }} + {{ 'app.admin.settings.privacy.privacy_policy' }}
-
+
@@ -17,7 +17,7 @@ {{ 'app.admin.settings.drag_and_drop_to_insert_images' | translate }}
-
+
@@ -38,10 +38,10 @@
- +
+ +
+
+ {{ 'app.admin.settings.privacy.various_settings' }} +
+
+

+ {{ 'app.admin.settings.privacy.phone_required_info' }} +

+
+
+ + + + +
+
+ +
+
\ No newline at end of file diff --git a/app/models/setting.rb b/app/models/setting.rb index 7327f4451..8c583ac71 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -75,7 +75,8 @@ class Setting < ApplicationRecord home_content home_css origin - uuid] } + uuid + phone_required] } def value last_value = history_values.order(HistoryValue.arel_table['created_at'].desc).first last_value&.value diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 60543d8a2..3a73cf1b1 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1019,6 +1019,7 @@ en: display_name_enable: "name display" machines_sort_by: "machines display order" fab_analytics: "Fab Analytics" + phone_required: "phone required" elements_ordering: "Elements ordering" machines_order: "Machines order" display_machines_sorted_by: "Display machines sorted by" @@ -1032,7 +1033,8 @@ en: created_at: "Creation date" updated_at: "Last update date" privacy: - title: "Privacy policy" + title: "Privacy" + privacy_policy: "Privacy policy" input_the_dpo: "Input the contact of the Data Protection Officer" current_policy: "Current policy" draft_from_USER_DATE: "Draft, saved by {USER}, on {DATE}" @@ -1056,6 +1058,9 @@ en: online_payment: "Is the online payment module active?" invoices: "Is the invoicing module active?" openlab: "Is the project sharing module (OpenLab) active?" + various_settings: "Various settings" + phone_required: "Phone required" + phone_required_info: "You can define if the phone number should be required to register a new user on Fab-manager." open_api_clients: add_new_client: "Create new API client" api_documentation: "API documentation" diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index 5721bff36..13adbc604 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -1032,7 +1032,8 @@ es: created_at: "Fecha de creación" updated_at: "Fecha de actualización" privacy: - title: "Política de privacidad" + title: "Privacidad" + privacy_policy: "Política de privacidad" input_the_dpo: "Input the contact of the Data Protection Officer" current_policy: "Política de privacidad" draft_from_USER_DATE: "Borrador, guardado por {USER}, el {DATE}" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 5d9281afb..b485c88c8 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1019,6 +1019,7 @@ fr: display_name_enable: "l'affichage du nom" machines_sort_by: "l'ordre d'affichage des machines" fab_analytics: "Fab Analytics" + phone_required: "téléphone requis" elements_ordering: "Ordre d'affichage des éléments" machines_order: "Ordre des machines" display_machines_sorted_by: "Afficher les machines triées par" @@ -1032,7 +1033,8 @@ fr: created_at: "Date de création" updated_at: "Date de mise à jour" privacy: - title: "Politique de confidentialité" + title: "Confidentialité" + privacy_policy: "Politique de confidentialité" input_the_dpo: "Saisir le contact du Délégué à la protection des données" current_policy: "Politique courante" draft_from_USER_DATE: "Brouillon, enregistré par {USER}, le {DATE}" @@ -1056,6 +1058,9 @@ fr: online_payment: "Le module de paiement par carte bancaire est-il actif ?" invoices: "Le module est facturation est-il actif ?" openlab: "Le module de partage de projets (OpenLab) est-il actif ?" + various_settings: "Paramètres divers" + phone_required: "Téléphone requis" + phone_required_info: "Vous pouvez définir si le numéro de téléphone doit être requis, lors de l'enregistrement d'un nouvel utilisateur sur Fab-manager." open_api_clients: add_new_client: "Créer un compte client" api_documentation: "Documentation de l'API" diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index 83e4b8aec..18a1bfc02 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -1032,7 +1032,8 @@ pt: created_at: "Data de criação" updated_at: "Última Data de Atualização" privacy: - title: "Política de privacidade" + title: "Privacidade" + privacy_policy: "Política de privacidade" input_the_dpo: "Input the contact of the Data Protection Officer" current_policy: "Current policy" draft_from_USER_DATE: "Draft, saved by {USER}, on {DATE}" From f47af21b421559affcad250e27b36f7cc2258a02 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 13 May 2020 14:46:25 +0200 Subject: [PATCH 002/209] delete old application.yml this file, used in development environment, was replaced by .env since v4.3.3 --- config/application.yml.default | 102 --------------------------------- doc/environment.md | 4 +- doc/translation_readme.md | 4 +- 3 files changed, 4 insertions(+), 106 deletions(-) delete mode 100644 config/application.yml.default diff --git a/config/application.yml.default b/config/application.yml.default deleted file mode 100644 index c897a115b..000000000 --- a/config/application.yml.default +++ /dev/null @@ -1,102 +0,0 @@ -# Add application configuration variables here, as shown below. - -# Databases -POSTGRES_HOST: fabmanager-postgres -POSTGRES_PASSWORD: -REDIS_HOST: fabmanager-redis -ELASTICSEARCH_HOST: fabmanager-elastic - -# Stripe -SECRET_KEY_BASE: 83daf5e7b80d990f037407bab78dff9904aaf3c195a50f84fa8695a22287e707dfbd9524b403b1dcf116ae1d8c06844c3d7ed942564e5b46be6ae3ead93a9d30 -STRIPE_API_KEY: -STRIPE_PUBLISHABLE_KEY: -STRIPE_CURRENCY: 'eur' - -# Invoices -INVOICE_PREFIX: Demo-FabLab-facture - -# FabLab optional modules -FABLAB_WITHOUT_PLANS: 'false' -FABLAB_WITHOUT_SPACES: 'true' -FABLAB_WITHOUT_ONLINE_PAYMENT: 'false' -FABLAB_WITHOUT_INVOICES: 'false' -PHONE_REQUIRED: 'true' -FABLAB_WITHOUT_WALLET: 'false' -BOOK_SLOT_AT_SAME_TIME: 'true' - -USER_CONFIRMATION_NEEDED_TO_SIGN_IN: 'false' - -EVENTS_IN_CALENDAR: 'false' -SLOT_DURATION: '60' -FEATURE_TOUR_DISPLAY: 'once' - -DEFAULT_MAIL_FROM: Fab-manager Demo - -# Configure carefully! -DEFAULT_HOST: 'localhost:5000' -DEFAULT_PROTOCOL: http - -# Email config -DELIVERY_METHOD: smtp -SMTP_ADDRESS: -SMTP_PORT: '587' -SMTP_USER_NAME: -SMTP_PASSWORD: -SMTP_AUTHENTICATION: 'plain' -SMTP_ENABLE_STARTTLS_AUTO: 'true' -SMTP_OPENSSL_VERIFY_MODE: '' -SMTP_TLS: 'false' - -# Google analytics -GA_ID: '' - -# Google recaptcha -RECAPTCHA_SITE_KEY: '' -RECAPTCHA_SECRET_KEY: '' - -# Projects comments -DISQUS_SHORTNAME: - -# Twitter sharing -TWITTER_NAME: 'FablabGrenoble' - -# Facebook sharing -FACEBOOK_APP_ID: '' - -# I18N configuration -RAILS_LOCALE: 'fr' -APP_LOCALE: 'fr' -MOMENT_LOCALE: 'fr' -SUMMERNOTE_LOCALE: 'fr-FR' -ANGULAR_LOCALE: 'fr-fr' -FULLCALENDAR_LOCALE: 'fr' - -ELASTICSEARCH_LANGUAGE_ANALYZER: 'french' - -TIME_ZONE: 'Paris' -WEEK_STARTING_DAY: 'monday' -D3_DATE_FORMAT: '%d/%m/%y' -UIB_DATE_FORMAT: 'dd/MM/yyyy' -EXCEL_DATE_FORMAT: 'dd/mm/yyyy' - -# OpenLab Projects -OPENLAB_APP_SECRET: -OPENLAB_APP_ID: -OPENLAB_DEFAULT: 'true' -# do not change this URL -OPENLAB_BASE_URI: 'https://openprojects.fab-manager.com' - -# System settings -LOG_LEVEL: 'debug' -DISK_SPACE_MB_ALERT: '100' -SUPERADMIN_EMAIL: 'admin@sleede.com' - -ALLOWED_EXTENSIONS: pdf ai eps cad math svg stl dxf dwg obj step iges igs 3dm 3dmf doc docx png ino scad fcad skp sldprt sldasm slddrw slddrt tex latex ps fcstd fcstd1 -ALLOWED_MIME_TYPES: application/pdf application/postscript application/illustrator image/x-eps image/svg+xml application/sla application/dxf application/acad application/dwg application/octet-stream application/step application/iges model/iges x-world/x-3dmf application/vnd.openxmlformats-officedocument.wordprocessingml.document image/png text/x-arduino text/plain application/scad application/vnd.sketchup.skp application/x-koan application/vnd-koan koan/x-skm application/vnd.koan application/x-tex application/x-latex application/x-extension-fcstd - -# 5242880 = 5 megabytes -MAX_IMPORT_SIZE: '5242880' -# 10485760 = 10 megabytes -MAX_IMAGE_SIZE: '10485760' -# 20971520 = 20 megabytes -MAX_CAO_SIZE: '20971520' diff --git a/doc/environment.md b/doc/environment.md index c98a597df..fa115feeb 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -13,8 +13,8 @@ The following environment variables configure the addresses of the databases, some credentials, some application behaviours and the localization preferences. If you are in a development environment, your can keep most of the default values, otherwise, in production, values must be configured carefully. -The settings in [config/application.yml](../config/application.yml.default) configure the environment variables when the application run in development mode. -If you run the application in production with docker, the settings are localized in [config/env](../docker/env.example). +The settings in [.env](../env.example) configure the environment variables when the application run in development mode. +If you run the application in production with docker, the settings are localized in [config/env](../setup/env.example). ## General settings diff --git a/doc/translation_readme.md b/doc/translation_readme.md index 51f31dfb4..ed472d56e 100644 --- a/doc/translation_readme.md +++ b/doc/translation_readme.md @@ -79,8 +79,8 @@ Use it to generate a similar localised PNG image which keep the default image si ## Configuration -In development, locales configurations are made in [config/application.yml](../config/application.yml.default). -In production, locales configuration are made in the [config/env](../docker/env.example) file. +In development, locales configurations are made in [.env](../env.example). +In production, locales configuration are made in the [config/env](../setup/env.example) file. If you are in a development environment, your can keep the default values, otherwise, in production, values must be configured carefully. From f80eb230cab4385cf769a25e061747b65b46baa9 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 13 May 2020 15:02:03 +0200 Subject: [PATCH 003/209] refactored code to use Setting.get --- app/controllers/api/availabilities_controller.rb | 4 ++-- app/controllers/api/machines_controller.rb | 2 +- app/controllers/api/version_controller.rb | 2 +- app/controllers/rss/events_controller.rb | 2 +- app/controllers/rss/projects_controller.rb | 2 +- app/models/profile.rb | 2 +- app/models/setting.rb | 9 +++++++++ app/models/stylesheet.rb | 6 +++--- app/pdfs/pdf/invoice.rb | 10 +++++----- app/policies/slot_policy.rb | 4 ++-- app/services/accounting_export_service.rb | 2 +- app/services/availabilities/status_service.rb | 2 +- app/services/health_service.rb | 4 ++-- app/services/invoice_reference_service.rb | 4 ++-- app/views/application/index.html.erb | 2 +- app/views/layouts/notifications_mailer.html.erb | 4 ++-- .../notify_user_auth_migration.html.erb | 2 +- .../notify_user_role_update.html.erb | 4 ++-- .../notify_user_account_created.html.erb | 4 ++-- db/seeds.rb | 4 ++-- doc/environment.md | 5 ----- lib/fab_hub.rb | 4 ++-- lib/version.rb | 2 +- test/integration/exports/accounting_export_test.rb | 14 +++++++------- 24 files changed, 52 insertions(+), 48 deletions(-) diff --git a/app/controllers/api/availabilities_controller.rb b/app/controllers/api/availabilities_controller.rb index bc9215379..76ff02bbd 100644 --- a/app/controllers/api/availabilities_controller.rb +++ b/app/controllers/api/availabilities_controller.rb @@ -193,7 +193,7 @@ class API::AvailabilitiesController < API::ApiController end def define_max_visibility - @visi_max_year = Setting.find_by(name: 'visibility_yearly').value.to_i.months.since - @visi_max_other = Setting.find_by(name: 'visibility_others').value.to_i.months.since + @visi_max_year = Setting.get('visibility_yearly').to_i.months.since + @visi_max_other = Setting.get('visibility_others').to_i.months.since end end diff --git a/app/controllers/api/machines_controller.rb b/app/controllers/api/machines_controller.rb index edcb6fb1e..c2c50a58d 100644 --- a/app/controllers/api/machines_controller.rb +++ b/app/controllers/api/machines_controller.rb @@ -7,7 +7,7 @@ class API::MachinesController < API::ApiController respond_to :json def index - sort_by = Setting.find_by(name: 'machines_sort_by').value || 'default' + sort_by = Setting.get('machines_sort_by') || 'default' @machines = if sort_by == 'default' Machine.includes(:machine_image, :plans) else diff --git a/app/controllers/api/version_controller.rb b/app/controllers/api/version_controller.rb index 41a616fe3..9c44c7c9c 100644 --- a/app/controllers/api/version_controller.rb +++ b/app/controllers/api/version_controller.rb @@ -15,7 +15,7 @@ class API::VersionController < API::ApiController origin.save! end # get the last version - update_status = Setting.find_by(name: 'hub_last_version')&.value || '{}' + update_status = Setting.get('hub_last_version') || '{}' json = JSON.parse(update_status) json['current'] = Version.current diff --git a/app/controllers/rss/events_controller.rb b/app/controllers/rss/events_controller.rb index 63ea6a657..0986c490c 100644 --- a/app/controllers/rss/events_controller.rb +++ b/app/controllers/rss/events_controller.rb @@ -7,6 +7,6 @@ class Rss::EventsController < Rss::RssController @events = Event.includes(:event_image, :event_files, :availability, :category) .where('availabilities.start_at >= ?', DateTime.current) .order('availabilities.start_at ASC').references(:availabilities).limit(10) - @fab_name = Setting.find_by(name: 'fablab_name').value + @fab_name = Setting.get('fablab_name') end end diff --git a/app/controllers/rss/projects_controller.rb b/app/controllers/rss/projects_controller.rb index 75a9736ea..88603e70c 100644 --- a/app/controllers/rss/projects_controller.rb +++ b/app/controllers/rss/projects_controller.rb @@ -2,6 +2,6 @@ class Rss::ProjectsController < Rss::RssController def index @projects = Project.includes(:project_image, :users).published.order('created_at desc').limit(10) - @fab_name = Setting.find_by(name: 'fablab_name').value + @fab_name = Setting.get('fablab_name') end end diff --git a/app/models/profile.rb b/app/models/profile.rb index bea552509..e09cb8278 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -10,7 +10,7 @@ class Profile < ApplicationRecord 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, if: -> { Rails.application.secrets.phone_required } + validates_numericality_of :phone, only_integer: true, allow_blank: false, if: -> { Setting.get('phone_required') } after_commit :update_invoicing_profile, if: :invoicing_data_was_modified?, on: [:update] diff --git a/app/models/setting.rb b/app/models/setting.rb index 8c583ac71..60d103d1a 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -91,4 +91,13 @@ class Setting < ApplicationRecord admin = User.admins.first save && history_values.create(invoicing_profile: admin.invoicing_profile, value: val) end + + ## + # Return the value of the requested setting + # Usage: Setting.get('my_setting') + # @return {string} + ## + def self.get(name) + find_by(name: name)&.value + end end diff --git a/app/models/stylesheet.rb b/app/models/stylesheet.rb index 6f9f9ecf2..3e634ad4a 100644 --- a/app/models/stylesheet.rb +++ b/app/models/stylesheet.rb @@ -34,11 +34,11 @@ class Stylesheet < ApplicationRecord end def self.primary - Setting.find_by(name: 'main_color')&.value + Setting.get('main_color') end def self.secondary - Setting.find_by(name: 'secondary_color')&.value + Setting.get('secondary_color') end def self.primary_light @@ -124,7 +124,7 @@ class Stylesheet < ApplicationRecord ## ===== HOME PAGE ===== def self.home_style - style = Setting.find_by(name: 'home_css')&.value + style = Setting.get('home_css') ".home-page { #{style} }" end diff --git a/app/pdfs/pdf/invoice.rb b/app/pdfs/pdf/invoice.rb index 5d0f8a5cc..203c260fb 100644 --- a/app/pdfs/pdf/invoice.rb +++ b/app/pdfs/pdf/invoice.rb @@ -41,8 +41,8 @@ class PDF::Invoice < Prawn::Document else text I18n.t('invoices.invoice_reference', REF: invoice.reference), leading: 3 end - if Setting.find_by(name: 'invoice_code-active').value == 'true' - text I18n.t('invoices.code', CODE: Setting.find_by(name: 'invoice_code-value').value), leading: 3 + if Setting.get('invoice_code-active') == 'true' + text I18n.t('invoices.code', CODE: Setting.get('invoice_code-value')), leading: 3 end if invoice.invoiced_type != WalletTransaction.name if invoice.is_a?(Avoir) @@ -251,7 +251,7 @@ class PDF::Invoice < Prawn::Document row(0).font_style = :bold column(1).style align: :right - if Setting.find_by(name: 'invoice_VAT-active').value == 'true' + if Setting.get('invoice_VAT-active') == 'true' # Total incl. taxes row(-1).style align: :right row(-1).background_color = 'E4E4E4' @@ -332,7 +332,7 @@ class PDF::Invoice < Prawn::Document # important information move_down 40 - txt = parse_html(Setting.find_by(name: 'invoice_text').value) + txt = parse_html(Setting.get('invoice_text')) txt.each_line do |line| text line, style: :bold, inline_format: true end @@ -340,7 +340,7 @@ class PDF::Invoice < Prawn::Document # address and legals information move_down 40 - txt = parse_html(Setting.find_by(name: 'invoice_legals').value) + txt = parse_html(Setting.get('invoice_legals')) txt.each_line do |line| text line, align: :right, leading: 4, inline_format: true end diff --git a/app/policies/slot_policy.rb b/app/policies/slot_policy.rb index a7240c230..29d86a303 100644 --- a/app/policies/slot_policy.rb +++ b/app/policies/slot_policy.rb @@ -4,8 +4,8 @@ class SlotPolicy < ApplicationPolicy def update? # check that the update is allowed and the prevention delay has not expired - delay = Setting.find_by(name: 'booking_move_delay').value.to_i - enabled = (Setting.find_by(name: 'booking_move_enable').value == 'true') + delay = Setting.get('booking_move_delay').to_i + enabled = (Setting.get('booking_move_enable') == 'true') # these condition does not apply to admins user.admin? || user.manager? || diff --git a/app/services/accounting_export_service.rb b/app/services/accounting_export_service.rb index abe8791bb..1e7e502bf 100644 --- a/app/services/accounting_export_service.rb +++ b/app/services/accounting_export_service.rb @@ -15,7 +15,7 @@ class AccountingExportService @date_format = '%d/%m/%Y' @label_max_length = 50 @export_zeros = false - @journal_code = Setting.find_by(name: 'accounting_journal_code')&.value || '' + @journal_code = Setting.get('accounting_journal_code') || '' @date_format = date_format @columns = columns end diff --git a/app/services/availabilities/status_service.rb b/app/services/availabilities/status_service.rb index 1e71c2aa3..90dc2321a 100644 --- a/app/services/availabilities/status_service.rb +++ b/app/services/availabilities/status_service.rb @@ -4,7 +4,7 @@ class Availabilities::StatusService def initialize(current_user_role) @current_user_role = current_user_role - @show_name = (@current_user_role == 'admin' || Setting.find_by(name: 'display_name_enable').value == 'true') + @show_name = (@current_user_role == 'admin' || Setting.get('display_name_enable') == 'true') end # check that the provided machine slot is reserved or not and modify it accordingly diff --git a/app/services/health_service.rb b/app/services/health_service.rb index 4339b525c..05b8c7f33 100644 --- a/app/services/health_service.rb +++ b/app/services/health_service.rb @@ -48,7 +48,7 @@ class HealthService end def self.stats - enable = Setting.find_by(name: 'fab_analytics')&.value + enable = Setting.get('fab_analytics') return false if enable == 'false' require 'openssl' @@ -56,7 +56,7 @@ class HealthService row_stats.to_json.to_s - key = Setting.find_by(name: 'hub_public_key')&.value + key = Setting.get('hub_public_key') return false unless key public_key = OpenSSL::PKey::RSA.new(key) diff --git a/app/services/invoice_reference_service.rb b/app/services/invoice_reference_service.rb index 966a76b15..7e77c992e 100644 --- a/app/services/invoice_reference_service.rb +++ b/app/services/invoice_reference_service.rb @@ -4,7 +4,7 @@ class InvoiceReferenceService class << self def generate_reference(invoice, date: DateTime.current, avoir: false) - pattern = Setting.find_by(name: 'invoice_reference').value + pattern = Setting.get('invoice_reference') reference = replace_invoice_number_pattern(pattern, invoice) reference = replace_date_pattern(reference, date) @@ -31,7 +31,7 @@ class InvoiceReferenceService end def generate_order_number(invoice) - pattern = Setting.find_by(name: 'invoice_order-nb').value + pattern = Setting.get('invoice_order-nb') # global invoice number (nn..nn) reference = pattern.gsub(/n+(?![^\[]*\])/) do |match| diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index 4350be3b4..63c3e9f61 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -7,7 +7,7 @@ - <%=Setting.find_by(name: 'fablab_name').value%> + <%=Setting.get('fablab_name')%> diff --git a/app/views/layouts/notifications_mailer.html.erb b/app/views/layouts/notifications_mailer.html.erb index 7b16662b6..884a6d46e 100644 --- a/app/views/layouts/notifications_mailer.html.erb +++ b/app/views/layouts/notifications_mailer.html.erb @@ -1,5 +1,5 @@ -<% fablab_name = Setting.find_by(name: 'fablab_name').value %> -<% fablab_gender = Setting.find_by(name: 'name_genre').value %> +<% fablab_name = Setting.get('fablab_name') %> +<% fablab_gender = Setting.get('name_genre') %> <% primary_color = Stylesheet.primary %> diff --git a/app/views/notifications_mailer/notify_user_auth_migration.html.erb b/app/views/notifications_mailer/notify_user_auth_migration.html.erb index 5cdca27f5..832a20398 100644 --- a/app/views/notifications_mailer/notify_user_auth_migration.html.erb +++ b/app/views/notifications_mailer/notify_user_auth_migration.html.erb @@ -18,7 +18,7 @@ url_path = File.join(root_url, 'sso-redirect') %> -

<%= t(".body.the_platform") %> <%= Setting.find_by(name: 'fablab_name').value %> <%= t(".body.is_changing_its_auth_system_and_will_now_use") %> <%= active_provider.name %> <%= t(".body.instead_of") %> <%= AuthProvider.find_by(status: 'previous').name %>.

+

<%= t(".body.the_platform") %> <%= Setting.get('fablab_name') %> <%= t(".body.is_changing_its_auth_system_and_will_now_use") %> <%= active_provider.name %> <%= t(".body.instead_of") %> <%= AuthProvider.find_by(status: 'previous').name %>.

<%= t('.body.consequence_of_the_modification') %>

diff --git a/app/views/notifications_mailer/notify_user_role_update.html.erb b/app/views/notifications_mailer/notify_user_role_update.html.erb index d10e1abca..27191a2df 100644 --- a/app/views/notifications_mailer/notify_user_role_update.html.erb +++ b/app/views/notifications_mailer/notify_user_role_update.html.erb @@ -1,8 +1,8 @@ <%= render 'notifications_mailer/shared/hello', recipient: @recipient %> <% - name = Setting.find_by(name: 'fablab_name').value - gender = Setting.find_by(name: 'name_genre').value + name = Setting.get('fablab_name') + gender = Setting.get('name_genre') %>

<%= _t('.body.role_changed_html', { diff --git a/app/views/users_mailer/notify_user_account_created.html.erb b/app/views/users_mailer/notify_user_account_created.html.erb index d5f095603..cee17f58d 100644 --- a/app/views/users_mailer/notify_user_account_created.html.erb +++ b/app/views/users_mailer/notify_user_account_created.html.erb @@ -17,8 +17,8 @@

<%= _t('.body.intro', { - GENDER: Setting.find_by(name: 'name_genre').value, - FABLAB: Setting.find_by(name: 'fablab_name').value + GENDER: Setting.get('name_genre'), + FABLAB: Setting.get('fablab_name') }) # messageFormat %> <%= link_to URI(root_url).host, root_url %>. diff --git a/db/seeds.rb b/db/seeds.rb index 545fedae6..e9413f7fb 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -918,8 +918,8 @@ end unless Setting.find_by(name: 'link_name').try(:value) include ApplicationHelper # rubocop:disable Style/MixinUsage - name = Setting.find_by(name: 'fablab_name').value - gender = Setting.find_by(name: 'name_genre').value + name = Setting.get('fablab_name') + gender = Setting.get('name_genre') setting = Setting.find_or_initialize_by(name: 'link_name') setting.value = _t('app.public.common.about_the_fablab', NAME: name, GENDER: gender) setting.save diff --git a/doc/environment.md b/doc/environment.md index fa115feeb..d7a047c47 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -112,11 +112,6 @@ This is useful if you have your own invoicing system and you want to prevent Fab If set to 'true', the wallet will be disabled. This is useful if you won't use wallet system. - - - PHONE_REQUIRED - -If set to 'false' the phone number won't be required to register a new user on the software. BOOK_SLOT_AT_SAME_TIME diff --git a/lib/fab_hub.rb b/lib/fab_hub.rb index 506f67470..36468b6a5 100644 --- a/lib/fab_hub.rb +++ b/lib/fab_hub.rb @@ -3,8 +3,8 @@ # Fab-manager central hub (remote host) class FabHub def self.version_check_payload - uuid = Setting.find_by(name: 'uuid')&.value - origin = Setting.find_by(name: 'origin')&.value || "#{Rails.application.secrets.default_protocol}://#{Rails.application.secrets.default_host}" + uuid = Setting.get('uuid') + origin = Setting.get('origin') || "#{Rails.application.secrets.default_protocol}://#{Rails.application.secrets.default_host}" { uuid: uuid, origin: origin, diff --git a/lib/version.rb b/lib/version.rb index f6a0f3736..75666e664 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -10,7 +10,7 @@ class Version # currently published def self.up_to_date? - hub_version = Setting.find_by(name: 'hub_last_version')&.value + hub_version = Setting.get('hub_last_version') return unless hub_version json = JSON.parse(hub_version) diff --git a/test/integration/exports/accounting_export_test.rb b/test/integration/exports/accounting_export_test.rb index 8cf2e32af..dfc308b45 100644 --- a/test/integration/exports/accounting_export_test.rb +++ b/test/integration/exports/accounting_export_test.rb @@ -51,7 +51,7 @@ class Exports::AccountingExportTest < ActionDispatch::IntegrationTest # test values # first line = client line - journal_code = Setting.find_by(name: 'accounting_journal_code').value + journal_code = Setting.get('accounting_journal_code') assert_equal journal_code, data[0][I18n.t('accounting_export.journal_code')], 'Wrong journal code' first_invoice = Invoice.first @@ -59,10 +59,10 @@ class Exports::AccountingExportTest < ActionDispatch::IntegrationTest assert_equal entry_date, DateTime.parse(data[0][I18n.t('accounting_export.date')]), 'Wrong date' if first_invoice.paid_with_stripe? - card_client_code = Setting.find_by(name: 'accounting_card_client_code').value + card_client_code = Setting.get('accounting_card_client_code') assert_equal card_client_code, data[0][I18n.t('accounting_export.account_code')], 'Account code for card client is wrong' - card_client_label = Setting.find_by(name: 'accounting_card_client_label').value + card_client_label = Setting.get('accounting_card_client_label') assert_equal card_client_label, data[0][I18n.t('accounting_export.account_label')], 'Account label for card client is wrong' else STDERR.puts "WARNING: unable to test accurately accounting export: invoice #{first_invoice.id} was not paid by card" @@ -93,10 +93,10 @@ class Exports::AccountingExportTest < ActionDispatch::IntegrationTest assert_equal entry_date, DateTime.parse(data[1][I18n.t('accounting_export.date')]), 'Wrong date' if first_invoice.subscription_invoice? - subscription_code = Setting.find_by(name: 'accounting_subscription_code').value + subscription_code = Setting.get('accounting_subscription_code') assert_equal subscription_code, data[1][I18n.t('accounting_export.account_code')], 'Account code for subscription is wrong' - subscription_label = Setting.find_by(name: 'accounting_subscription_label').value + subscription_label = Setting.get('accounting_subscription_label') assert_equal subscription_label, data[1][I18n.t('accounting_export.account_label')], 'Account label for subscription is wrong' end @@ -122,10 +122,10 @@ class Exports::AccountingExportTest < ActionDispatch::IntegrationTest client_row[I18n.t('accounting_export.line_label')], 'Line label does not contains the reference to the invoiced item' - machine_code = Setting.find_by(name: 'accounting_Machine_code').value + machine_code = Setting.get('accounting_Machine_code') assert_equal machine_code, item_row[I18n.t('accounting_export.account_code')], 'Account code for machine reservation is wrong' - machine_label = Setting.find_by(name: 'accounting_Machine_label').value + machine_label = Setting.get('accounting_Machine_label') assert_equal machine_label, item_row[I18n.t('accounting_export.account_label')], 'Account label for machine reservation is wrong' else From 13bcd9a1f883d280be94e31889cd7bc42cada442 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 13 May 2020 15:52:01 +0200 Subject: [PATCH 004/209] use phoneRequired from settings instead of env --- app/assets/javascripts/router.js.erb | 2 +- app/models/setting.rb | 12 +++++++++--- app/models/user.rb | 2 +- app/views/application/index.html.erb | 2 +- config/secrets.yml | 4 ---- db/seeds.rb | 6 ++++++ 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/router.js.erb b/app/assets/javascripts/router.js.erb index b4d800d98..d9afa808d 100644 --- a/app/assets/javascripts/router.js.erb +++ b/app/assets/javascripts/router.js.erb @@ -1019,7 +1019,7 @@ angular.module('application.router', ['ui.router']) 'fablab_name', 'name_genre', 'reminder_enable', \ 'reminder_delay', 'visibility_yearly', 'visibility_others', \ 'display_name_enable', 'machines_sort_by', 'fab_analytics', \ - 'link_name', 'home_content', 'home_css']` }).$promise; + 'link_name', 'home_content', 'home_css', 'phone_required']` }).$promise; }], privacyDraftsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'privacy_draft', history: true }).$promise; }], cguFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'cgu-file' }).$promise; }], diff --git a/app/models/setting.rb b/app/models/setting.rb index 60d103d1a..a3b536f41 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -93,11 +93,17 @@ class Setting < ApplicationRecord end ## - # Return the value of the requested setting + # Return the value of the requested setting, if any. # Usage: Setting.get('my_setting') - # @return {string} + # @return {String} ## def self.get(name) - find_by(name: name)&.value + res = find_by(name: name)&.value + + # handle boolean values + return true if res == 'true' + return false if res == 'false' + + res end end diff --git a/app/models/user.rb b/app/models/user.rb index 545285114..9b328a59a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -203,7 +203,7 @@ class User < ApplicationRecord 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? || - (Rails.application.secrets.phone_required && profile.phone.blank?) + (Setting.get('phone_required') && profile.phone.blank?) end ## Retrieve the requested data in the User and user's Profile tables diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index 63c3e9f61..cf2951765 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -27,7 +27,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.phoneRequired = ('<%= Setting.get('phone_required') %>' === 'true'); Fablab.fablabWithoutWallet = ('<%= Rails.application.secrets.fablab_without_wallet %>' === 'true'); Fablab.bookSlotAtSameTime = ('<%= Rails.application.secrets.book_slot_at_same_time %>' === 'true'); Fablab.eventsInCalendar = ('<%= Rails.application.secrets.events_in_calendar %>' === 'true'); diff --git a/config/secrets.yml b/config/secrets.yml index 6a261a3ec..3479c252c 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -20,7 +20,6 @@ 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"] %> fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %> book_slot_at_same_time: <%= ENV["BOOK_SLOT_AT_SAME_TIME"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> @@ -68,7 +67,6 @@ test: fablab_without_spaces: false fablab_without_online_payments: false fablab_without_invoices: false - phone_required: true fablab_without_wallet: false book_slot_at_same_time: true user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> @@ -116,7 +114,6 @@ 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"] %> fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %> book_slot_at_same_time: <%= ENV["BOOK_SLOT_AT_SAME_TIME"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> @@ -176,7 +173,6 @@ 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"] %> fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %> book_slot_at_same_time: <%= ENV["BOOK_SLOT_AT_SAME_TIME"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> diff --git a/db/seeds.rb b/db/seeds.rb index e9413f7fb..5ab927adc 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -925,6 +925,12 @@ unless Setting.find_by(name: 'link_name').try(:value) setting.save end +unless Setting.find_by(name: 'phone_required').try(:value) + setting = Setting.find_or_initialize_by(name: 'phone_required') + setting.value = 'true' + setting.save +end + unless Setting.find_by(name: 'home_content').try(:value) setting = Setting.find_or_initialize_by(name: 'home_content') setting.value = <<~HTML From 2c17cfafedf12bb5a2a5ad28c25549164adcab35 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 13 May 2020 15:54:25 +0200 Subject: [PATCH 005/209] initialize phoneRequired from env --- db/seeds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/seeds.rb b/db/seeds.rb index 5ab927adc..a7ce23b4d 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -927,7 +927,7 @@ end unless Setting.find_by(name: 'phone_required').try(:value) setting = Setting.find_or_initialize_by(name: 'phone_required') - setting.value = 'true' + setting.value = ENV.fetch('PHONE_REQUIRED', 'true') setting.save end From 701d18d50149f14120ea581c88a0fb56e743a19f Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 13 May 2020 16:02:54 +0200 Subject: [PATCH 006/209] Improved display of the icons alerting about an outdated version --- CHANGELOG.md | 2 ++ app/views/application/index.html.erb | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7aa368bbf..67e1eab66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog Fab-manager +- Improved display of the icons alerting about an outdated version + ## v4.4.4 2020 May 25 - Fix a security issue: updated puma from 3.12.4 to 3.12.6 to fix [CVE-2020-11077](https://nvd.nist.gov/vuln/detail/CVE-2020-11077) and [CVE-2020-11076](https://nvd.nist.gov/vuln/detail/CVE-2020-11076) diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index cf2951765..3085ee7a3 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -129,8 +129,8 @@

- - + + Powered by Fab-manager
From 484102721634cfdc9621fb19d5f9b83529dae02b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 13 May 2020 16:28:32 +0200 Subject: [PATCH 007/209] interface to collect the google analytics ID --- app/assets/templates/admin/settings/privacy.html | 14 ++++++++++++++ config/locales/app.admin.en.yml | 2 ++ config/locales/app.admin.fr.yml | 2 ++ 3 files changed, 18 insertions(+) diff --git a/app/assets/templates/admin/settings/privacy.html b/app/assets/templates/admin/settings/privacy.html index fb3232313..9c63ff604 100644 --- a/app/assets/templates/admin/settings/privacy.html +++ b/app/assets/templates/admin/settings/privacy.html @@ -81,6 +81,20 @@
+

+
+
+ + + + +
+
\ No newline at end of file diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 3a73cf1b1..8b8dfc3e9 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1061,6 +1061,8 @@ en: various_settings: "Various settings" phone_required: "Phone required" phone_required_info: "You can define if the phone number should be required to register a new user on Fab-manager." + google_analytics_info_html: "To enable the statistical tracking of the visits using Google Analytics, set your tracking ID here. It is in the form UA-000000-2. Visit the Google Analytics website to get one.Warning : if you enable this feature, remember to write it in your privacy policy, above." + google_analytics: "Tracking ID" open_api_clients: add_new_client: "Create new API client" api_documentation: "API documentation" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index b485c88c8..4235bb11d 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1061,6 +1061,8 @@ fr: various_settings: "Paramètres divers" phone_required: "Téléphone requis" phone_required_info: "Vous pouvez définir si le numéro de téléphone doit être requis, lors de l'enregistrement d'un nouvel utilisateur sur Fab-manager." + google_analytics_info_html: "Pour activer les suivi statistique des visites utilisant Google Analytics, définissez ici votre ID de suivi. Il se présente sous la forme UA-000000-2. Visitez le site web de Google Analytics pour en obtenir un.
Attention : si vous activez cette fonctionnalité, pensez à l'indiquer dans votre politique de confidentialité, ci-dessus." + google_analytics: "ID de suivi" open_api_clients: add_new_client: "Créer un compte client" api_documentation: "Documentation de l'API" From 419605e551f17bd28b2a90ab5e09e4ddecc0de22 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 19 May 2020 16:20:59 +0200 Subject: [PATCH 008/209] configuration of google analytics tracking ID through the settings interface --- CHANGELOG.md | 1 + .../javascripts/controllers/admin/settings.js.erb | 1 + app/assets/javascripts/router.js.erb | 2 +- app/assets/templates/admin/settings/privacy.html | 10 +++++----- app/models/setting.rb | 3 ++- app/views/application/index.html.erb | 2 +- config/locales/app.admin.en.yml | 5 +++-- config/locales/app.admin.fr.yml | 5 +++-- config/secrets.yml | 2 -- db/seeds.rb | 6 ------ doc/environment.md | 5 ----- env.example | 3 --- lib/tasks/fablab/setup.rake | 14 ++++++++++++++ setup/env.example | 2 -- setup/setup.sh | 2 +- 15 files changed, 32 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67e1eab66..acc0905cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog Fab-manager - Improved display of the icons alerting about an outdated version +- [TODO DEPLOY] `rails fablab:setup:env_to_db` ## v4.4.4 2020 May 25 diff --git a/app/assets/javascripts/controllers/admin/settings.js.erb b/app/assets/javascripts/controllers/admin/settings.js.erb index 91f61a357..07fa0ff71 100644 --- a/app/assets/javascripts/controllers/admin/settings.js.erb +++ b/app/assets/javascripts/controllers/admin/settings.js.erb @@ -77,6 +77,7 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope' $scope.fablabName = { name: 'fablab_name', value: settingsPromise.fablab_name }; $scope.nameGenre = { name: 'name_genre', value: settingsPromise.name_genre }; $scope.machinesSortBy = { name: 'machines_sort_by', value: settingsPromise.machines_sort_by }; + $scope.trackingId = { name: 'tracking_id', value: settingsPromise.tracking_id } $scope.cguFile = cguFile.custom_asset; $scope.cgvFile = cgvFile.custom_asset; $scope.customLogo = logoFile.custom_asset; diff --git a/app/assets/javascripts/router.js.erb b/app/assets/javascripts/router.js.erb index d9afa808d..fd7743c1b 100644 --- a/app/assets/javascripts/router.js.erb +++ b/app/assets/javascripts/router.js.erb @@ -1009,7 +1009,7 @@ angular.module('application.router', ['ui.router']) resolve: { settingsPromise: ['Setting', function (Setting) { return Setting.query({ - names: `['twitter_name', 'about_title', 'about_body', \ + names: `['twitter_name', 'about_title', 'about_body', 'tracking_id',\ 'privacy_body', 'privacy_dpo', 'about_contacts', \ 'home_blogpost', 'machine_explications_alert', 'training_explications_alert', \ 'training_information_message', 'subscription_explications_alert', 'event_explications_alert', \ diff --git a/app/assets/templates/admin/settings/privacy.html b/app/assets/templates/admin/settings/privacy.html index 9c63ff604..cc392ec65 100644 --- a/app/assets/templates/admin/settings/privacy.html +++ b/app/assets/templates/admin/settings/privacy.html @@ -81,18 +81,18 @@
-

+

- - {{ 'app.admin.settings.privacy.tracking_id' }} + - +
diff --git a/app/models/setting.rb b/app/models/setting.rb index a3b536f41..ea5c94ac3 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -76,7 +76,8 @@ class Setting < ApplicationRecord home_css origin uuid - phone_required] } + phone_required + tracking_id] } def value last_value = history_values.order(HistoryValue.arel_table['created_at'].desc).first last_value&.value diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index 3085ee7a3..a520d4eb4 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -35,7 +35,7 @@ Fablab.featureTourDisplay = "<%= Rails.application.secrets.feature_tour_display %>"; Fablab.disqusShortname = "<%= Rails.application.secrets.disqus_shortname %>"; Fablab.defaultHost = "<%= Rails.application.secrets.default_host %>"; - Fablab.gaId = "<%= Rails.application.secrets.google_analytics_id %>"; + Fablab.gaId = "<%= Setting.get('tracking_id') %>"; Fablab.superadminId = parseInt("<%= User.superadmin&.id %>", 10); // i18n stuff diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 8b8dfc3e9..7d53c4732 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1020,6 +1020,7 @@ en: machines_sort_by: "machines display order" fab_analytics: "Fab Analytics" phone_required: "phone required" + tracking_id: "tracking ID" elements_ordering: "Elements ordering" machines_order: "Machines order" display_machines_sorted_by: "Display machines sorted by" @@ -1061,8 +1062,8 @@ en: various_settings: "Various settings" phone_required: "Phone required" phone_required_info: "You can define if the phone number should be required to register a new user on Fab-manager." - google_analytics_info_html: "To enable the statistical tracking of the visits using Google Analytics, set your tracking ID here. It is in the form UA-000000-2. Visit the Google Analytics website to get one.Warning : if you enable this feature, remember to write it in your privacy policy, above." - google_analytics: "Tracking ID" + tracking_id_info_html: "To enable the statistical tracking of the visits using Google Analytics, set your tracking ID here. It is in the form UA-000000-2. Visit the Google Analytics website to get one.Warning : if you enable this feature, remember to write it in your privacy policy, above." + tracking_id: "Tracking ID" open_api_clients: add_new_client: "Create new API client" api_documentation: "API documentation" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 4235bb11d..f57f5fe79 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1020,6 +1020,7 @@ fr: machines_sort_by: "l'ordre d'affichage des machines" fab_analytics: "Fab Analytics" phone_required: "téléphone requis" + tracking_id: "ID de suivi" elements_ordering: "Ordre d'affichage des éléments" machines_order: "Ordre des machines" display_machines_sorted_by: "Afficher les machines triées par" @@ -1061,8 +1062,8 @@ fr: various_settings: "Paramètres divers" phone_required: "Téléphone requis" phone_required_info: "Vous pouvez définir si le numéro de téléphone doit être requis, lors de l'enregistrement d'un nouvel utilisateur sur Fab-manager." - google_analytics_info_html: "Pour activer les suivi statistique des visites utilisant Google Analytics, définissez ici votre ID de suivi. Il se présente sous la forme UA-000000-2. Visitez le site web de Google Analytics pour en obtenir un.
Attention : si vous activez cette fonctionnalité, pensez à l'indiquer dans votre politique de confidentialité, ci-dessus." - google_analytics: "ID de suivi" + tracking_id_info_html: "Pour activer les suivi statistique des visites utilisant Google Analytics, définissez ici votre ID de suivi. Il se présente sous la forme UA-000000-2. Visitez le site web de Google Analytics pour en obtenir un.
Attention : si vous activez cette fonctionnalité, pensez à l'indiquer dans votre politique de confidentialité, ci-dessus." + tracking_id: "ID de suivi" open_api_clients: add_new_client: "Créer un compte client" api_documentation: "Documentation de l'API" diff --git a/config/secrets.yml b/config/secrets.yml index 3479c252c..1d9fdafa2 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -146,7 +146,6 @@ staging: openlab_app_id: <%= ENV["OPENLAB_APP_ID"] %> openlab_default: <%= ENV["OPENLAB_DEFAULT"] %> openlab_base_uri: <%= ENV["OPENLAB_BASE_URI"] %> - google_analytics_id: <%= ENV["GA_ID"] %> navinum_api_login: <%= ENV["NAVINUM_API_LOGIN"] %> navinum_api_password: <%= ENV["NAVINUM_API_PASSWORD"] %> facebook_app_id: <%= ENV["FACEBOOK_APP_ID"] %> @@ -205,7 +204,6 @@ production: openlab_app_id: <%= ENV["OPENLAB_APP_ID"] %> openlab_default: <%= ENV["OPENLAB_DEFAULT"] %> openlab_base_uri: <%= ENV["OPENLAB_BASE_URI"] %> - google_analytics_id: <%= ENV["GA_ID"] %> navinum_api_login: <%= ENV["NAVINUM_API_LOGIN"] %> navinum_api_password: <%= ENV["NAVINUM_API_PASSWORD"] %> facebook_app_id: <%= ENV["FACEBOOK_APP_ID"] %> diff --git a/db/seeds.rb b/db/seeds.rb index a7ce23b4d..e9413f7fb 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -925,12 +925,6 @@ unless Setting.find_by(name: 'link_name').try(:value) setting.save end -unless Setting.find_by(name: 'phone_required').try(:value) - setting = Setting.find_or_initialize_by(name: 'phone_required') - setting.value = ENV.fetch('PHONE_REQUIRED', 'true') - setting.save -end - unless Setting.find_by(name: 'home_content').try(:value) setting = Setting.find_or_initialize_by(name: 'home_content') setting.value = <<~HTML diff --git a/doc/environment.md b/doc/environment.md index d7a047c47..62dc26cff 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -155,11 +155,6 @@ See http://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-config When DELIVERY_METHOD is set to **smtp**, configure the SMTP server parameters. See https://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration for more details. DEFAULT_HOST is also used to configure Google Analytics. - - - GA_ID - -Identifier of your Google Analytics account. RECAPTCHA_SITE_KEY, RECAPTCHA_SECRET_KEY diff --git a/env.example b/env.example index 16130e8e7..455626b9a 100644 --- a/env.example +++ b/env.example @@ -47,9 +47,6 @@ SMTP_ENABLE_STARTTLS_AUTO=true SMTP_OPENSSL_VERIFY_MODE= SMTP_TLS=false -# Google analytics -GA_ID= - # Google recaptcha RECAPTCHA_SITE_KEY= RECAPTCHA_SECRET_KEY= diff --git a/lib/tasks/fablab/setup.rake b/lib/tasks/fablab/setup.rake index 86f34c554..6e345ff88 100644 --- a/lib/tasks/fablab/setup.rake +++ b/lib/tasks/fablab/setup.rake @@ -100,5 +100,19 @@ namespace :fablab do FileUtils.rm_rf 'invoices' FileUtils.mv 'tmp/invoices', 'invoices' end + + desc 'migrate environment variables to the database (settings)' + task env_to_db: :environment do + mapping = [ + %w[PHONE_REQUIRED phone_required true], + %w[GA_ID tracking_id] + ] + + mapping.each do |m| + setting = Setting.find_or_initialize_by(name: m[1]) + setting.value = ENV.fetch(m[0], m[2]) + setting.save if setting.value + end + end end end diff --git a/setup/env.example b/setup/env.example index 65a19af58..2115432a2 100644 --- a/setup/env.example +++ b/setup/env.example @@ -35,8 +35,6 @@ SMTP_ENABLE_STARTTLS_AUTO=true SMTP_OPENSSL_VERIFY_MODE= SMTP_TLS=false -GA_ID= - RECAPTCHA_SITE_KEY= RECAPTCHA_SECRET_KEY= diff --git a/setup/setup.sh b/setup/setup.sh index 6d117e7d0..d61527dc9 100755 --- a/setup/setup.sh +++ b/setup/setup.sh @@ -236,7 +236,7 @@ configure_env_file() doc=$(\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/doc/environment.md) variables=(STRIPE_API_KEY STRIPE_PUBLISHABLE_KEY STRIPE_CURRENCY INVOICE_PREFIX FABLAB_WITHOUT_PLANS FABLAB_WITHOUT_SPACES FABLAB_WITHOUT_ONLINE_PAYMENT FABLAB_WITHOUT_INVOICES FABLAB_WITHOUT_WALLET \ PHONE_REQUIRED BOOK_SLOT_AT_SAME_TIME USER_CONFIRMATION_NEEDED_TO_SIGN_IN EVENTS_IN_CALENDAR SLOT_DURATION DEFAULT_MAIL_FROM DELIVERY_METHOD DEFAULT_HOST DEFAULT_PROTOCOL SMTP_ADDRESS SMTP_PORT SMTP_USER_NAME SMTP_PASSWORD SMTP_AUTHENTICATION \ - SMTP_ENABLE_STARTTLS_AUTO SMTP_OPENSSL_VERIFY_MODE SMTP_TLS GA_ID RECAPTCHA_SITE_KEY RECAPTCHA_SECRET_KEY DISQUS_SHORTNAME TWITTER_NAME \ + SMTP_ENABLE_STARTTLS_AUTO SMTP_OPENSSL_VERIFY_MODE SMTP_TLS RECAPTCHA_SITE_KEY RECAPTCHA_SECRET_KEY DISQUS_SHORTNAME TWITTER_NAME \ FACEBOOK_APP_ID LOG_LEVEL ALLOWED_EXTENSIONS ALLOWED_MIME_TYPES MAX_IMAGE_SIZE MAX_CAO_SIZE MAX_IMPORT_SIZE DISK_SPACE_MB_ALERT FEATURE_TOUR_DISPLAY \ SUPERADMIN_EMAIL APP_LOCALE RAILS_LOCALE MOMENT_LOCALE SUMMERNOTE_LOCALE ANGULAR_LOCALE FULLCALENDAR_LOCALE ELASTICSEARCH_LANGUAGE_ANALYZER TIME_ZONE \ WEEK_STARTING_DAY D3_DATE_FORMAT UIB_DATE_FORMAT EXCEL_DATE_FORMAT OPENLAB_APP_ID OPENLAB_APP_SECRET OPENLAB_DEFAULT) From ddce7f516a91d331807bdb4a57effddd209c0347 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 19 May 2020 17:08:11 +0200 Subject: [PATCH 009/209] configuration of book concurrent slots through the settings interface --- .../javascripts/controllers/admin/settings.js.erb | 5 +++++ .../templates/admin/settings/reservations.html | 15 +++++++++++++++ app/models/setting.rb | 3 ++- app/views/application/index.html.erb | 2 +- config/locales/app.admin.en.yml | 3 +++ config/locales/app.admin.fr.yml | 3 +++ config/secrets.yml | 4 ---- doc/environment.md | 5 ----- env.example | 1 - lib/tasks/fablab/setup.rake | 3 ++- setup/env.example | 1 - setup/setup.sh | 2 +- 12 files changed, 32 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/controllers/admin/settings.js.erb b/app/assets/javascripts/controllers/admin/settings.js.erb index 07fa0ff71..2a30c975c 100644 --- a/app/assets/javascripts/controllers/admin/settings.js.erb +++ b/app/assets/javascripts/controllers/admin/settings.js.erb @@ -140,6 +140,11 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope' value: (settingsPromise.phone_required === 'true') }; + $scope.bookOverlappingSlots = { + name: 'book_overlapping_slots', + value: (settingsPromise.book_overlapping_slots === 'true') + } + // By default, we display the currently published privacy policy $scope.privacyPolicy = { version: null, diff --git a/app/assets/templates/admin/settings/reservations.html b/app/assets/templates/admin/settings/reservations.html index 643d51930..5c5652988 100644 --- a/app/assets/templates/admin/settings/reservations.html +++ b/app/assets/templates/admin/settings/reservations.html @@ -106,6 +106,21 @@
+
+

{{ 'app.admin.settings.book_overlapping_slots_info' }}

+
+ + + +
+
diff --git a/app/models/setting.rb b/app/models/setting.rb index ea5c94ac3..c9389afc5 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -77,7 +77,8 @@ class Setting < ApplicationRecord origin uuid phone_required - tracking_id] } + tracking_id + book_overlapping_slots] } def value last_value = history_values.order(HistoryValue.arel_table['created_at'].desc).first last_value&.value diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index a520d4eb4..a195e0528 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -29,7 +29,7 @@ Fablab.withoutInvoices = ('<%= Rails.application.secrets.fablab_without_invoices %>' === 'true'); Fablab.phoneRequired = ('<%= Setting.get('phone_required') %>' === 'true'); Fablab.fablabWithoutWallet = ('<%= Rails.application.secrets.fablab_without_wallet %>' === 'true'); - Fablab.bookSlotAtSameTime = ('<%= Rails.application.secrets.book_slot_at_same_time %>' === 'true'); + Fablab.bookSlotAtSameTime = ('<%= Setting.get('book_overlapping_slots') %>' === 'true'); Fablab.eventsInCalendar = ('<%= Rails.application.secrets.events_in_calendar %>' === 'true'); Fablab.slotDuration = parseInt("<%= ApplicationHelper::SLOT_DURATION %>", 10); Fablab.featureTourDisplay = "<%= Rails.application.secrets.feature_tour_display %>"; diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 7d53c4732..401a37da5 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1021,6 +1021,7 @@ en: fab_analytics: "Fab Analytics" phone_required: "phone required" tracking_id: "tracking ID" + book_overlapping_slots: "book overlapping slots" elements_ordering: "Elements ordering" machines_order: "Machines order" display_machines_sorted_by: "Display machines sorted by" @@ -1028,6 +1029,8 @@ en: customize_home_page_css: "Customise the stylesheet og the home page" home_css_notice_html: "You can customize the stylesheet which will apply to the home page, using the SASS syntax. These styles will be automatically subordinated to the .home-page selector to prevent any risk of breaking the application. Meanwhile please be careful, any changes in the home page editor at the top of the page may broke your styles, always refer to the HTML code." an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." + book_overlapping_slots_info: "Allow / prevent the reservation of overlapping slots" + allow_booking: "Allow booking" sort_by: default: "Default" name: "Name" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index f57f5fe79..e1f60c8d5 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1021,6 +1021,7 @@ fr: fab_analytics: "Fab Analytics" phone_required: "téléphone requis" tracking_id: "ID de suivi" + book_overlapping_slots: "réservation de créneaux simultanés" elements_ordering: "Ordre d'affichage des éléments" machines_order: "Ordre des machines" display_machines_sorted_by: "Afficher les machines triées par" @@ -1028,6 +1029,8 @@ fr: customize_home_page_css: "Personnaliser la feuille de style de la page d'accueil" home_css_notice_html: "Vous pouvez personnaliser la feuille de style qui s'appliquera à la page d'accueil en utilisant la syntaxe SASS. Ces styles seront automatiquement subordonnées au sélecteur .home-page pour prévenir tout risque de casse de l'application. Attention toutefois, les modifications de la page d'accueil dans l'éditeur en haut de page peuvent rendre caduque vos styles, référez vous toujours au code HTML." an_error_occurred_saving_the_setting: "Une erreur est survenue pendant l'enregistrement du paramètre. Veuillez réessayer plus tard." + book_overlapping_slots_info: "Autoriser / empêcher la réservation de créneaux qui se chevauchent" + allow_booking: "Autoriser la réservation" sort_by: default: "Défaut" name: "Nom" diff --git a/config/secrets.yml b/config/secrets.yml index 1d9fdafa2..1eea9e04d 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -21,7 +21,6 @@ development: fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %> fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %> fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %> - book_slot_at_same_time: <%= ENV["BOOK_SLOT_AT_SAME_TIME"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %> slot_duration: <%= ENV["SLOT_DURATION"] %> @@ -68,7 +67,6 @@ test: fablab_without_online_payments: false fablab_without_invoices: false fablab_without_wallet: false - book_slot_at_same_time: true user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> events_in_calendar: false slot_duration: 60 @@ -115,7 +113,6 @@ staging: fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %> fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %> fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %> - book_slot_at_same_time: <%= ENV["BOOK_SLOT_AT_SAME_TIME"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %> slot_duration: <%= ENV["SLOT_DURATION"] %> @@ -173,7 +170,6 @@ production: fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %> fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %> fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %> - book_slot_at_same_time: <%= ENV["BOOK_SLOT_AT_SAME_TIME"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %> slot_duration: <%= ENV["SLOT_DURATION"] %> diff --git a/doc/environment.md b/doc/environment.md index 62dc26cff..943e9fc98 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -112,11 +112,6 @@ This is useful if you have your own invoicing system and you want to prevent Fab If set to 'true', the wallet will be disabled. This is useful if you won't use wallet system. - - - BOOK_SLOT_AT_SAME_TIME - -If set to 'true', users will be able to book a machine/formation/event slot, even if they already have a reservation the same day at the same time. USER_CONFIRMATION_NEEDED_TO_SIGN_IN diff --git a/env.example b/env.example index 455626b9a..0801b6356 100644 --- a/env.example +++ b/env.example @@ -22,7 +22,6 @@ FABLAB_WITHOUT_ONLINE_PAYMENT=false FABLAB_WITHOUT_INVOICES=false PHONE_REQUIRED=true FABLAB_WITHOUT_WALLET=false -BOOK_SLOT_AT_SAME_TIME=true USER_CONFIRMATION_NEEDED_TO_SIGN_IN=false diff --git a/lib/tasks/fablab/setup.rake b/lib/tasks/fablab/setup.rake index 6e345ff88..21d4882df 100644 --- a/lib/tasks/fablab/setup.rake +++ b/lib/tasks/fablab/setup.rake @@ -105,7 +105,8 @@ namespace :fablab do task env_to_db: :environment do mapping = [ %w[PHONE_REQUIRED phone_required true], - %w[GA_ID tracking_id] + %w[GA_ID tracking_id], + %w[BOOK_SLOT_AT_SAME_TIME book_overlapping_slots true] ] mapping.each do |m| diff --git a/setup/env.example b/setup/env.example index 2115432a2..015959f21 100644 --- a/setup/env.example +++ b/setup/env.example @@ -15,7 +15,6 @@ FABLAB_WITHOUT_ONLINE_PAYMENT=false FABLAB_WITHOUT_INVOICES=false PHONE_REQUIRED=false FABLAB_WITHOUT_WALLET=false -BOOK_SLOT_AT_SAME_TIME=true EVENTS_IN_CALENDAR=true SLOT_DURATION=60 diff --git a/setup/setup.sh b/setup/setup.sh index d61527dc9..63f9955c7 100755 --- a/setup/setup.sh +++ b/setup/setup.sh @@ -235,7 +235,7 @@ configure_env_file() local doc variables secret doc=$(\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/doc/environment.md) variables=(STRIPE_API_KEY STRIPE_PUBLISHABLE_KEY STRIPE_CURRENCY INVOICE_PREFIX FABLAB_WITHOUT_PLANS FABLAB_WITHOUT_SPACES FABLAB_WITHOUT_ONLINE_PAYMENT FABLAB_WITHOUT_INVOICES FABLAB_WITHOUT_WALLET \ - PHONE_REQUIRED BOOK_SLOT_AT_SAME_TIME USER_CONFIRMATION_NEEDED_TO_SIGN_IN EVENTS_IN_CALENDAR SLOT_DURATION DEFAULT_MAIL_FROM DELIVERY_METHOD DEFAULT_HOST DEFAULT_PROTOCOL SMTP_ADDRESS SMTP_PORT SMTP_USER_NAME SMTP_PASSWORD SMTP_AUTHENTICATION \ + USER_CONFIRMATION_NEEDED_TO_SIGN_IN EVENTS_IN_CALENDAR SLOT_DURATION DEFAULT_MAIL_FROM DELIVERY_METHOD DEFAULT_HOST DEFAULT_PROTOCOL SMTP_ADDRESS SMTP_PORT SMTP_USER_NAME SMTP_PASSWORD SMTP_AUTHENTICATION \ SMTP_ENABLE_STARTTLS_AUTO SMTP_OPENSSL_VERIFY_MODE SMTP_TLS RECAPTCHA_SITE_KEY RECAPTCHA_SECRET_KEY DISQUS_SHORTNAME TWITTER_NAME \ FACEBOOK_APP_ID LOG_LEVEL ALLOWED_EXTENSIONS ALLOWED_MIME_TYPES MAX_IMAGE_SIZE MAX_CAO_SIZE MAX_IMPORT_SIZE DISK_SPACE_MB_ALERT FEATURE_TOUR_DISPLAY \ SUPERADMIN_EMAIL APP_LOCALE RAILS_LOCALE MOMENT_LOCALE SUMMERNOTE_LOCALE ANGULAR_LOCALE FULLCALENDAR_LOCALE ELASTICSEARCH_LANGUAGE_ANALYZER TIME_ZONE \ From f37049c3ab6c6df9efd1c7c69310af278a4b5ea5 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 20 May 2020 10:14:44 +0200 Subject: [PATCH 010/209] updated README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 29fb01742..1fc0207a8 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Fab-manager is the Fab Lab management solution. It provides a comprehensive, web Fab-manager is a Ruby on Rails / AngularJS web application that runs on the following software: - Ubuntu LTS 14.04+ / Debian 8+ -- Ruby 2.3 +- Ruby 2.6 - Redis 2.8.4+ - Sidekiq 3.3.4+ - Elasticsearch 5.6 @@ -99,9 +99,9 @@ You can see an example on the [repo of navinum gamification plugin](https://gith ## Single Sign-On Fab-manager can be connected to a [Single Sign-On](https://en.wikipedia.org/wiki/Single_sign-on) server which will provide its own authentication for the platform's users. -Currently OAuth 2 is the only supported protocol for SSO authentication. +Currently, OAuth 2 is the only supported protocol for SSO authentication. -For an example of how to use configure a SSO in Fab-manager, please read [sso_with_github.md](doc/sso_with_github.md). +For an example of how to use configure an SSO in Fab-manager, please read [sso_with_github.md](doc/sso_with_github.md). ## Known issues From e625f8c7f78739334585c8313400113bfd49dd78 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 20 May 2020 11:13:38 +0200 Subject: [PATCH 011/209] reorganized home directives --- app/assets/javascripts/directives/{ => home}/events.js.erb | 0 app/assets/javascripts/directives/{ => home}/news.js.erb | 0 app/assets/javascripts/directives/{ => home}/projects.js.erb | 0 app/assets/javascripts/directives/{ => home}/twitter.js.erb | 0 app/assets/javascripts/directives/settings/boolean-setting.js | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename app/assets/javascripts/directives/{ => home}/events.js.erb (100%) rename app/assets/javascripts/directives/{ => home}/news.js.erb (100%) rename app/assets/javascripts/directives/{ => home}/projects.js.erb (100%) rename app/assets/javascripts/directives/{ => home}/twitter.js.erb (100%) create mode 100644 app/assets/javascripts/directives/settings/boolean-setting.js diff --git a/app/assets/javascripts/directives/events.js.erb b/app/assets/javascripts/directives/home/events.js.erb similarity index 100% rename from app/assets/javascripts/directives/events.js.erb rename to app/assets/javascripts/directives/home/events.js.erb diff --git a/app/assets/javascripts/directives/news.js.erb b/app/assets/javascripts/directives/home/news.js.erb similarity index 100% rename from app/assets/javascripts/directives/news.js.erb rename to app/assets/javascripts/directives/home/news.js.erb diff --git a/app/assets/javascripts/directives/projects.js.erb b/app/assets/javascripts/directives/home/projects.js.erb similarity index 100% rename from app/assets/javascripts/directives/projects.js.erb rename to app/assets/javascripts/directives/home/projects.js.erb diff --git a/app/assets/javascripts/directives/twitter.js.erb b/app/assets/javascripts/directives/home/twitter.js.erb similarity index 100% rename from app/assets/javascripts/directives/twitter.js.erb rename to app/assets/javascripts/directives/home/twitter.js.erb diff --git a/app/assets/javascripts/directives/settings/boolean-setting.js b/app/assets/javascripts/directives/settings/boolean-setting.js new file mode 100644 index 000000000..e69de29bb From 906564e5e53c9fc042776e62f2fcb9ec75815e72 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 20 May 2020 15:16:55 +0200 Subject: [PATCH 012/209] boolean-setting directive + eslint on .js.erb + refactored book_overlapping_slots using the new directive --- .eslintrc | 5 ++- .../controllers/admin/settings.js.erb | 3 ++ .../directives/settings/boolean-setting.js | 0 .../settings/boolean-setting.js.erb | 40 +++++++++++++++++++ app/assets/javascripts/router.js.erb | 2 +- .../templates/admin/settings/boolean.html | 12 ++++++ .../admin/settings/reservations.html | 13 +----- package.json | 1 + yarn.lock | 4 ++ 9 files changed, 65 insertions(+), 15 deletions(-) delete mode 100644 app/assets/javascripts/directives/settings/boolean-setting.js create mode 100644 app/assets/javascripts/directives/settings/boolean-setting.js.erb create mode 100644 app/assets/templates/admin/settings/boolean.html diff --git a/.eslintrc b/.eslintrc index 4006a27f2..545c29d9c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -7,7 +7,8 @@ "Application": true, "angular": true, "Fablab": true, - "moment": true, - } + "moment": true + }, + "plugins": ["lint-erb"] } diff --git a/app/assets/javascripts/controllers/admin/settings.js.erb b/app/assets/javascripts/controllers/admin/settings.js.erb index 2a30c975c..cfb8e701d 100644 --- a/app/assets/javascripts/controllers/admin/settings.js.erb +++ b/app/assets/javascripts/controllers/admin/settings.js.erb @@ -54,6 +54,9 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope' // full history of privacy policy drafts $scope.privacyDraftsHistory = []; + // all settings as retrieved from database + $scope.allSettings = settingsPromise; + // various configurable settings $scope.twitterSetting = { name: 'twitter_name', value: settingsPromise.twitter_name }; $scope.linkName = { name: 'link_name', value: settingsPromise.link_name }; diff --git a/app/assets/javascripts/directives/settings/boolean-setting.js b/app/assets/javascripts/directives/settings/boolean-setting.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/assets/javascripts/directives/settings/boolean-setting.js.erb b/app/assets/javascripts/directives/settings/boolean-setting.js.erb new file mode 100644 index 000000000..c448d94b2 --- /dev/null +++ b/app/assets/javascripts/directives/settings/boolean-setting.js.erb @@ -0,0 +1,40 @@ +Application.Directives.directive('booleanSetting', ['Setting', 'growl', '_t', + function (Setting, growl, _t) { + return ({ + restrict: 'E', + scope: { + name: '@', + label: '@', + settings: '=' + }, + templateUrl: '<%= asset_path "admin/settings/boolean.html" %>', + link ($scope, element, attributes) { + // The setting + $scope.setting = { + name: $scope.name, + value: ($scope.settings[$scope.name] === 'true') + }; + + /** + * Callback to save the setting value to the database + * @param setting {{value:*, name:string}} note that the value will be stringified + */ + $scope.save = function (setting) { + const { value } = setting; + + Setting.update( + { name: setting.name }, + { value: value.toString() }, + function () { growl.success(_t('app.admin.settings.customization_of_SETTING_successfully_saved', { SETTING: _t(`app.admin.settings.${setting.name}`) })); }, + function (error) { + if (error.status === 304) return; + + growl.error(_t('app.admin.settings.an_error_occurred_saving_the_setting')); + console.log(error); + } + ); + }; + } + }); + } +]); diff --git a/app/assets/javascripts/router.js.erb b/app/assets/javascripts/router.js.erb index fd7743c1b..1772fe61a 100644 --- a/app/assets/javascripts/router.js.erb +++ b/app/assets/javascripts/router.js.erb @@ -1010,7 +1010,7 @@ angular.module('application.router', ['ui.router']) settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: `['twitter_name', 'about_title', 'about_body', 'tracking_id',\ - 'privacy_body', 'privacy_dpo', 'about_contacts', \ + 'privacy_body', 'privacy_dpo', 'about_contacts', 'book_overlapping_slots', \ 'home_blogpost', 'machine_explications_alert', 'training_explications_alert', \ 'training_information_message', 'subscription_explications_alert', 'event_explications_alert', \ 'space_explications_alert', 'booking_window_start', 'booking_window_end', \ diff --git a/app/assets/templates/admin/settings/boolean.html b/app/assets/templates/admin/settings/boolean.html new file mode 100644 index 000000000..ee8f0b2d7 --- /dev/null +++ b/app/assets/templates/admin/settings/boolean.html @@ -0,0 +1,12 @@ +
+ + + +
diff --git a/app/assets/templates/admin/settings/reservations.html b/app/assets/templates/admin/settings/reservations.html index 5c5652988..84c62a77c 100644 --- a/app/assets/templates/admin/settings/reservations.html +++ b/app/assets/templates/admin/settings/reservations.html @@ -108,18 +108,7 @@

{{ 'app.admin.settings.book_overlapping_slots_info' }}

-
- - - -
+
diff --git a/package.json b/package.json index 13b0fee38..48376aa6a 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "eslint": "~6.8.0", "eslint-config-standard": "~14.1.1", "eslint-plugin-import": "~2.20.1", + "eslint-plugin-lint-erb": "https://github.com/sleede/eslint-plugin-lint-erb", "eslint-plugin-node": "~11.0.0", "eslint-plugin-promise": "~4.2.1", "eslint-plugin-standard": "~4.0.1" diff --git a/yarn.lock b/yarn.lock index 2a08e766a..288be95e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -553,6 +553,10 @@ eslint-plugin-import@~2.20.1: read-pkg-up "^2.0.0" resolve "^1.12.0" +"eslint-plugin-lint-erb@https://github.com/sleede/eslint-plugin-lint-erb": + version "0.2.2" + resolved "https://github.com/sleede/eslint-plugin-lint-erb#c163046088f7e988d131b0ca857a47feb925c10f" + eslint-plugin-node@~11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.0.0.tgz#365944bb0804c5d1d501182a9bc41a0ffefed726" From af45f5bbcd9894898408397956c49a6e379655b4 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 20 May 2020 15:42:54 +0200 Subject: [PATCH 013/209] refactored settings to use boolean-setting directive --- .../controllers/admin/settings.js.erb | 35 ------------ .../settings/boolean-setting.js.erb | 9 +++- .../templates/admin/settings/boolean.html | 6 +-- .../templates/admin/settings/privacy.html | 37 ++++++------- .../admin/settings/reservations.html | 54 ++----------------- 5 files changed, 31 insertions(+), 110 deletions(-) diff --git a/app/assets/javascripts/controllers/admin/settings.js.erb b/app/assets/javascripts/controllers/admin/settings.js.erb index cfb8e701d..00bdab3e9 100644 --- a/app/assets/javascripts/controllers/admin/settings.js.erb +++ b/app/assets/javascripts/controllers/admin/settings.js.erb @@ -88,31 +88,16 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope' $scope.customFavicon = faviconFile.custom_asset; $scope.profileImage = profileImageFile.custom_asset; - $scope.enableMove = { - name: 'booking_move_enable', - value: (settingsPromise.booking_move_enable === 'true') - }; - $scope.moveDelay = { name: 'booking_move_delay', value: parseInt(settingsPromise.booking_move_delay, 10) }; - $scope.enableCancel = { - name: 'booking_cancel_enable', - value: (settingsPromise.booking_cancel_enable === 'true') - }; - $scope.cancelDelay = { name: 'booking_cancel_delay', value: parseInt(settingsPromise.booking_cancel_delay, 10) }; - $scope.enableReminder = { - name: 'reminder_enable', - value: (settingsPromise.reminder_enable === 'true') - }; - $scope.reminderDelay = { name: 'reminder_delay', value: parseInt(settingsPromise.reminder_delay, 10) @@ -128,26 +113,6 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope' value: parseInt(settingsPromise.visibility_others, 10) }; - $scope.displayNameEnable = { - name: 'display_name_enable', - value: (settingsPromise.display_name_enable === 'true') - }; - - $scope.fabAnalytics = { - name: 'fab_analytics', - value: (settingsPromise.fab_analytics === 'true') - }; - - $scope.phoneRequired = { - name: 'phone_required', - value: (settingsPromise.phone_required === 'true') - }; - - $scope.bookOverlappingSlots = { - name: 'book_overlapping_slots', - value: (settingsPromise.book_overlapping_slots === 'true') - } - // By default, we display the currently published privacy policy $scope.privacyPolicy = { version: null, diff --git a/app/assets/javascripts/directives/settings/boolean-setting.js.erb b/app/assets/javascripts/directives/settings/boolean-setting.js.erb index c448d94b2..bc1f9a3b1 100644 --- a/app/assets/javascripts/directives/settings/boolean-setting.js.erb +++ b/app/assets/javascripts/directives/settings/boolean-setting.js.erb @@ -5,7 +5,10 @@ Application.Directives.directive('booleanSetting', ['Setting', 'growl', '_t', scope: { name: '@', label: '@', - settings: '=' + settings: '=', + yesLabel: '@', + noLabel: '@', + classes: '@' }, templateUrl: '<%= asset_path "admin/settings/boolean.html" %>', link ($scope, element, attributes) { @@ -15,6 +18,10 @@ Application.Directives.directive('booleanSetting', ['Setting', 'growl', '_t', value: ($scope.settings[$scope.name] === 'true') }; + // default values for the switch labels + $scope.yesLabel = $scope.yesLabel || 'app.admin.settings.enabled'; + $scope.noLabel = $scope.noLabel || 'app.admin.settings.disabled'; + /** * Callback to save the setting value to the database * @param setting {{value:*, name:string}} note that the value will be stringified diff --git a/app/assets/templates/admin/settings/boolean.html b/app/assets/templates/admin/settings/boolean.html index ee8f0b2d7..76a1fdda8 100644 --- a/app/assets/templates/admin/settings/boolean.html +++ b/app/assets/templates/admin/settings/boolean.html @@ -1,12 +1,12 @@ -
+
diff --git a/app/assets/templates/admin/settings/privacy.html b/app/assets/templates/admin/settings/privacy.html index cc392ec65..4ea267dfe 100644 --- a/app/assets/templates/admin/settings/privacy.html +++ b/app/assets/templates/admin/settings/privacy.html @@ -38,20 +38,17 @@
- - + +

{{ 'app.admin.settings.privacy.about_analytics' }} {{ 'app.admin.settings.privacy.read_more' }}

-
@@ -68,17 +65,13 @@

- - - - + +

@@ -97,4 +90,4 @@
- \ No newline at end of file + diff --git a/app/assets/templates/admin/settings/reservations.html b/app/assets/templates/admin/settings/reservations.html index 84c62a77c..bfe846673 100644 --- a/app/assets/templates/admin/settings/reservations.html +++ b/app/assets/templates/admin/settings/reservations.html @@ -50,18 +50,7 @@

{{ 'app.admin.settings.ability_for_the_users_to_move_their_reservations' }}

-
- - - -
+
@@ -79,18 +68,7 @@

{{ 'app.admin.settings.ability_for_the_users_to_cancel_their_reservations' }}

-
- - - -
+
@@ -108,7 +86,7 @@

{{ 'app.admin.settings.book_overlapping_slots_info' }}

- +
@@ -121,18 +99,7 @@

{{ 'app.admin.settings.notification_sending_before_the_reservation_occurs' }}

-
- - - -
+
@@ -162,18 +129,7 @@

{{ 'app.admin.settings.display_machine_reservation_user_name' }}

-
- - - -
+
From cb2ad950b50b7876f3dc110abd4e628c4e85ba3d Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 20 May 2020 15:57:03 +0200 Subject: [PATCH 014/209] update setting in memory after save --- .../directives/settings/boolean-setting.js.erb | 9 ++++++--- app/assets/templates/admin/settings/reservations.html | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/directives/settings/boolean-setting.js.erb b/app/assets/javascripts/directives/settings/boolean-setting.js.erb index bc1f9a3b1..a2640a211 100644 --- a/app/assets/javascripts/directives/settings/boolean-setting.js.erb +++ b/app/assets/javascripts/directives/settings/boolean-setting.js.erb @@ -27,12 +27,15 @@ Application.Directives.directive('booleanSetting', ['Setting', 'growl', '_t', * @param setting {{value:*, name:string}} note that the value will be stringified */ $scope.save = function (setting) { - const { value } = setting; + const value = setting.value.toString(); Setting.update( { name: setting.name }, - { value: value.toString() }, - function () { growl.success(_t('app.admin.settings.customization_of_SETTING_successfully_saved', { SETTING: _t(`app.admin.settings.${setting.name}`) })); }, + { value }, + function () { + growl.success(_t('app.admin.settings.customization_of_SETTING_successfully_saved', { SETTING: _t(`app.admin.settings.${setting.name}`) })); + $scope.settings[$scope.name] = value; + }, function (error) { if (error.status === 304) return; diff --git a/app/assets/templates/admin/settings/reservations.html b/app/assets/templates/admin/settings/reservations.html index bfe846673..b122f19d7 100644 --- a/app/assets/templates/admin/settings/reservations.html +++ b/app/assets/templates/admin/settings/reservations.html @@ -52,7 +52,7 @@

{{ 'app.admin.settings.ability_for_the_users_to_move_their_reservations' }}

-
+
@@ -70,7 +70,7 @@

{{ 'app.admin.settings.ability_for_the_users_to_cancel_their_reservations' }}

-
+
@@ -101,7 +101,7 @@

{{ 'app.admin.settings.notification_sending_before_the_reservation_occurs' }}

-
+
From 1ad072071157956f87503c8cc7f7ea3e59196f25 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 20 May 2020 16:35:07 +0200 Subject: [PATCH 015/209] number-setting directive + refactored admin/settings to use new directive --- .../controllers/admin/settings.js.erb | 25 ----- .../directives/settings/number-setting.js.erb | 53 +++++++++ .../templates/admin/settings/number.html | 15 +++ .../admin/settings/reservations.html | 103 +++++++----------- 4 files changed, 108 insertions(+), 88 deletions(-) create mode 100644 app/assets/javascripts/directives/settings/number-setting.js.erb create mode 100644 app/assets/templates/admin/settings/number.html diff --git a/app/assets/javascripts/controllers/admin/settings.js.erb b/app/assets/javascripts/controllers/admin/settings.js.erb index 00bdab3e9..3f7fc53a4 100644 --- a/app/assets/javascripts/controllers/admin/settings.js.erb +++ b/app/assets/javascripts/controllers/admin/settings.js.erb @@ -88,31 +88,6 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope' $scope.customFavicon = faviconFile.custom_asset; $scope.profileImage = profileImageFile.custom_asset; - $scope.moveDelay = { - name: 'booking_move_delay', - value: parseInt(settingsPromise.booking_move_delay, 10) - }; - - $scope.cancelDelay = { - name: 'booking_cancel_delay', - value: parseInt(settingsPromise.booking_cancel_delay, 10) - }; - - $scope.reminderDelay = { - name: 'reminder_delay', - value: parseInt(settingsPromise.reminder_delay, 10) - }; - - $scope.visibilityYearly = { - name: 'visibility_yearly', - value: parseInt(settingsPromise.visibility_yearly, 10) - }; - - $scope.visibilityOthers = { - name: 'visibility_others', - value: parseInt(settingsPromise.visibility_others, 10) - }; - // By default, we display the currently published privacy policy $scope.privacyPolicy = { version: null, diff --git a/app/assets/javascripts/directives/settings/number-setting.js.erb b/app/assets/javascripts/directives/settings/number-setting.js.erb new file mode 100644 index 000000000..32e69f793 --- /dev/null +++ b/app/assets/javascripts/directives/settings/number-setting.js.erb @@ -0,0 +1,53 @@ +Application.Directives.directive('numberSetting', ['Setting', 'growl', '_t', + function (Setting, growl, _t) { + return ({ + restrict: 'E', + scope: { + name: '@', + label: '@', + settings: '=', + classes: '@', + faIcon: '@', + helperText: '@', + min: '@', + required: '<' + }, + templateUrl: '<%= asset_path "admin/settings/number.html" %>', + link ($scope, element, attributes) { + // The setting + $scope.setting = { + name: $scope.name, + value: parseInt($scope.settings[$scope.name], 10) + }; + + /** + * Callback to save the setting value to the database + * @param setting {{value:*, name:string}} note that the value will be stringified + */ + $scope.save = function (setting) { + let value; + if (typeof setting.value === 'number') { + value = setting.value.toString(); + } else { + ({ value } = setting); + } + + Setting.update( + { name: setting.name }, + { value }, + function () { + growl.success(_t('app.admin.settings.customization_of_SETTING_successfully_saved', { SETTING: _t(`app.admin.settings.${setting.name}`) })); + $scope.settings[$scope.name] = value; + }, + function (error) { + if (error.status === 304) return; + + growl.error(_t('app.admin.settings.an_error_occurred_saving_the_setting')); + console.log(error); + } + ); + }; + } + }); + } +]); diff --git a/app/assets/templates/admin/settings/number.html b/app/assets/templates/admin/settings/number.html new file mode 100644 index 000000000..e616d0e6a --- /dev/null +++ b/app/assets/templates/admin/settings/number.html @@ -0,0 +1,15 @@ + + +
+
+
+ +
+ +
+ + {{ helperText | translate }} + +
+ + diff --git a/app/assets/templates/admin/settings/reservations.html b/app/assets/templates/admin/settings/reservations.html index b122f19d7..d4bc1693c 100644 --- a/app/assets/templates/admin/settings/reservations.html +++ b/app/assets/templates/admin/settings/reservations.html @@ -23,66 +23,50 @@

{{ 'app.admin.settings.max_visibility' }}

-
- -
-
-
- -
- -
-
- -
-
- -
-
-
- -
- -
-
- -
+ + + +

{{ 'app.admin.settings.ability_for_the_users_to_move_their_reservations' }}

-
- -
-
-
- -
- -
-
- -
+ +

{{ 'app.admin.settings.ability_for_the_users_to_cancel_their_reservations' }}

-
- -
-
-
- -
- -
-
- -
+ +

{{ 'app.admin.settings.book_overlapping_slots_info' }}

@@ -102,21 +86,14 @@
-
- -
-
-
- -
- -
- - {{ 'app.admin.settings.default_value_is_24_hours' | translate }} - -
- -
+ +
From a63340188bb67944e4d6e3ed54611b2e98934c58 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 20 May 2020 17:18:19 +0200 Subject: [PATCH 016/209] configure default slot duration from settings panel --- app/assets/javascripts/router.js.erb | 2 +- app/assets/stylesheets/modules/settings.scss | 6 ++++++ .../templates/admin/settings/reservations.html | 18 +++++++++++++++++- app/helpers/application_helper.rb | 2 +- app/models/setting.rb | 3 ++- config/locales/app.admin.en.yml | 4 ++++ config/locales/app.admin.fr.yml | 4 ++++ db/seeds.rb | 6 ++++++ doc/environment.md | 9 --------- lib/tasks/fablab/setup.rake | 3 ++- 10 files changed, 43 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/router.js.erb b/app/assets/javascripts/router.js.erb index 1772fe61a..0d638ab5e 100644 --- a/app/assets/javascripts/router.js.erb +++ b/app/assets/javascripts/router.js.erb @@ -1011,7 +1011,7 @@ angular.module('application.router', ['ui.router']) return Setting.query({ names: `['twitter_name', 'about_title', 'about_body', 'tracking_id',\ 'privacy_body', 'privacy_dpo', 'about_contacts', 'book_overlapping_slots', \ - 'home_blogpost', 'machine_explications_alert', 'training_explications_alert', \ + 'home_blogpost', 'machine_explications_alert', 'training_explications_alert', 'slot_duration', \ 'training_information_message', 'subscription_explications_alert', 'event_explications_alert', \ 'space_explications_alert', 'booking_window_start', 'booking_window_end', \ 'booking_move_enable', 'booking_move_delay', 'booking_cancel_enable', \ diff --git a/app/assets/stylesheets/modules/settings.scss b/app/assets/stylesheets/modules/settings.scss index 7414033a5..3e5889803 100644 --- a/app/assets/stylesheets/modules/settings.scss +++ b/app/assets/stylesheets/modules/settings.scss @@ -67,4 +67,10 @@ } } } + + .section-separator { + background: radial-gradient(#dddddd, transparent); + height: 1px; + margin: 24px 33% 12px 33%; + } } diff --git a/app/assets/templates/admin/settings/reservations.html b/app/assets/templates/admin/settings/reservations.html index d4bc1693c..b1d8c885d 100644 --- a/app/assets/templates/admin/settings/reservations.html +++ b/app/assets/templates/admin/settings/reservations.html @@ -21,6 +21,7 @@
+

{{ 'app.admin.settings.max_visibility' }}

+

{{ 'app.admin.settings.ability_for_the_users_to_move_their_reservations' }}

@@ -68,10 +70,24 @@ required="allSettings.booking_cancel_enable === 'true'">
+

{{ 'app.admin.settings.book_overlapping_slots_info' }}

+
+
+

{{ 'app.admin.settings.default_slot_duration' }}

+

{{ 'app.admin.settings.default_slot_duration_info' }}

+ + +
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 4513e0d63..55735c7d2 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -5,7 +5,7 @@ module ApplicationHelper require 'message_format' ## machine/spaces availabilities are divided in multiple slots of 60 minutes - SLOT_DURATION ||= Rails.application.secrets.slot_duration || 60 + SLOT_DURATION ||= Setting.get('slot_duration') || 60 ## # Verify if the provided attribute is in the provided attributes array, whatever it exists or not diff --git a/app/models/setting.rb b/app/models/setting.rb index c9389afc5..aa24093bd 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -78,7 +78,8 @@ class Setting < ApplicationRecord uuid phone_required tracking_id - book_overlapping_slots] } + book_overlapping_slots + slot_duration] } def value last_value = history_values.order(HistoryValue.arel_table['created_at'].desc).first last_value&.value diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 401a37da5..12ce02fb2 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1022,6 +1022,7 @@ en: phone_required: "phone required" tracking_id: "tracking ID" book_overlapping_slots: "book overlapping slots" + slot_duration: "slots duration" elements_ordering: "Elements ordering" machines_order: "Machines order" display_machines_sorted_by: "Display machines sorted by" @@ -1031,6 +1032,9 @@ en: an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." book_overlapping_slots_info: "Allow / prevent the reservation of overlapping slots" allow_booking: "Allow booking" + default_slot_duration: "Default duration for slots" + duration_minutes: "Duration (in minutes)" + default_slot_duration_info: "Machine and space availabilities are divided in multiple slots of this duration. This value can be overridden per availability." sort_by: default: "Default" name: "Name" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index e1f60c8d5..05044fafe 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1022,6 +1022,7 @@ fr: phone_required: "téléphone requis" tracking_id: "ID de suivi" book_overlapping_slots: "réservation de créneaux simultanés" + slot_duration: "durée des créneaux" elements_ordering: "Ordre d'affichage des éléments" machines_order: "Ordre des machines" display_machines_sorted_by: "Afficher les machines triées par" @@ -1031,6 +1032,9 @@ fr: an_error_occurred_saving_the_setting: "Une erreur est survenue pendant l'enregistrement du paramètre. Veuillez réessayer plus tard." book_overlapping_slots_info: "Autoriser / empêcher la réservation de créneaux qui se chevauchent" allow_booking: "Autoriser la réservation" + default_slot_duration: "Durée par défaut pour les créneaux" + duration_minutes: "Durée (en minutes)" + default_slot_duration_info: "Les disponibilités des machines et des espaces sont divisées en plusieurs créneaux de cette durée. Cette valeur peur être changée pour chaque disponibilité." sort_by: default: "Défaut" name: "Nom" diff --git a/db/seeds.rb b/db/seeds.rb index e9413f7fb..cc5a7ea8f 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -951,6 +951,12 @@ unless Setting.find_by(name: 'home_content').try(:value) setting.save end +unless Setting.find_by(name: 'slot_duration').try(:value) + setting = Setting.find_or_initialize_by(name: 'slot_duration') + setting.value = '60' + setting.save +end + if StatisticCustomAggregation.count.zero? # available reservations hours for machines machine_hours = StatisticType.find_by(key: 'hour', statistic_index_id: 2) diff --git a/doc/environment.md b/doc/environment.md index 943e9fc98..5786a0418 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -123,15 +123,6 @@ Set to 'false' if you don't want this behaviour. EVENTS_IN_CALENDAR If set to 'true', the admin calendar will display the scheduled events in the current view, as read-only items. - - - SLOT_DURATION - -Machine and space availabilities are divided in multiple slots of the duration set by this variable. -Default value is 60 minutes (1 hour). - -⚠ Changing this value during the application life may cause serious issues. -Please ensure there's no machine/space availabilities opened to reservation or already reserved **in the future** when you change this value. DEFAULT_MAIL_FROM diff --git a/lib/tasks/fablab/setup.rake b/lib/tasks/fablab/setup.rake index 21d4882df..d7d96dcad 100644 --- a/lib/tasks/fablab/setup.rake +++ b/lib/tasks/fablab/setup.rake @@ -106,7 +106,8 @@ namespace :fablab do mapping = [ %w[PHONE_REQUIRED phone_required true], %w[GA_ID tracking_id], - %w[BOOK_SLOT_AT_SAME_TIME book_overlapping_slots true] + %w[BOOK_SLOT_AT_SAME_TIME book_overlapping_slots true], + %w[SLOT_DURATION slot_duration 60] ] mapping.each do |m| From ba4c39ca9995569b5c53f5534e367ec5e08eb76f Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 20 May 2020 17:36:57 +0200 Subject: [PATCH 017/209] use slot duration from the db setting --- app/controllers/api/slots_controller.rb | 2 +- app/helpers/application_helper.rb | 3 --- app/models/availability.rb | 4 ++-- app/models/slot.rb | 2 +- app/services/availabilities/availabilities_service.rb | 4 ++-- app/services/availabilities/public_availabilities_service.rb | 4 ++-- app/views/application/index.html.erb | 2 +- app/views/exports/availabilities_index.xlsx.axlsx | 4 ++-- 8 files changed, 11 insertions(+), 14 deletions(-) diff --git a/app/controllers/api/slots_controller.rb b/app/controllers/api/slots_controller.rb index f3d4a52ea..e901efb2a 100644 --- a/app/controllers/api/slots_controller.rb +++ b/app/controllers/api/slots_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Slot # Slots are used to cut Availabilities into reservable slots. The duration of these slots is configured per -# availability by Availability.slot_duration, or otherwise globally by ApplicationHelper::SLOT_DURATION minutes +# availability by Availability.slot_duration, or otherwise globally by Setting.get('slot_duration') class API::SlotsController < API::ApiController before_action :authenticate_user! before_action :set_slot, only: %i[update cancel] diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 55735c7d2..f42c7661a 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -4,9 +4,6 @@ module ApplicationHelper require 'message_format' - ## machine/spaces availabilities are divided in multiple slots of 60 minutes - SLOT_DURATION ||= Setting.get('slot_duration') || 60 - ## # Verify if the provided attribute is in the provided attributes array, whatever it exists or not # @param attributes {Array|nil} diff --git a/app/models/availability.rb b/app/models/availability.rb index 6cc51bfe3..ff7e63d96 100644 --- a/app/models/availability.rb +++ b/app/models/availability.rb @@ -89,7 +89,7 @@ class Availability < ApplicationRecord def available_space_places return unless available_type == 'space' - duration = slot_duration || ApplicationHelper::SLOT_DURATION + duration = slot_duration || Setting.get('slot_duration') ((end_at - start_at) / duration.minutes).to_i * nb_total_places end @@ -162,7 +162,7 @@ class Availability < ApplicationRecord def length_must_be_slot_multiple return unless available_type == 'machines' || available_type == 'space' - duration = slot_duration || ApplicationHelper::SLOT_DURATION + duration = slot_duration || Setting.get('slot_duration') return unless end_at < (start_at + duration.minutes) errors.add(:end_at, I18n.t('availabilities.length_must_be_slot_multiple', MIN: duration)) diff --git a/app/models/slot.rb b/app/models/slot.rb index 9341d52ea..3af13f833 100644 --- a/app/models/slot.rb +++ b/app/models/slot.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # Time range, slicing an Availability. -# Its duration is defined by globally by ApplicationHelper::SLOT_DURATION but can be overridden per availability +# Its duration is defined by globally by Setting.get('slot_duration') but can be overridden per availability # During a slot a Reservation is possible # Only reserved slots are persisted in DB, others are instantiated on the fly class Slot < ApplicationRecord diff --git a/app/services/availabilities/availabilities_service.rb b/app/services/availabilities/availabilities_service.rb index 9c4b77696..9ee40b121 100644 --- a/app/services/availabilities/availabilities_service.rb +++ b/app/services/availabilities/availabilities_service.rb @@ -17,7 +17,7 @@ class Availabilities::AvailabilitiesService slots = [] availabilities.each do |a| - slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION + slot_duration = a.slot_duration || Setting.get('slot_duration') ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i| next unless (a.start_at + (i * slot_duration).minutes) > DateTime.current || user.admin? @@ -44,7 +44,7 @@ class Availabilities::AvailabilitiesService slots = [] availabilities.each do |a| - slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION + slot_duration = a.slot_duration || Setting.get('slot_duration') ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i| next unless (a.start_at + (i * slot_duration).minutes) > DateTime.current || user.admin? diff --git a/app/services/availabilities/public_availabilities_service.rb b/app/services/availabilities/public_availabilities_service.rb index 1f55330ff..0e81b98fa 100644 --- a/app/services/availabilities/public_availabilities_service.rb +++ b/app/services/availabilities/public_availabilities_service.rb @@ -15,7 +15,7 @@ class Availabilities::PublicAvailabilitiesService .where(lock: false) slots = [] availabilities.each do |a| - slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION + slot_duration = a.slot_duration || Setting.get('slot_duration') a.machines.each do |machine| next unless machine_ids&.include?(machine.id.to_s) @@ -46,7 +46,7 @@ class Availabilities::PublicAvailabilitiesService slots = [] availabilities.each do |a| - slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION + slot_duration = a.slot_duration || Setting.get('slot_duration') space = a.spaces.first ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i| next unless (a.start_at + (i * slot_duration).minutes) > DateTime.current diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index a195e0528..2b592b512 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -31,7 +31,7 @@ Fablab.fablabWithoutWallet = ('<%= Rails.application.secrets.fablab_without_wallet %>' === 'true'); Fablab.bookSlotAtSameTime = ('<%= Setting.get('book_overlapping_slots') %>' === 'true'); Fablab.eventsInCalendar = ('<%= Rails.application.secrets.events_in_calendar %>' === 'true'); - Fablab.slotDuration = parseInt("<%= ApplicationHelper::SLOT_DURATION %>", 10); + Fablab.slotDuration = parseInt("<%= Setting.get('slot_duration') %>", 10); Fablab.featureTourDisplay = "<%= Rails.application.secrets.feature_tour_display %>"; Fablab.disqusShortname = "<%= Rails.application.secrets.disqus_shortname %>"; Fablab.defaultHost = "<%= Rails.application.secrets.default_host %>"; diff --git a/app/views/exports/availabilities_index.xlsx.axlsx b/app/views/exports/availabilities_index.xlsx.axlsx index cc8d3fd2f..7d9e28921 100644 --- a/app/views/exports/availabilities_index.xlsx.axlsx +++ b/app/views/exports/availabilities_index.xlsx.axlsx @@ -16,7 +16,7 @@ wb.add_worksheet(name: t('export_availabilities.machines')) do |sheet| # data rows @availabilities.where(available_type: 'machines').order(:start_at).each do |a| - slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION + slot_duration = a.slot_duration || Setting.get('slot_duration') a.machines.each do |m| ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i| start_at = a.start_at + (i * slot_duration).minutes @@ -84,7 +84,7 @@ if Rails.application.secrets.fablab_without_spaces != 'false' # data rows @availabilities.where(available_type: 'space').order(:start_at).each do |a| - slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION + slot_duration = a.slot_duration || Setting.get('slot_duration') ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i| start_at = a.start_at + (i * slot_duration).minutes end_at = a.start_at + (i * slot_duration).minutes + slot_duration.minutes From 54d9b348e0c1e67bf7b0a0299d5cf01e12333c34 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 25 May 2020 15:16:40 +0200 Subject: [PATCH 018/209] retrieve slot_duration directly from the api, in the front-end --- app/assets/javascripts/app.js | 2 -- .../javascripts/controllers/admin/calendar.js.erb | 15 ++++++++------- .../javascripts/controllers/admin/pricing.js.erb | 11 +++++++---- app/assets/javascripts/router.js.erb | 6 ++++-- app/views/application/index.html.erb | 1 - 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/app.js b/app/assets/javascripts/app.js index 0b08ad6cf..6f5d0f3d3 100644 --- a/app/assets/javascripts/app.js +++ b/app/assets/javascripts/app.js @@ -93,8 +93,6 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout $rootScope.phoneRequired = Fablab.phoneRequired; // Global config: if true, the events are shown in the admin calendar $rootScope.eventsInCalendar = Fablab.eventsInCalendar; - // Global config: machine/space slot duration - $rootScope.slotDuration = Fablab.slotDuration; // Global config: if true, user must confirm his email to sign in $rootScope.userConfirmationNeededToSignIn = Fablab.userConfirmationNeededToSignIn; // Global config: if true, wallet will be disable diff --git a/app/assets/javascripts/controllers/admin/calendar.js.erb b/app/assets/javascripts/controllers/admin/calendar.js.erb index 287ae138b..5cb947ce5 100644 --- a/app/assets/javascripts/controllers/admin/calendar.js.erb +++ b/app/assets/javascripts/controllers/admin/calendar.js.erb @@ -18,8 +18,8 @@ * Controller used in the calendar management page */ -Application.Controllers.controller('AdminCalendarController', ['$scope', '$state', '$uibModal', 'moment', 'AuthService', 'Availability', 'Slot', 'Setting', 'Export', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', 'plansPromise', 'groupsPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Member', 'uiTourService', - function ($scope, $state, $uibModal, moment, AuthService, Availability, Slot, Setting, Export, growl, dialogs, bookingWindowStart, bookingWindowEnd, machinesPromise, plansPromise, groupsPromise, _t, uiCalendarConfig, CalendarConfig, Member, uiTourService) { +Application.Controllers.controller('AdminCalendarController', ['$scope', '$state', '$uibModal', 'moment', 'AuthService', 'Availability', 'Slot', 'Setting', 'Export', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', 'plansPromise', 'groupsPromise', 'slotDurationPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Member', 'uiTourService', + function ($scope, $state, $uibModal, moment, AuthService, Availability, Slot, Setting, Export, growl, dialogs, bookingWindowStart, bookingWindowEnd, machinesPromise, plansPromise, groupsPromise, slotDurationPromise, _t, uiCalendarConfig, CalendarConfig, Member, uiTourService) { /* PRIVATE STATIC CONSTANTS */ // The calendar is divided in slots of 30 minutes @@ -29,7 +29,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state const BOOKING_SNAP = '00:30:00'; // We do not allow the creation of slots that are not a multiple of 60 minutes - const SLOT_MULTIPLE = Fablab.slotDuration; + const SLOT_MULTIPLE = slotDurationPromise.setting.value; /* PUBLIC SCOPE */ @@ -429,7 +429,8 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state spacesPromise: ['Space', function (Space) { return Space.query().$promise; }], tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }], plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }], - groupsPromise: ['Group', function (Group) { return Group.query().$promise; }] + groupsPromise: ['Group', function (Group) { return Group.query().$promise; }], + slotDurationPromise: ['Setting', function (Setting) { return Setting.get({ name: 'slot_duration' }).$promise; }] } }); // when the modal is closed, we send the slot to the server for saving modalInstance.result.then( @@ -531,8 +532,8 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state /** * Controller used in the slot creation modal window */ -Application.Controllers.controller('CreateEventModalController', ['$scope', '$uibModalInstance', '$sce', 'moment', 'start', 'end', 'slots', 'machinesPromise', 'Availability', 'trainingsPromise', 'spacesPromise', 'tagsPromise', 'plansPromise', 'groupsPromise', 'growl', '_t', - function ($scope, $uibModalInstance, $sce, moment, start, end, slots, machinesPromise, Availability, trainingsPromise, spacesPromise, tagsPromise, plansPromise, groupsPromise, growl, _t) { +Application.Controllers.controller('CreateEventModalController', ['$scope', '$uibModalInstance', '$sce', 'moment', 'start', 'end', 'slots', 'machinesPromise', 'Availability', 'trainingsPromise', 'spacesPromise', 'tagsPromise', 'plansPromise', 'groupsPromise', 'slotDurationPromise', 'growl', '_t', + function ($scope, $uibModalInstance, $sce, moment, start, end, slots, machinesPromise, Availability, trainingsPromise, spacesPromise, tagsPromise, plansPromise, groupsPromise, slotDurationPromise, growl, _t) { // $uibModal parameter $scope.start = start; @@ -595,7 +596,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui period: 'week', nb_periods: 1, end_date: undefined, // recurrence end - slot_duration: Fablab.slotDuration + slot_duration: parseInt(slotDurationPromise.setting.value, 10) }; // recurrent slots diff --git a/app/assets/javascripts/controllers/admin/pricing.js.erb b/app/assets/javascripts/controllers/admin/pricing.js.erb index 7d501e4a0..9aa323607 100644 --- a/app/assets/javascripts/controllers/admin/pricing.js.erb +++ b/app/assets/javascripts/controllers/admin/pricing.js.erb @@ -18,8 +18,8 @@ /** * Controller used in the prices edition page */ -Application.Controllers.controller('EditPricingController', ['$scope', '$state', '$uibModal', '$filter', 'TrainingsPricing', 'Credit', 'Pricing', 'Plan', 'Coupon', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', 'spacesPromise', 'spacesPricesPromise', 'spacesCreditsPromise', '_t', 'Member', 'uiTourService', - function ($scope, $state, $uibModal, $filter, TrainingsPricing, Credit, Pricing, Plan, Coupon, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, spacesPromise, spacesPricesPromise, spacesCreditsPromise, _t, Member, uiTourService) { +Application.Controllers.controller('EditPricingController', ['$scope', '$state', '$uibModal', '$filter', 'TrainingsPricing', 'Credit', 'Pricing', 'Plan', 'Coupon', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', 'spacesPromise', 'spacesPricesPromise', 'spacesCreditsPromise', 'slotDurationPromise', '_t', 'Member', 'uiTourService', + function ($scope, $state, $uibModal, $filter, TrainingsPricing, Credit, Pricing, Plan, Coupon, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, spacesPromise, spacesPricesPromise, spacesCreditsPromise, slotDurationPromise, _t, Member, uiTourService) { /* PUBLIC SCOPE */ // List of machines prices (not considering any plan) @@ -76,6 +76,9 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state', // Default: we show only enabled plans $scope.planFiltering = 'enabled'; + // Default duration for the slots + $scope.slotDuration = parseInt(slotDurationPromise.setting.value, 10); + // Available options for filtering plans by status $scope.filterDisabled = [ 'enabled', @@ -620,7 +623,7 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state', /** * Return the exemple price based on the configuration of the default slot duration. * @param type {string} 'hourly_rate' | * - * @returns {number} price for Fablab.slotDuration minutes. + * @returns {number} price for "SLOT_DURATION" minutes. */ $scope.examplePrice = function(type) { const hourlyRate = 10; @@ -629,7 +632,7 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state', return $filter('currency')(hourlyRate); } - const price = (hourlyRate / 60) * Fablab.slotDuration; + const price = (hourlyRate / 60) * $scope.slotDuration; return $filter('currency')(price); } diff --git a/app/assets/javascripts/router.js.erb b/app/assets/javascripts/router.js.erb index 0d638ab5e..43184a193 100644 --- a/app/assets/javascripts/router.js.erb +++ b/app/assets/javascripts/router.js.erb @@ -586,7 +586,8 @@ angular.module('application.router', ['ui.router']) bookingWindowEnd: ['Setting', function (Setting) { return Setting.get({ name: 'booking_window_end' }).$promise; }], machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }], - groupsPromise: ['Group', function (Group) { return Group.query().$promise; }] + groupsPromise: ['Group', function (Group) { return Group.query().$promise; }], + slotDurationPromise: ['Setting', function (Setting) { return Setting.get({ name: 'slot_duration' }).$promise; }] } }) .state('app.admin.calendar.icalendar', { @@ -752,7 +753,8 @@ angular.module('application.router', ['ui.router']) couponsPromise: ['Coupon', function (Coupon) { return Coupon.query({ page: 1, filter: 'all' }).$promise; }], spacesPromise: ['Space', function (Space) { return Space.query().$promise; }], spacesPricesPromise: ['Price', function (Price) { return Price.query({ priceable_type: 'Space', plan_id: 'null' }).$promise; }], - spacesCreditsPromise: ['Credit', function (Credit) { return Credit.query({ creditable_type: 'Space' }).$promise; }] + spacesCreditsPromise: ['Credit', function (Credit) { return Credit.query({ creditable_type: 'Space' }).$promise; }], + slotDurationPromise: ['Setting', function (Setting) { return Setting.get({ name: 'slot_duration' }).$promise; }] } }) diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index 2b592b512..278c69b54 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -31,7 +31,6 @@ Fablab.fablabWithoutWallet = ('<%= Rails.application.secrets.fablab_without_wallet %>' === 'true'); Fablab.bookSlotAtSameTime = ('<%= Setting.get('book_overlapping_slots') %>' === 'true'); Fablab.eventsInCalendar = ('<%= Rails.application.secrets.events_in_calendar %>' === 'true'); - Fablab.slotDuration = parseInt("<%= Setting.get('slot_duration') %>", 10); Fablab.featureTourDisplay = "<%= Rails.application.secrets.feature_tour_display %>"; Fablab.disqusShortname = "<%= Rails.application.secrets.disqus_shortname %>"; Fablab.defaultHost = "<%= Rails.application.secrets.default_host %>"; From ed287884de8d4748fd8da6ab1d4c83c27c565c09 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 25 May 2020 15:28:06 +0200 Subject: [PATCH 019/209] retrieve book_overlapping_slots directly from the api --- app/assets/javascripts/controllers/events.js.erb | 1 + app/assets/javascripts/directives/cart.js.erb | 9 +++++---- app/views/application/index.html.erb | 1 - 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/controllers/events.js.erb b/app/assets/javascripts/controllers/events.js.erb index 40768ee4b..514d331f3 100644 --- a/app/assets/javascripts/controllers/events.js.erb +++ b/app/assets/javascripts/controllers/events.js.erb @@ -859,6 +859,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' controller: 'ReserveSlotSameTimeController', resolve: { sameTimeReservations: function() { return sameTimeReservations; }, + bookOverlappingSlotsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'book_overlapping_slots' }).$promise; }] } }); modalInstance.result.then(callback); diff --git a/app/assets/javascripts/directives/cart.js.erb b/app/assets/javascripts/directives/cart.js.erb index 35fb70539..8fe332ac7 100644 --- a/app/assets/javascripts/directives/cart.js.erb +++ b/app/assets/javascripts/directives/cart.js.erb @@ -361,7 +361,8 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', size: 'md', controller: 'ReserveSlotSameTimeController', resolve: { - sameTimeReservations: function() { return sameTimeReservations; } + sameTimeReservations: function() { return sameTimeReservations; }, + bookOverlappingSlotsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'book_overlapping_slots' }).$promise; }] } }); modalInstance.result.then(function(res) { @@ -783,10 +784,10 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', /** * Controller of the modal showing the reservations the same date at the same time */ -Application.Controllers.controller('ReserveSlotSameTimeController', ['$scope', '$uibModalInstance', 'AuthService', 'sameTimeReservations', - function ($scope, $uibModalInstance, AuthService, sameTimeReservations) { +Application.Controllers.controller('ReserveSlotSameTimeController', ['$scope', '$uibModalInstance', 'AuthService', 'sameTimeReservations', 'bookOverlappingSlotsPromise', + function ($scope, $uibModalInstance, AuthService, sameTimeReservations, bookOverlappingSlotsPromise) { $scope.sameTimeReservations = sameTimeReservations; - $scope.bookSlotAtSameTime = Fablab.bookSlotAtSameTime; + $scope.bookSlotAtSameTime = (bookOverlappingSlotsPromise.setting.value === 'true'); $scope.isAuthorized = AuthService.isAuthorized; /** * Confirmation callback diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index 278c69b54..21e4ffc75 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -29,7 +29,6 @@ Fablab.withoutInvoices = ('<%= Rails.application.secrets.fablab_without_invoices %>' === 'true'); Fablab.phoneRequired = ('<%= Setting.get('phone_required') %>' === 'true'); Fablab.fablabWithoutWallet = ('<%= Rails.application.secrets.fablab_without_wallet %>' === 'true'); - Fablab.bookSlotAtSameTime = ('<%= Setting.get('book_overlapping_slots') %>' === 'true'); Fablab.eventsInCalendar = ('<%= Rails.application.secrets.events_in_calendar %>' === 'true'); Fablab.featureTourDisplay = "<%= Rails.application.secrets.feature_tour_display %>"; Fablab.disqusShortname = "<%= Rails.application.secrets.disqus_shortname %>"; From 3135abcee6449b4325960dcddce5b4ca364dc4f3 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 25 May 2020 16:02:40 +0200 Subject: [PATCH 020/209] retrieve phone_required directly from the api --- app/assets/javascripts/app.js | 2 -- .../javascripts/controllers/admin/members.js.erb | 14 ++++++++++---- .../javascripts/controllers/application.js.erb | 8 +++++++- app/assets/javascripts/controllers/members.js | 7 +++++-- app/assets/javascripts/controllers/profile.js.erb | 7 +++++-- app/assets/javascripts/router.js.erb | 8 +++++++- app/views/application/index.html.erb | 1 - 7 files changed, 34 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/app.js b/app/assets/javascripts/app.js index 6f5d0f3d3..38d12a332 100644 --- a/app/assets/javascripts/app.js +++ b/app/assets/javascripts/app.js @@ -89,8 +89,6 @@ 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 config: if true, the events are shown in the admin calendar $rootScope.eventsInCalendar = Fablab.eventsInCalendar; // Global config: if true, user must confirm his email to sign in diff --git a/app/assets/javascripts/controllers/admin/members.js.erb b/app/assets/javascripts/controllers/admin/members.js.erb index 906bf8396..4463d2d9f 100644 --- a/app/assets/javascripts/controllers/admin/members.js.erb +++ b/app/assets/javascripts/controllers/admin/members.js.erb @@ -641,8 +641,8 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce', /** * Controller used in the member edition page */ -Application.Controllers.controller('EditMemberController', ['$scope', '$state', '$stateParams', 'Member', 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'activeProviderPromise', 'Wallet', - function ($scope, $state, $stateParams, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, activeProviderPromise, Wallet) { +Application.Controllers.controller('EditMemberController', ['$scope', '$state', '$stateParams', 'Member', 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'activeProviderPromise', 'Wallet', 'phoneRequiredPromise', + function ($scope, $state, $stateParams, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, activeProviderPromise, Wallet, phoneRequiredPromise) { /* PUBLIC SCOPE */ // API URL where the form will be posted @@ -660,6 +660,9 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state', // Should the password be modified? $scope.password = { change: false }; + // is the phone number required in _member_form? + $scope.phoneRequired = (phoneRequiredPromise.setting.value === 'true'); + // the user subscription if (($scope.user.subscribed_plan != null) && ($scope.user.subscription != null)) { $scope.subscription = $scope.user.subscription; @@ -948,8 +951,8 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state', /** * Controller used in the member's creation page (admin view) */ -Application.Controllers.controller('NewMemberController', ['$scope', '$state', '$stateParams', 'Member', 'Training', 'Group', 'CSRF', - function ($scope, $state, $stateParams, Member, Training, Group, CSRF) { +Application.Controllers.controller('NewMemberController', ['$scope', '$state', '$stateParams', 'Member', 'Training', 'Group', 'CSRF', 'phoneRequiredPromise', + function ($scope, $state, $stateParams, Member, Training, Group, CSRF, phoneRequiredPromise) { CSRF.setMetaTags(); /* PUBLIC SCOPE */ @@ -963,6 +966,9 @@ Application.Controllers.controller('NewMemberController', ['$scope', '$state', ' // Should the password be set manually or generated? $scope.password = { change: false }; + // is the phone number required in _member_form? + $scope.phoneRequired = (phoneRequiredPromise.setting.value === 'true'); + // Default member's profile parameters $scope.user = { plan_interval: '', diff --git a/app/assets/javascripts/controllers/application.js.erb b/app/assets/javascripts/controllers/application.js.erb index c0f67baa2..eef926281 100644 --- a/app/assets/javascripts/controllers/application.js.erb +++ b/app/assets/javascripts/controllers/application.js.erb @@ -91,7 +91,10 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco return $uibModal.open({ templateUrl: '<%= asset_path "shared/signupModal.html" %>', size: 'md', - controller: ['$scope', '$uibModalInstance', 'Group', 'CustomAsset', 'growl', '_t', function ($scope, $uibModalInstance, Group, CustomAsset, growl, _t) { + resolve: { + phoneRequiredPromise: ['Setting', function (Setting) { return Setting.get({ name: 'phone_required' }).$promise; }] + }, + controller: ['$scope', '$uibModalInstance', 'Group', 'CustomAsset', 'phoneRequiredPromise', 'growl', '_t', function ($scope, $uibModalInstance, Group, CustomAsset, phoneRequiredPromise, growl, _t) { // default parameters for the date picker in the account creation modal $scope.datePicker = { format: Fablab.uibDateFormat, @@ -101,6 +104,9 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco } }; + // is the phone number required to sign-up? + $scope.phoneRequired = (phoneRequiredPromise.setting.value === 'true'); + // reCaptcha v2 site key (or undefined) $scope.recaptchaSiteKey = Fablab.recaptchaSiteKey; diff --git a/app/assets/javascripts/controllers/members.js b/app/assets/javascripts/controllers/members.js index 92a0232e6..2b23102ee 100644 --- a/app/assets/javascripts/controllers/members.js +++ b/app/assets/javascripts/controllers/members.js @@ -72,8 +72,8 @@ Application.Controllers.controller('MembersController', ['$scope', 'Member', 'me /** * Controller used when editing the current user's profile (in dashboard) */ -Application.Controllers.controller('EditProfileController', ['$scope', '$rootScope', '$state', '$window', '$sce', '$cookies', '$injector', 'Member', 'Auth', 'Session', 'activeProviderPromise', 'growl', 'dialogs', 'CSRF', 'memberPromise', 'groups', '_t', - function ($scope, $rootScope, $state, $window, $sce, $cookies, $injector, Member, Auth, Session, activeProviderPromise, growl, dialogs, CSRF, memberPromise, groups, _t) { +Application.Controllers.controller('EditProfileController', ['$scope', '$rootScope', '$state', '$window', '$sce', '$cookies', '$injector', 'Member', 'Auth', 'Session', 'activeProviderPromise', 'phoneRequiredPromise', 'growl', 'dialogs', 'CSRF', 'memberPromise', 'groups', '_t', + function ($scope, $rootScope, $state, $window, $sce, $cookies, $injector, Member, Auth, Session, activeProviderPromise, phoneRequiredPromise, growl, dialogs, CSRF, memberPromise, groups, _t) { /* PUBLIC SCOPE */ // API URL where the form will be posted @@ -110,6 +110,9 @@ Application.Controllers.controller('EditProfileController', ['$scope', '$rootSco // Should the passord be modified? $scope.password = { change: false }; + // is the phone number required in _member_form? + $scope.phoneRequired = (phoneRequiredPromise.setting.value === 'true'); + // Angular-Bootstrap datepicker configuration for birthday $scope.datePicker = { format: Fablab.uibDateFormat, diff --git a/app/assets/javascripts/controllers/profile.js.erb b/app/assets/javascripts/controllers/profile.js.erb index 0ae5e79ce..df7f6ea78 100644 --- a/app/assets/javascripts/controllers/profile.js.erb +++ b/app/assets/javascripts/controllers/profile.js.erb @@ -13,8 +13,8 @@ 'use strict'; -Application.Controllers.controller('CompleteProfileController', ['$scope', '$rootScope', '$state', '$window', '_t', 'growl', 'CSRF', 'Auth', 'Member', 'settingsPromise', 'activeProviderPromise', 'groupsPromise', 'cguFile', 'memberPromise', 'Session', 'dialogs', 'AuthProvider', - function ($scope, $rootScope, $state, $window, _t, growl, CSRF, Auth, Member, settingsPromise, activeProviderPromise, groupsPromise, cguFile, memberPromise, Session, dialogs, AuthProvider) { +Application.Controllers.controller('CompleteProfileController', ['$scope', '$rootScope', '$state', '$window', '_t', 'growl', 'CSRF', 'Auth', 'Member', 'settingsPromise', 'activeProviderPromise', 'groupsPromise', 'cguFile', 'memberPromise', 'Session', 'dialogs', 'AuthProvider', 'phoneRequiredPromise', + function ($scope, $rootScope, $state, $window, _t, growl, CSRF, Auth, Member, settingsPromise, activeProviderPromise, groupsPromise, cguFile, memberPromise, Session, dialogs, AuthProvider, phoneRequiredPromise) { /* PUBLIC SCOPE */ // API URL where the form will be posted @@ -47,6 +47,9 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo // CGU $scope.cgu = cguFile.custom_asset; + // is the phone number required in _member_form? + $scope.phoneRequired = (phoneRequiredPromise.setting.value === 'true'); + // Angular-Bootstrap datepicker configuration for birthday $scope.datePicker = { format: Fablab.uibDateFormat, diff --git a/app/assets/javascripts/router.js.erb b/app/assets/javascripts/router.js.erb index 43184a193..b85583103 100644 --- a/app/assets/javascripts/router.js.erb +++ b/app/assets/javascripts/router.js.erb @@ -126,6 +126,7 @@ angular.module('application.router', ['ui.router']) groupsPromise: ['Group', function (Group) { return Group.query().$promise; }], cguFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'cgu-file' }).$promise; }], memberPromise: ['Member', 'currentUser', function (Member, currentUser) { return Member.get({ id: currentUser.id }).$promise; }], + phoneRequiredPromise: ['Setting', function (Setting) { return Setting.get({ name: 'phone_required' }).$promise; }] } }) @@ -157,6 +158,7 @@ angular.module('application.router', ['ui.router']) resolve: { groups: ['Group', function (Group) { return Group.query().$promise; }], activeProviderPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.active().$promise; }], + phoneRequiredPromise: ['Setting', function (Setting) { return Setting.get({ name: 'phone_required' }).$promise; }] } }) .state('app.logged.dashboard.projects', { @@ -882,6 +884,9 @@ angular.module('application.router', ['ui.router']) templateUrl: '<%= asset_path "admin/members/new.html" %>', controller: 'NewMemberController' } + }, + resolve: { + phoneRequiredPromise: ['Setting', function (Setting) { return Setting.get({ name: 'phone_required' }).$promise; }] } }) .state('app.admin.members_import', { @@ -921,7 +926,8 @@ angular.module('application.router', ['ui.router']) activeProviderPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.active().$promise; }], walletPromise: ['Wallet', '$stateParams', function (Wallet, $stateParams) { return Wallet.getWalletByUser({ user_id: $stateParams.id }).$promise; }], transactionsPromise: ['Wallet', 'walletPromise', function (Wallet, walletPromise) { return Wallet.transactions({ id: walletPromise.id }).$promise; }], - tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }] + tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }], + phoneRequiredPromise: ['Setting', function (Setting) { return Setting.get({ name: 'phone_required' }).$promise; }] } }) .state('app.admin.admins_new', { diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index 21e4ffc75..21d39ebce 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -27,7 +27,6 @@ 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 = ('<%= Setting.get('phone_required') %>' === 'true'); Fablab.fablabWithoutWallet = ('<%= Rails.application.secrets.fablab_without_wallet %>' === 'true'); Fablab.eventsInCalendar = ('<%= Rails.application.secrets.events_in_calendar %>' === 'true'); Fablab.featureTourDisplay = "<%= Rails.application.secrets.feature_tour_display %>"; From 2b0eb477306bbd8b92ff2288af0b0b453aba53a2 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 25 May 2020 16:10:40 +0200 Subject: [PATCH 021/209] reorganized settings/reservations --- .../admin/settings/reservations.html | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/app/assets/templates/admin/settings/reservations.html b/app/assets/templates/admin/settings/reservations.html index b1d8c885d..9dea81204 100644 --- a/app/assets/templates/admin/settings/reservations.html +++ b/app/assets/templates/admin/settings/reservations.html @@ -43,32 +43,38 @@
-

{{ 'app.admin.settings.ability_for_the_users_to_move_their_reservations' }}

- -
-
- - -
-
-

{{ 'app.admin.settings.ability_for_the_users_to_cancel_their_reservations' }}

- -
-
- - +
+
+

{{ 'app.admin.settings.ability_for_the_users_to_move_their_reservations' }}

+ +
+
+ + +
+
+
+
+

{{ 'app.admin.settings.ability_for_the_users_to_cancel_their_reservations' }}

+ +
+
+ + +
+
From 98c63e832769e4440c4240cc560168be782f66cd Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 25 May 2020 16:35:21 +0200 Subject: [PATCH 022/209] [bug] managers do not see the name of the user who reserved a slot --- CHANGELOG.md | 1 + app/services/availabilities/availabilities_service.rb | 2 +- app/services/availabilities/status_service.rb | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acc0905cb..802985382 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog Fab-manager - Improved display of the icons alerting about an outdated version +- Fix a bug: managers do not see the name of the user who reserved a slot - [TODO DEPLOY] `rails fablab:setup:env_to_db` ## v4.4.4 2020 May 25 diff --git a/app/services/availabilities/availabilities_service.rb b/app/services/availabilities/availabilities_service.rb index 9ee40b121..167755aec 100644 --- a/app/services/availabilities/availabilities_service.rb +++ b/app/services/availabilities/availabilities_service.rb @@ -6,7 +6,7 @@ class Availabilities::AvailabilitiesService def initialize(current_user, maximum_visibility = {}) @current_user = current_user @maximum_visibility = maximum_visibility - @service = Availabilities::StatusService.new(current_user.admin? ? 'admin' : 'user') + @service = Availabilities::StatusService.new(current_user.role) end # list all slots for the given machine, with reservations info, relatives to the given user diff --git a/app/services/availabilities/status_service.rb b/app/services/availabilities/status_service.rb index 90dc2321a..31f4ed314 100644 --- a/app/services/availabilities/status_service.rb +++ b/app/services/availabilities/status_service.rb @@ -4,7 +4,7 @@ class Availabilities::StatusService def initialize(current_user_role) @current_user_role = current_user_role - @show_name = (@current_user_role == 'admin' || Setting.get('display_name_enable') == 'true') + @show_name = (%w[admin manager].include?(@current_user_role) || Setting.get('display_name_enable') == 'true') end # check that the provided machine slot is reserved or not and modify it accordingly @@ -19,7 +19,7 @@ class Availabilities::StatusService slot.id = s.id slot.is_reserved = true slot.title = "#{slot.machine.name} - #{@show_name ? r.user&.profile&.full_name : I18n.t('availabilities.not_available')}" - slot.can_modify = true if @current_user_role == 'admin' + slot.can_modify = true if %w[admin manager].include?(@current_user_role) slot.reservations.push r next unless r.statistic_profile_id == statistic_profile_id @@ -41,7 +41,7 @@ class Availabilities::StatusService next unless s.start_at == slot.start_at && s.canceled_at.nil? - slot.can_modify = true if @current_user_role == 'admin' + slot.can_modify = true if %w[admin manager].include?(@current_user_role) slot.reservations.push r next unless r.statistic_profile_id == statistic_profile_id From 01017f301227e5ea39bac358497479b42b9330f5 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 25 May 2020 16:47:06 +0200 Subject: [PATCH 023/209] fix setting.get for boolean --- app/pdfs/pdf/invoice.rb | 4 ++-- app/policies/slot_policy.rb | 2 +- app/services/availabilities/public_availabilities_service.rb | 2 +- app/services/availabilities/status_service.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/pdfs/pdf/invoice.rb b/app/pdfs/pdf/invoice.rb index 203c260fb..b559cc293 100644 --- a/app/pdfs/pdf/invoice.rb +++ b/app/pdfs/pdf/invoice.rb @@ -41,7 +41,7 @@ class PDF::Invoice < Prawn::Document else text I18n.t('invoices.invoice_reference', REF: invoice.reference), leading: 3 end - if Setting.get('invoice_code-active') == 'true' + if Setting.get('invoice_code-active') text I18n.t('invoices.code', CODE: Setting.get('invoice_code-value')), leading: 3 end if invoice.invoiced_type != WalletTransaction.name @@ -251,7 +251,7 @@ class PDF::Invoice < Prawn::Document row(0).font_style = :bold column(1).style align: :right - if Setting.get('invoice_VAT-active') == 'true' + if Setting.get('invoice_VAT-active') # Total incl. taxes row(-1).style align: :right row(-1).background_color = 'E4E4E4' diff --git a/app/policies/slot_policy.rb b/app/policies/slot_policy.rb index 29d86a303..315ec317b 100644 --- a/app/policies/slot_policy.rb +++ b/app/policies/slot_policy.rb @@ -5,7 +5,7 @@ class SlotPolicy < ApplicationPolicy def update? # check that the update is allowed and the prevention delay has not expired delay = Setting.get('booking_move_delay').to_i - enabled = (Setting.get('booking_move_enable') == 'true') + enabled = Setting.get('booking_move_enable') # these condition does not apply to admins user.admin? || user.manager? || diff --git a/app/services/availabilities/public_availabilities_service.rb b/app/services/availabilities/public_availabilities_service.rb index 0e81b98fa..7e0fce152 100644 --- a/app/services/availabilities/public_availabilities_service.rb +++ b/app/services/availabilities/public_availabilities_service.rb @@ -4,7 +4,7 @@ class Availabilities::PublicAvailabilitiesService def initialize(current_user) @current_user = current_user - @service = Availabilities::StatusService.new('') + @service = Availabilities::StatusService.new('public') end # provides a list of slots and availabilities for the machines, between the given dates diff --git a/app/services/availabilities/status_service.rb b/app/services/availabilities/status_service.rb index 31f4ed314..5735466ab 100644 --- a/app/services/availabilities/status_service.rb +++ b/app/services/availabilities/status_service.rb @@ -4,7 +4,7 @@ class Availabilities::StatusService def initialize(current_user_role) @current_user_role = current_user_role - @show_name = (%w[admin manager].include?(@current_user_role) || Setting.get('display_name_enable') == 'true') + @show_name = (%w[admin manager].include?(@current_user_role) || Setting.get('display_name_enable')) end # check that the provided machine slot is reserved or not and modify it accordingly From 57ceeec2e71a64e94e5af5f7d481f15444c251dd Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 25 May 2020 17:05:54 +0200 Subject: [PATCH 024/209] refactored settings/reservations/confidentiality section --- app/assets/templates/admin/settings/reservations.html | 3 ++- config/locales/app.admin.en.yml | 3 ++- config/locales/app.admin.es.yml | 2 +- config/locales/app.admin.fr.yml | 3 ++- config/locales/app.admin.pt.yml | 2 +- config/locales/app.admin.zu.yml | 2 +- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/assets/templates/admin/settings/reservations.html b/app/assets/templates/admin/settings/reservations.html index 9dea81204..4019f47e7 100644 --- a/app/assets/templates/admin/settings/reservations.html +++ b/app/assets/templates/admin/settings/reservations.html @@ -123,11 +123,12 @@
- {{ 'app.admin.settings.confidentiality' }} + {{ 'app.admin.settings.display' }}

{{ 'app.admin.settings.display_machine_reservation_user_name' }}

+

diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 12ce02fb2..0b53e14b3 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1013,7 +1013,8 @@ en: default_value_is_24_hours: "If the field is leaved empty: 24 hours." visibility_yearly: "maximum visibility for annual subscribers" visibility_others: "maximum visibility for other members" - confidentiality: "Confidentiality" + display: "Display" + display_name_info_html: "When enabled, members and visitors browsing the calendar or booking a machine will see the name of the members who has booked some slots. When disabled, only administrators and managers will view the names.
Warning: if you enable this feature, remember to write it in your privacy policy." display_machine_reservation_user_name: "Display the full name of the user who booked a machine slot" display_name: "Display the name" display_name_enable: "name display" diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index 13adbc604..408abec0c 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -1013,7 +1013,7 @@ es: default_value_is_24_hours: "Si el campo está vacío: 24 horas." visibility_yearly: "máxima visibilidad para suscriptores anuales" visibility_others: "máxima visibilidad para otros miembros" - confidentiality: "Confidencialidad" + display: "Display" display_machine_reservation_user_name: "Mostrar el nombre del usuario que ha reservado una maquina" display_name: "Mostrar el nombre" display_name_enable: "la visualización del nombre" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 05044fafe..64ebcbdef 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1013,7 +1013,8 @@ fr: default_value_is_24_hours: "Si aucune valeur n'est renseignée : 24 heures." visibility_yearly: "la visibilité maximum pour les abonnées annuels" visibility_others: "la visibilité maximum pour les autres membres" - confidentiality: "Confidentialité" + display: "Affichage" + display_name_info_html: "Si cette option est activée, les membres et les visiteurs qui parcourent le calendrier ou qui réservent une machine verront le nom des membres ayant réservé des créneaux. Si désactivée, seuls les administrateurs et les gestionnaires verront les noms.
Attention : si vous activez cette fonctionnalité, pensez à l'indiquer dans votre politique de confidentialité." display_machine_reservation_user_name: "Afficher le nom de l'utilisateur ayant réservé une machine" display_name: "Afficher le nom" display_name_enable: "l'affichage du nom" diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index 18a1bfc02..01e0486e2 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -1013,7 +1013,7 @@ pt: default_value_is_24_hours: "Se o campo estiver vazio: 24 horas." visibility_yearly: "visibilidade máxima para assinantes anuais" visibility_others: "visibilidade máxima para outros membros" - confidentiality: "Confidencialidade" + display: "Display" display_machine_reservation_user_name: "Exibir o nome completo do usuário que reservou um slot de máquina" display_name: "Nome de exibição" display_name_enable: "exibição de nome" diff --git a/config/locales/app.admin.zu.yml b/config/locales/app.admin.zu.yml index 13ee8c22e..e706aa1ba 100644 --- a/config/locales/app.admin.zu.yml +++ b/config/locales/app.admin.zu.yml @@ -1013,7 +1013,7 @@ zu: default_value_is_24_hours: "crwdns8395:0crwdne8395:0" visibility_yearly: "crwdns8397:0crwdne8397:0" visibility_others: "crwdns8399:0crwdne8399:0" - confidentiality: "crwdns8401:0crwdne8401:0" + display: "crwdns8401:0crwdne8401:0" display_machine_reservation_user_name: "crwdns8403:0crwdne8403:0" display_name: "crwdns8405:0crwdne8405:0" display_name_enable: "crwdns8407:0crwdne8407:0" From acefc325f6d86b7fa6e0b0436bed9c06a198af74 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 25 May 2020 17:36:53 +0200 Subject: [PATCH 025/209] configure events_in_calendar form the UI panel --- app/assets/javascripts/app.js | 4 +--- app/assets/javascripts/controllers/admin/calendar.js.erb | 9 ++++++--- app/assets/javascripts/router.js.erb | 5 +++-- app/assets/templates/admin/settings/reservations.html | 5 +++++ app/controllers/api/availabilities_controller.rb | 2 +- app/models/setting.rb | 3 ++- app/views/application/index.html.erb | 1 - config/locales/app.admin.en.yml | 4 ++++ config/locales/app.admin.fr.yml | 4 ++++ config/secrets.yml | 8 -------- doc/environment.md | 5 ----- env.example | 2 -- lib/tasks/fablab/setup.rake | 3 ++- setup/env.example | 1 - setup/setup.sh | 2 +- test/fixtures/history_values.yml | 9 +++++++++ test/fixtures/settings.yml | 8 +++++++- 17 files changed, 45 insertions(+), 30 deletions(-) diff --git a/app/assets/javascripts/app.js b/app/assets/javascripts/app.js index 38d12a332..7cfc13358 100644 --- a/app/assets/javascripts/app.js +++ b/app/assets/javascripts/app.js @@ -89,11 +89,9 @@ 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 events are shown in the admin calendar - $rootScope.eventsInCalendar = Fablab.eventsInCalendar; // Global config: if true, user must confirm his email to sign in $rootScope.userConfirmationNeededToSignIn = Fablab.userConfirmationNeededToSignIn; - // Global config: if true, wallet will be disable + // Global config: if true, wallet will be disabled $rootScope.fablabWithoutWallet = Fablab.fablabWithoutWallet; // Global function to allow the user to navigate to the previous screen (ie. $state). diff --git a/app/assets/javascripts/controllers/admin/calendar.js.erb b/app/assets/javascripts/controllers/admin/calendar.js.erb index 5cb947ce5..e0313118b 100644 --- a/app/assets/javascripts/controllers/admin/calendar.js.erb +++ b/app/assets/javascripts/controllers/admin/calendar.js.erb @@ -18,8 +18,8 @@ * Controller used in the calendar management page */ -Application.Controllers.controller('AdminCalendarController', ['$scope', '$state', '$uibModal', 'moment', 'AuthService', 'Availability', 'Slot', 'Setting', 'Export', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', 'plansPromise', 'groupsPromise', 'slotDurationPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Member', 'uiTourService', - function ($scope, $state, $uibModal, moment, AuthService, Availability, Slot, Setting, Export, growl, dialogs, bookingWindowStart, bookingWindowEnd, machinesPromise, plansPromise, groupsPromise, slotDurationPromise, _t, uiCalendarConfig, CalendarConfig, Member, uiTourService) { +Application.Controllers.controller('AdminCalendarController', ['$scope', '$state', '$uibModal', 'moment', 'AuthService', 'Availability', 'Slot', 'Setting', 'Export', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', 'plansPromise', 'groupsPromise', 'slotDurationPromise', 'eventsInCalendarPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Member', 'uiTourService', + function ($scope, $state, $uibModal, moment, AuthService, Availability, Slot, Setting, Export, growl, dialogs, bookingWindowStart, bookingWindowEnd, machinesPromise, plansPromise, groupsPromise, slotDurationPromise, eventsInCalendarPromise, _t, uiCalendarConfig, CalendarConfig, Member, uiTourService) { /* PRIVATE STATIC CONSTANTS */ // The calendar is divided in slots of 30 minutes @@ -29,7 +29,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state const BOOKING_SNAP = '00:30:00'; // We do not allow the creation of slots that are not a multiple of 60 minutes - const SLOT_MULTIPLE = slotDurationPromise.setting.value; + const SLOT_MULTIPLE = parseInt(slotDurationPromise.setting.value, 10); /* PUBLIC SCOPE */ @@ -42,6 +42,9 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state // corresponding fullCalendar item in the DOM $scope.availabilityDom = null; + // Should we show the scheduled events in the calendar? + $scope.eventsInCalendar = (eventsInCalendarPromise.setting.value === 'true'); + // bind the availabilities slots with full-Calendar events $scope.eventSources = []; $scope.eventSources.push({ diff --git a/app/assets/javascripts/router.js.erb b/app/assets/javascripts/router.js.erb index b85583103..a93aada18 100644 --- a/app/assets/javascripts/router.js.erb +++ b/app/assets/javascripts/router.js.erb @@ -589,7 +589,8 @@ angular.module('application.router', ['ui.router']) machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }], groupsPromise: ['Group', function (Group) { return Group.query().$promise; }], - slotDurationPromise: ['Setting', function (Setting) { return Setting.get({ name: 'slot_duration' }).$promise; }] + slotDurationPromise: ['Setting', function (Setting) { return Setting.get({ name: 'slot_duration' }).$promise; }], + eventsInCalendarPromise: ['Setting', function (Setting) { return Setting.get({ name: 'events_in_calendar' }).$promise; }] } }) .state('app.admin.calendar.icalendar', { @@ -1021,7 +1022,7 @@ angular.module('application.router', ['ui.router']) 'privacy_body', 'privacy_dpo', 'about_contacts', 'book_overlapping_slots', \ 'home_blogpost', 'machine_explications_alert', 'training_explications_alert', 'slot_duration', \ 'training_information_message', 'subscription_explications_alert', 'event_explications_alert', \ - 'space_explications_alert', 'booking_window_start', 'booking_window_end', \ + 'space_explications_alert', 'booking_window_start', 'booking_window_end', 'events_in_calendar', \ 'booking_move_enable', 'booking_move_delay', 'booking_cancel_enable', \ 'booking_cancel_delay', 'main_color', 'secondary_color', \ 'fablab_name', 'name_genre', 'reminder_enable', \ diff --git a/app/assets/templates/admin/settings/reservations.html b/app/assets/templates/admin/settings/reservations.html index 4019f47e7..8c563af28 100644 --- a/app/assets/templates/admin/settings/reservations.html +++ b/app/assets/templates/admin/settings/reservations.html @@ -131,5 +131,10 @@

+
+

{{ 'app.admin.settings.events_in_calendar' }}

+

{{ 'app.admin.settings.events_in_calendar_info' }}

+ +
diff --git a/app/controllers/api/availabilities_controller.rb b/app/controllers/api/availabilities_controller.rb index 76ff02bbd..8ca8f82cb 100644 --- a/app/controllers/api/availabilities_controller.rb +++ b/app/controllers/api/availabilities_controller.rb @@ -16,7 +16,7 @@ class API::AvailabilitiesController < API::ApiController @availabilities = Availability.includes(:machines, :tags, :trainings, :spaces) .where('start_at >= ? AND end_at <= ?', start_date, end_date) - @availabilities = @availabilities.where.not(available_type: 'event') unless Rails.application.secrets.events_in_calendar + @availabilities = @availabilities.where.not(available_type: 'event') unless Setting.get('events_in_calendar') @availabilities = @availabilities.where.not(available_type: 'space') if fablab_spaces_deactivated? end diff --git a/app/models/setting.rb b/app/models/setting.rb index aa24093bd..5f4a61fe1 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -79,7 +79,8 @@ class Setting < ApplicationRecord phone_required tracking_id book_overlapping_slots - slot_duration] } + slot_duration + events_in_calendar] } def value last_value = history_values.order(HistoryValue.arel_table['created_at'].desc).first last_value&.value diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index 21d39ebce..97ffaad1b 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -28,7 +28,6 @@ Fablab.withoutOnlinePayment = ('<%= Rails.application.secrets.fablab_without_online_payments %>' === 'true'); Fablab.withoutInvoices = ('<%= Rails.application.secrets.fablab_without_invoices %>' === 'true'); Fablab.fablabWithoutWallet = ('<%= Rails.application.secrets.fablab_without_wallet %>' === 'true'); - Fablab.eventsInCalendar = ('<%= Rails.application.secrets.events_in_calendar %>' === 'true'); Fablab.featureTourDisplay = "<%= Rails.application.secrets.feature_tour_display %>"; Fablab.disqusShortname = "<%= Rails.application.secrets.disqus_shortname %>"; Fablab.defaultHost = "<%= Rails.application.secrets.default_host %>"; diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 0b53e14b3..ad284326d 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1018,6 +1018,10 @@ en: display_machine_reservation_user_name: "Display the full name of the user who booked a machine slot" display_name: "Display the name" display_name_enable: "name display" + events_in_the_calendar: "Display the events in the calendar" + events_in_calendar_info: "When enabled, the admin calendar will display the scheduled events, as read-only items." + show_event: "Show the events" + events_in_calendar: "events display in the calendar" machines_sort_by: "machines display order" fab_analytics: "Fab Analytics" phone_required: "phone required" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 64ebcbdef..fa9bbb37e 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1018,6 +1018,10 @@ fr: display_machine_reservation_user_name: "Afficher le nom de l'utilisateur ayant réservé une machine" display_name: "Afficher le nom" display_name_enable: "l'affichage du nom" + events_in_the_calendar: "Afficher les évènements dans l'agenda" + events_in_calendar_info: "Si cette option est activée, l'agenda administrateur affichera les évènements planifiés en lecture seule." + show_event: "Afficher les évènements" + events_in_calendar: "l'affichage des évènements dans l'agenda" machines_sort_by: "l'ordre d'affichage des machines" fab_analytics: "Fab Analytics" phone_required: "téléphone requis" diff --git a/config/secrets.yml b/config/secrets.yml index 1eea9e04d..ece1cda1e 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -22,8 +22,6 @@ development: fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %> fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> - events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %> - slot_duration: <%= ENV["SLOT_DURATION"] %> feature_tour_display: <%= ENV["FEATURE_TOUR_DISPLAY"] %> default_host: <%= ENV["DEFAULT_HOST"] %> default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %> @@ -68,8 +66,6 @@ test: fablab_without_invoices: false fablab_without_wallet: false user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> - events_in_calendar: false - slot_duration: 60 feature_tour_display: <%= ENV["FEATURE_TOUR_DISPLAY"] %> default_host: <%= ENV["DEFAULT_HOST"] %> default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %> @@ -114,8 +110,6 @@ staging: fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %> fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> - events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %> - slot_duration: <%= ENV["SLOT_DURATION"] %> feature_tour_display: <%= ENV["FEATURE_TOUR_DISPLAY"] %> default_host: <%= ENV["DEFAULT_HOST"] %> default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %> @@ -171,8 +165,6 @@ production: fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %> fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> - events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %> - slot_duration: <%= ENV["SLOT_DURATION"] %> feature_tour_display: <%= ENV["FEATURE_TOUR_DISPLAY"] %> default_host: <%= ENV["DEFAULT_HOST"] %> default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %> diff --git a/doc/environment.md b/doc/environment.md index 5786a0418..64e0116da 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -118,11 +118,6 @@ This is useful if you won't use wallet system. If set to 'true' the users will need to confirm their email address to be able to sign in. Set to 'false' if you don't want this behaviour. - - - EVENTS_IN_CALENDAR - -If set to 'true', the admin calendar will display the scheduled events in the current view, as read-only items. DEFAULT_MAIL_FROM diff --git a/env.example b/env.example index 0801b6356..5e3f8c3be 100644 --- a/env.example +++ b/env.example @@ -25,8 +25,6 @@ FABLAB_WITHOUT_WALLET=false USER_CONFIRMATION_NEEDED_TO_SIGN_IN=false -EVENTS_IN_CALENDAR=false -SLOT_DURATION=60 FEATURE_TOUR_DISPLAY=once DEFAULT_MAIL_FROM=Fab-manager Demo diff --git a/lib/tasks/fablab/setup.rake b/lib/tasks/fablab/setup.rake index d7d96dcad..426b34877 100644 --- a/lib/tasks/fablab/setup.rake +++ b/lib/tasks/fablab/setup.rake @@ -107,7 +107,8 @@ namespace :fablab do %w[PHONE_REQUIRED phone_required true], %w[GA_ID tracking_id], %w[BOOK_SLOT_AT_SAME_TIME book_overlapping_slots true], - %w[SLOT_DURATION slot_duration 60] + %w[SLOT_DURATION slot_duration 60], + %w[EVENTS_IN_CALENDAR events_in_calendar false] ] mapping.each do |m| diff --git a/setup/env.example b/setup/env.example index 015959f21..43271037b 100644 --- a/setup/env.example +++ b/setup/env.example @@ -16,7 +16,6 @@ FABLAB_WITHOUT_INVOICES=false PHONE_REQUIRED=false FABLAB_WITHOUT_WALLET=false -EVENTS_IN_CALENDAR=true SLOT_DURATION=60 FEATURE_TOUR_DISPLAY=once diff --git a/setup/setup.sh b/setup/setup.sh index 63f9955c7..a9be714d3 100755 --- a/setup/setup.sh +++ b/setup/setup.sh @@ -235,7 +235,7 @@ configure_env_file() local doc variables secret doc=$(\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/doc/environment.md) variables=(STRIPE_API_KEY STRIPE_PUBLISHABLE_KEY STRIPE_CURRENCY INVOICE_PREFIX FABLAB_WITHOUT_PLANS FABLAB_WITHOUT_SPACES FABLAB_WITHOUT_ONLINE_PAYMENT FABLAB_WITHOUT_INVOICES FABLAB_WITHOUT_WALLET \ - USER_CONFIRMATION_NEEDED_TO_SIGN_IN EVENTS_IN_CALENDAR SLOT_DURATION DEFAULT_MAIL_FROM DELIVERY_METHOD DEFAULT_HOST DEFAULT_PROTOCOL SMTP_ADDRESS SMTP_PORT SMTP_USER_NAME SMTP_PASSWORD SMTP_AUTHENTICATION \ + USER_CONFIRMATION_NEEDED_TO_SIGN_IN DEFAULT_MAIL_FROM DELIVERY_METHOD DEFAULT_HOST DEFAULT_PROTOCOL SMTP_ADDRESS SMTP_PORT SMTP_USER_NAME SMTP_PASSWORD SMTP_AUTHENTICATION \ SMTP_ENABLE_STARTTLS_AUTO SMTP_OPENSSL_VERIFY_MODE SMTP_TLS RECAPTCHA_SITE_KEY RECAPTCHA_SECRET_KEY DISQUS_SHORTNAME TWITTER_NAME \ FACEBOOK_APP_ID LOG_LEVEL ALLOWED_EXTENSIONS ALLOWED_MIME_TYPES MAX_IMAGE_SIZE MAX_CAO_SIZE MAX_IMPORT_SIZE DISK_SPACE_MB_ALERT FEATURE_TOUR_DISPLAY \ SUPERADMIN_EMAIL APP_LOCALE RAILS_LOCALE MOMENT_LOCALE SUMMERNOTE_LOCALE ANGULAR_LOCALE FULLCALENDAR_LOCALE ELASTICSEARCH_LANGUAGE_ANALYZER TIME_ZONE \ diff --git a/test/fixtures/history_values.yml b/test/fixtures/history_values.yml index d149519a4..37eeac774 100644 --- a/test/fixtures/history_values.yml +++ b/test/fixtures/history_values.yml @@ -584,3 +584,12 @@ value_history_60: created_at: 2020-03-25 09:24:09.016676894 Z updated_at: 2020-03-25 09:24:09.016676894 Z footprint: + +history_value_61: + id: 61 + setting_id: 61 + invoicing_profile_id: 1 + value: '60' + created_at: 2020-05-22 15:22:08.254410000 Z + updated_at: 2020-05-22 15:22:08.254410000 Z + footprint: diff --git a/test/fixtures/settings.yml b/test/fixtures/settings.yml index 0264f52e5..0fa1d1296 100644 --- a/test/fixtures/settings.yml +++ b/test/fixtures/settings.yml @@ -351,4 +351,10 @@ setting_60: id: 60 name: home_content created_at: 2020-03-25 09:21:35.200795784 Z - updated_at: 2020-03-25 09:21:35.200795784 Z \ No newline at end of file + updated_at: 2020-03-25 09:21:35.200795784 Z + +setting_61: + id: 61 + name: slot_duration + created_at: 2020-05-22 15:20:25.254250000 Z + updated_at: 2020-05-22 15:20:25.254250000 Z From fd93093f0d82c26761d8be82a2077032a9a7c7ca Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 26 May 2020 10:53:49 +0200 Subject: [PATCH 026/209] UI to configure the spaces module --- app/assets/javascripts/router.js.erb | 4 ++-- .../templates/admin/settings/general.html | 18 +++++++++++++++ .../templates/admin/settings/privacy.html | 4 +--- .../admin/settings/reservations.html | 2 +- app/helpers/application_helper.rb | 6 ++++- app/models/setting.rb | 3 ++- config/locales/app.admin.en.yml | 4 ++++ config/locales/app.admin.fr.yml | 4 ++++ lib/tasks/fablab/setup.rake | 23 ++++++++++++------- 9 files changed, 52 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/router.js.erb b/app/assets/javascripts/router.js.erb index a93aada18..ba5eb0041 100644 --- a/app/assets/javascripts/router.js.erb +++ b/app/assets/javascripts/router.js.erb @@ -1018,13 +1018,13 @@ angular.module('application.router', ['ui.router']) resolve: { settingsPromise: ['Setting', function (Setting) { return Setting.query({ - names: `['twitter_name', 'about_title', 'about_body', 'tracking_id',\ + names: `['twitter_name', 'about_title', 'about_body', 'tracking_id', \ 'privacy_body', 'privacy_dpo', 'about_contacts', 'book_overlapping_slots', \ 'home_blogpost', 'machine_explications_alert', 'training_explications_alert', 'slot_duration', \ 'training_information_message', 'subscription_explications_alert', 'event_explications_alert', \ 'space_explications_alert', 'booking_window_start', 'booking_window_end', 'events_in_calendar', \ 'booking_move_enable', 'booking_move_delay', 'booking_cancel_enable', \ - 'booking_cancel_delay', 'main_color', 'secondary_color', \ + 'booking_cancel_delay', 'main_color', 'secondary_color', 'spaces_module', \ 'fablab_name', 'name_genre', 'reminder_enable', \ 'reminder_delay', 'visibility_yearly', 'visibility_others', \ 'display_name_enable', 'machines_sort_by', 'fab_analytics', \ diff --git a/app/assets/templates/admin/settings/general.html b/app/assets/templates/admin/settings/general.html index 208dc2b04..349241405 100644 --- a/app/assets/templates/admin/settings/general.html +++ b/app/assets/templates/admin/settings/general.html @@ -347,3 +347,21 @@ + +
+
+ {{ 'app.admin.settings.modules' }} +
+
+
+

{{ 'app.admin.settings.spaces' }}

+

+ +
+
+
diff --git a/app/assets/templates/admin/settings/privacy.html b/app/assets/templates/admin/settings/privacy.html index 4ea267dfe..233434c6d 100644 --- a/app/assets/templates/admin/settings/privacy.html +++ b/app/assets/templates/admin/settings/privacy.html @@ -41,9 +41,7 @@ + label="app.admin.settings.fab_analytics">

{{ 'app.admin.settings.privacy.about_analytics' }} diff --git a/app/assets/templates/admin/settings/reservations.html b/app/assets/templates/admin/settings/reservations.html index 8c563af28..cc7e95d63 100644 --- a/app/assets/templates/admin/settings/reservations.html +++ b/app/assets/templates/admin/settings/reservations.html @@ -132,7 +132,7 @@

-

{{ 'app.admin.settings.events_in_calendar' }}

+

{{ 'app.admin.settings.events_in_the_calendar' }}

{{ 'app.admin.settings.events_in_calendar_info' }}

diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f42c7661a..7f28ad931 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -13,7 +13,7 @@ module ApplicationHelper attributes.try(:include?, attribute) end - def bootstrap_class_for flash_type + def bootstrap_class_for(flash_type) { flash: 'alert-success', alert: 'alert-danger', notice: 'alert-info' }[flash_type.to_sym] || flash_type.to_s end @@ -57,6 +57,10 @@ module ApplicationHelper bool ? :true : :false # rubocop:disable Lint/BooleanSymbol end + def str_to_bool(str, default = 'true') + str.to_s.casecmp(default).zero? + end + def amount_to_f(amount) amount / 100.00 end diff --git a/app/models/setting.rb b/app/models/setting.rb index 5f4a61fe1..e3b62f204 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -80,7 +80,8 @@ class Setting < ApplicationRecord tracking_id book_overlapping_slots slot_duration - events_in_calendar] } + events_in_calendar + spaces_module] } def value last_value = history_values.order(HistoryValue.arel_table['created_at'].desc).first last_value&.value diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index ad284326d..ad191999f 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1040,6 +1040,10 @@ en: default_slot_duration: "Default duration for slots" duration_minutes: "Duration (in minutes)" default_slot_duration_info: "Machine and space availabilities are divided in multiple slots of this duration. This value can be overridden per availability." + modules: "Modules" + spaces: "Spaces" + spaces_info_html: "

A space can be, for example, a woodshop or a meeting room. Their particularity is that they can be booked by several people at the same time.

Warning: It is not recommended to disable spaces if at least one space reservation was made on the system.

" + enable_spaces: "Enable the spaces" sort_by: default: "Default" name: "Name" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index fa9bbb37e..ebbd5b247 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1040,6 +1040,10 @@ fr: default_slot_duration: "Durée par défaut pour les créneaux" duration_minutes: "Durée (en minutes)" default_slot_duration_info: "Les disponibilités des machines et des espaces sont divisées en plusieurs créneaux de cette durée. Cette valeur peur être changée pour chaque disponibilité." + modules: "Modules" + spaces: "Espaces" + spaces_info_html: "

Un espace peut-être, par exemple, un atelier bois ou une salle de réunion. Leur particularité est qu'ils peuvent être réservés par plusieurs personnes en même temps.

Attention : Il n'est pas recommandé de désactiver les espaces is au moins une réservation est en cours sur un espace.

" + enable_spaces: "Activer les espaces" sort_by: default: "Défaut" name: "Nom" diff --git a/lib/tasks/fablab/setup.rake b/lib/tasks/fablab/setup.rake index 426b34877..d04b82e0d 100644 --- a/lib/tasks/fablab/setup.rake +++ b/lib/tasks/fablab/setup.rake @@ -103,18 +103,25 @@ namespace :fablab do desc 'migrate environment variables to the database (settings)' task env_to_db: :environment do + include ApplicationHelper + mapping = [ - %w[PHONE_REQUIRED phone_required true], - %w[GA_ID tracking_id], - %w[BOOK_SLOT_AT_SAME_TIME book_overlapping_slots true], - %w[SLOT_DURATION slot_duration 60], - %w[EVENTS_IN_CALENDAR events_in_calendar false] + %w[_ PHONE_REQUIRED phone_required true], + %w[_ GA_ID tracking_id], + %w[_ BOOK_SLOT_AT_SAME_TIME book_overlapping_slots true], + %w[_ SLOT_DURATION slot_duration 60], + %w[_ EVENTS_IN_CALENDAR events_in_calendar false], + %w[! FABLAB_WITHOUT_SPACES spaces_module] ] mapping.each do |m| - setting = Setting.find_or_initialize_by(name: m[1]) - setting.value = ENV.fetch(m[0], m[2]) - setting.save if setting.value + setting = Setting.find_or_initialize_by(name: m[2]) + value = ENV.fetch(m[1], m[3]) + next unless value + + value = (!str_to_bool(value)).to_s if m[0] == '!' + setting.value = value + setting.save end end end From 6cc6bba7ce7bc11a08778f9f0a645d562567aa31 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 26 May 2020 13:59:40 +0200 Subject: [PATCH 027/209] refactored app to gather spaces module status from the settings --- app/assets/javascripts/app.js | 2 - .../controllers/admin/pricing.js.erb | 2 +- .../controllers/admin/statistics.js.erb | 2 +- app/assets/javascripts/controllers/home.js | 6 +- .../javascripts/controllers/main_nav.js | 4 +- app/assets/javascripts/router.js.erb | 23 +-- .../admin/calendar/calendar.html.erb | 2 +- .../admin/calendar/eventModal.html.erb | 2 +- .../templates/admin/plans/edit.html.erb | 4 +- .../templates/admin/pricing/credits.html.erb | 6 +- .../templates/admin/pricing/index.html.erb | 2 +- .../templates/admin/settings/general.html | 3 +- app/assets/templates/calendar/filter.html.erb | 2 +- .../api/availabilities_controller.rb | 2 +- .../concerns/fablab_configuration.rb | 10 +- app/models/setting.rb | 11 ++ app/services/health_service.rb | 2 +- app/views/application/index.html.erb | 2 +- .../exports/availabilities_index.xlsx.axlsx | 2 +- config/locales/app.admin.en.yml | 1 + config/locales/app.admin.fr.yml | 3 +- config/locales/en.yml | 1 + config/locales/fr.yml | 1 + config/secrets.yml | 4 - db/seeds.rb | 164 ++++-------------- doc/environment.md | 6 - env.example | 1 - lib/tasks/fablab/setup.rake | 2 +- setup/env.example | 1 - setup/setup.sh | 2 +- .../availabilities/as_admin_test.rb | 6 +- 31 files changed, 88 insertions(+), 193 deletions(-) diff --git a/app/assets/javascripts/app.js b/app/assets/javascripts/app.js index 7cfc13358..346bc067f 100644 --- a/app/assets/javascripts/app.js +++ b/app/assets/javascripts/app.js @@ -83,8 +83,6 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout // Global config: if true, the whole 'Plans & Subscriptions' feature will be disabled in the application $rootScope.fablabWithoutPlans = Fablab.withoutPlans; - // Global config: it true, the whole 'Spaces' features will be disabled in the application - $rootScope.fablabWithoutSpaces = Fablab.withoutSpaces; // Global config: if true, all payments will be disabled in the application for the members (only admins will be able to proceed reservations) $rootScope.fablabWithoutOnlinePayment = Fablab.withoutOnlinePayment; // Global config: if true, no invoices will be generated diff --git a/app/assets/javascripts/controllers/admin/pricing.js.erb b/app/assets/javascripts/controllers/admin/pricing.js.erb index 9aa323607..d09d2230d 100644 --- a/app/assets/javascripts/controllers/admin/pricing.js.erb +++ b/app/assets/javascripts/controllers/admin/pricing.js.erb @@ -676,7 +676,7 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state', content: _t('app.admin.tour.pricing.machines.content'), placement: 'bottom' }); - if (!Fablab.withoutSpaces) { + if ($scope.spacesModule) { uitour.createStep({ selector: '.plans-pricing .spaces-tab', stepId: 'spaces', diff --git a/app/assets/javascripts/controllers/admin/statistics.js.erb b/app/assets/javascripts/controllers/admin/statistics.js.erb index 85e650247..1c51be4ed 100644 --- a/app/assets/javascripts/controllers/admin/statistics.js.erb +++ b/app/assets/javascripts/controllers/admin/statistics.js.erb @@ -181,7 +181,7 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state', if (tab.table) { if ((tab.es_type_key === 'subscription') && $rootScope.fablabWithoutPlans) { return true; - } else return (tab.es_type_key === 'space') && $rootScope.fablabWithoutSpaces; + } else return (tab.es_type_key === 'space') && !$rootScope.spacesModule; } else { return true; } diff --git a/app/assets/javascripts/controllers/home.js b/app/assets/javascripts/controllers/home.js index ca681fc40..bbaabca59 100644 --- a/app/assets/javascripts/controllers/home.js +++ b/app/assets/javascripts/controllers/home.js @@ -1,7 +1,7 @@ 'use strict'; -Application.Controllers.controller('HomeController', ['$scope', '$stateParams', '$translatePartialLoader', 'AuthService', 'settingsPromise', 'Member', 'uiTourService', '_t', 'Help', - function ($scope, $stateParams, $translatePartialLoader, AuthService, settingsPromise, Member, uiTourService, _t, Help) { +Application.Controllers.controller('HomeController', ['$scope', '$stateParams', '$translatePartialLoader', 'AuthService', 'settingsPromise', 'Member', 'uiTourService', '_t', + function ($scope, $stateParams, $translatePartialLoader, AuthService, settingsPromise, Member, uiTourService, _t) { /* PUBLIC SCOPE */ // Home page HTML content @@ -140,7 +140,7 @@ Application.Controllers.controller('HomeController', ['$scope', '$stateParams', content: _t('app.public.tour.welcome.machines.content'), placement: 'right' }); - if (!Fablab.withoutSpaces) { + if ($scope.spacesModule) { uitour.createStep({ selector: '.nav-primary li.reserve-space-link', stepId: 'spaces', diff --git a/app/assets/javascripts/controllers/main_nav.js b/app/assets/javascripts/controllers/main_nav.js index 88ee97899..4b27d2631 100644 --- a/app/assets/javascripts/controllers/main_nav.js +++ b/app/assets/javascripts/controllers/main_nav.js @@ -67,7 +67,7 @@ Application.Controllers.controller('MainNavController', ['$scope', function ($sc }); } - if (!Fablab.withoutSpaces) { + if ($scope.spacesModule) { $scope.navLinks.splice(4, 0, { state: 'app.public.spaces_list', linkText: 'app.public.common.reserve_a_space', @@ -153,7 +153,7 @@ Application.Controllers.controller('MainNavController', ['$scope', function ($sc $scope.adminNavLinks = adminNavLinks; - if (!Fablab.withoutSpaces) { + if ($scope.spacesModule) { return $scope.adminNavLinks.splice(3, 0, { state: 'app.public.spaces_list', linkText: 'app.public.common.manage_the_spaces', diff --git a/app/assets/javascripts/router.js.erb b/app/assets/javascripts/router.js.erb index ba5eb0041..cc0424abc 100644 --- a/app/assets/javascripts/router.js.erb +++ b/app/assets/javascripts/router.js.erb @@ -16,7 +16,7 @@ angular.module('application.router', ['ui.router']) // abstract root parents states // these states controls the access rights to the various routes inherited from them - return $stateProvider + $stateProvider .state('app', { abstract: true, views: { @@ -36,14 +36,16 @@ angular.module('application.router', ['ui.router']) resolve: { logoFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-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; }], + spacesModulePromise: ['Setting', function (Setting) { return Setting.get({ name: 'spaces_module' }).$promise; }] }, - onEnter: ['$rootScope', 'logoFile', 'logoBlackFile', 'CSRF', function ($rootScope, logoFile, logoBlackFile, CSRF) { + onEnter: ['$rootScope', 'logoFile', 'logoBlackFile', 'spacesModulePromise', 'CSRF', function ($rootScope, logoFile, logoBlackFile, spacesModulePromise, CSRF) { // Retrieve Anti-CSRF tokens from cookies CSRF.setMetaTags(); // Application logo $rootScope.logo = logoFile.custom_asset; $rootScope.logoBlack = logoBlackFile.custom_asset; + $rootScope.spacesModule = (spacesModulePromise.setting.value === 'true'); }] }) .state('app.public', { @@ -98,7 +100,7 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['home_content', 'home_blogpost']" }).$promise; }] + settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['home_content', 'home_blogpost', 'spaces_module']" }).$promise; }] } }) .state('app.public.privacy', { @@ -366,7 +368,7 @@ angular.module('application.router', ['ui.router']) // spaces .state('app.public.spaces_list', { url: '/spaces', - abstract: Fablab.withoutSpaces, + abstract: !Fablab.spacesModule, views: { 'main@': { templateUrl: '<%= asset_path "spaces/index.html" %>', @@ -379,7 +381,7 @@ angular.module('application.router', ['ui.router']) }) .state('app.admin.space_new', { url: '/spaces/new', - abstract: Fablab.withoutSpaces, + abstract: !Fablab.spacesModule, views: { 'main@': { templateUrl: '<%= asset_path "spaces/new.html" %>', @@ -389,7 +391,7 @@ angular.module('application.router', ['ui.router']) }) .state('app.public.space_show', { url: '/spaces/:id', - abstract: Fablab.withoutSpaces, + abstract: !Fablab.spacesModule, views: { 'main@': { templateUrl: '<%= asset_path "spaces/show.html" %>', @@ -402,7 +404,7 @@ angular.module('application.router', ['ui.router']) }) .state('app.admin.space_edit', { url: '/spaces/:id/edit', - abstract: Fablab.withoutSpaces, + abstract: !Fablab.spacesModule, views: { 'main@': { templateUrl: '<%= asset_path "spaces/edit.html" %>', @@ -415,7 +417,7 @@ angular.module('application.router', ['ui.router']) }) .state('app.logged.space_reserve', { url: '/spaces/:id/reserve', - abstract: Fablab.withoutSpaces, + abstract: !Fablab.spacesModule, views: { 'main@': { templateUrl: '<%= asset_path "spaces/reserve.html" %>', @@ -757,7 +759,8 @@ angular.module('application.router', ['ui.router']) spacesPromise: ['Space', function (Space) { return Space.query().$promise; }], spacesPricesPromise: ['Price', function (Price) { return Price.query({ priceable_type: 'Space', plan_id: 'null' }).$promise; }], spacesCreditsPromise: ['Credit', function (Credit) { return Credit.query({ creditable_type: 'Space' }).$promise; }], - slotDurationPromise: ['Setting', function (Setting) { return Setting.get({ name: 'slot_duration' }).$promise; }] + slotDurationPromise: ['Setting', function (Setting) { return Setting.get({ name: 'slot_duration' }).$promise; }], + spacesModulePromise: ['Setting', function (Setting) { return Setting.get({ name: 'spaces_module' }).$promise; }] } }) diff --git a/app/assets/templates/admin/calendar/calendar.html.erb b/app/assets/templates/admin/calendar/calendar.html.erb index 60e293c4c..1ce39e10f 100644 --- a/app/assets/templates/admin/calendar/calendar.html.erb +++ b/app/assets/templates/admin/calendar/calendar.html.erb @@ -38,7 +38,7 @@
{{ 'app.admin.calendar.trainings' }}
{{ 'app.admin.calendar.machines' }}
- {{ 'app.admin.calendar.spaces' }} + {{ 'app.admin.calendar.spaces' }} {{ 'app.admin.calendar.events' }}
diff --git a/app/assets/templates/admin/calendar/eventModal.html.erb b/app/assets/templates/admin/calendar/eventModal.html.erb index a28c21253..596d44bb4 100644 --- a/app/assets/templates/admin/calendar/eventModal.html.erb +++ b/app/assets/templates/admin/calendar/eventModal.html.erb @@ -18,7 +18,7 @@ {{ 'app.admin.calendar.machine' }} -
+