1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-03-15 12:29:16 +01:00

Merge branch 'dev' for release 5.3.6

This commit is contained in:
Sylvain 2022-03-24 10:48:08 +01:00
commit 3fae1f53c0
132 changed files with 3449 additions and 5306 deletions

View File

@ -1 +0,0 @@
defaults

View File

@ -13,7 +13,9 @@
"angular": true,
"Fablab": true,
"moment": true,
"_": true
"_": true,
"Humanize": true,
"GTM": true
},
"plugins": ["lint-erb"],
"overrides": [

7
.gitignore vendored
View File

@ -65,3 +65,10 @@ yarn-error.log
/yarn-error.log
yarn-debug.log*
.yarn-integrity
/public/packs
/public/packs-test
/node_modules
/yarn-error.log
yarn-debug.log*
.yarn-integrity

View File

@ -1,5 +1,43 @@
# Changelog Fab-manager
## v5.3.6 2022 March 24
- Support for Google Analytics V4
- OAuth2 scopes are now configurable from the interface
- Prepaid-packs purchases are exported to the accounting CSV file
- Updated environment documentation
- Updated react-i18next to 11.15.6
- Updated i18next to 21.6.13
- Updated i18next-icu to 2.0.3
- Updated sidekiq-unique-jobs to 7.1.15
- Updated @uirouter/angularjs to 1.0.30
- Updated bootstrap-sass to 3.4.3
- Removed unmaintained gem sidekiq-cron and replaced it with sidekiq-scheduler
- Removed unmaintained @rails/webpacker v5 and replaced it with shakapacker v6.2.0
- Removed dependency to auto-ngtemplate-loader
- Removed support for Universal Analytics
- Updated deprecated division operators in sass
- Fix a bug: prepaid-packs purchases are reported as subscriptions in the statistics
- Fix a bug: error Couldn't find the binary git during assets compilation
- Fix a bug: a sentence was not linked to a translation key
- Fix a bug: the version check may be scheduled at an invalid time
- Fix a bug: the moment-timezone relied on an outdated version of moment with a case-sensitive locale file
- Fix a bug: unable to delete an administrator who had closed an accounting period
- Fix a bug: captcha keys are not shown in the admin panel, once configured
- Fix a bug: help message in upgrade script has a bogus format
- Fix a security issue: removed message format in elasticsearch's log4j to fix [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228)
- Fix a security issue: updated image_processing to 1.12.2 to fix [CVE-2022-24720](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24720)
- Fix a security issue: updated url-parse to 1.5.10 to fix [CVE-2022-0686](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0686), [CVE-2022-0691](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0691), [CVE-2022-0639](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0639) and [CVE-2022-0512](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0512)
- Fix a security issue: updated rails to 5.2.6.3 to fix [CVE-2022-21831](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21831), [CVE-2022-23633](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23633)
- Fix a security issue: updated sidekiq to 6.4.1 to fix [CVE-2022-23837](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23837)
- Fix a security issue: updated nokogiri to 1.13.3 to fix [CVE-2021-30560](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-30560) and [CVE-2022-23308](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23308)
- Fix a security issue: updated puma to 4.3.11 to fix [CVE-2022-23634](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23634)
- Fix a security issue: updated i18next-http-backend to 1.3.2 to fix [CVE-2022-0235](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0235)
- Fix a security issue: updated follow-redirects to 1.18.8 to fix [CVE-2022-0536](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0536)
- [TODO DEPLOY] `rails fablab:maintenance:regenerate_statistics[2021,07]`
- [TODO DEPLOY] `\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/scripts/cve-2021-44228.sh | bash`
- [TODO DEPLOY] update your oAuth2 provider configuration with the scopes previously defined in the OAUTH2_SCOPE environment variable
## v5.3.5 2022 March 02
- Added [an option](doc/environment.md#OPENLAB_SSL_VERIFY) to allow set verify ssl option for OpenLab

View File

@ -9,6 +9,8 @@ RUN apk update && apk upgrade && \
curl \
nodejs \
yarn \
git \
openssh \
imagemagick \
supervisor \
tzdata \
@ -26,7 +28,6 @@ RUN apk update && apk upgrade && \
alpine-sdk \
build-base \
linux-headers \
git \
patch
RUN gem install bundler

View File

@ -7,8 +7,8 @@ gem 'rails', '~> 5.2.4'
# Used by rails 5.2 to reduce the app boot time by over 50%
gem 'bootsnap'
# Use Puma as web server
gem 'puma', '4.3.9'
gem 'webpacker', '~> 5.x'
gem 'puma', '4.3.11'
gem 'shakapacker', '6.2.0'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
@ -90,8 +90,8 @@ gem 'aasm'
# Background job processing
gem 'sidekiq', '>= 6.0.7'
# Recurring jobs for Sidekiq
gem 'sidekiq-cron'
gem 'sidekiq-unique-jobs', '~> 6.0.22'
gem 'sidekiq-scheduler'
gem 'sidekiq-unique-jobs', '~> 7.1.15'
gem 'stripe', '5.29.0'

View File

@ -4,46 +4,46 @@ GEM
Ascii85 (1.0.3)
aasm (5.0.8)
concurrent-ruby (~> 1.0)
actioncable (5.2.6)
actionpack (= 5.2.6)
actioncable (5.2.6.3)
actionpack (= 5.2.6.3)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailer (5.2.6)
actionpack (= 5.2.6)
actionview (= 5.2.6)
activejob (= 5.2.6)
actionmailer (5.2.6.3)
actionpack (= 5.2.6.3)
actionview (= 5.2.6.3)
activejob (= 5.2.6.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.2.6)
actionview (= 5.2.6)
activesupport (= 5.2.6)
actionpack (5.2.6.3)
actionview (= 5.2.6.3)
activesupport (= 5.2.6.3)
rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionpack-page_caching (1.2.2)
actionpack (>= 5.0.0)
actionview (5.2.6)
activesupport (= 5.2.6)
actionview (5.2.6.3)
activesupport (= 5.2.6.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_record_query_trace (1.7)
activejob (5.2.6)
activesupport (= 5.2.6)
activejob (5.2.6.3)
activesupport (= 5.2.6.3)
globalid (>= 0.3.6)
activemodel (5.2.6)
activesupport (= 5.2.6)
activerecord (5.2.6)
activemodel (= 5.2.6)
activesupport (= 5.2.6)
activemodel (5.2.6.3)
activesupport (= 5.2.6.3)
activerecord (5.2.6.3)
activemodel (= 5.2.6.3)
activesupport (= 5.2.6.3)
arel (>= 9.0)
activestorage (5.2.6)
actionpack (= 5.2.6)
activerecord (= 5.2.6)
activestorage (5.2.6.3)
actionpack (= 5.2.6.3)
activerecord (= 5.2.6.3)
marcel (~> 1.0.0)
activesupport (5.2.6)
activesupport (5.2.6.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@ -66,6 +66,9 @@ GEM
bindex (0.8.1)
bootsnap (1.4.6)
msgpack (~> 1.0)
brpoplpush-redis_script (0.1.2)
concurrent-ruby (~> 1.0, >= 1.0.5)
redis (>= 1.0, <= 5.0)
builder (3.2.4)
bullet (7.0.0)
activesupport (>= 3.0.0)
@ -91,7 +94,7 @@ GEM
cldr-plurals-runtime-rb (1.0.1)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
concurrent-ruby (1.1.8)
concurrent-ruby (1.1.9)
connection_pool (2.2.5)
coveralls_reborn (0.18.0)
simplecov (>= 0.18.1, < 0.20.0)
@ -115,6 +118,7 @@ GEM
dotenv-rails (2.7.5)
dotenv (= 2.7.5)
railties (>= 3.2, < 6.1)
e2mmap (0.1.0)
elasticsearch (5.0.5)
elasticsearch-api (= 5.0.5)
elasticsearch-transport (= 5.0.5)
@ -137,22 +141,22 @@ GEM
multi_json
equalizer (0.0.11)
erubi (1.10.0)
et-orbi (1.2.1)
et-orbi (1.2.7)
tzinfo
faker (2.10.2)
i18n (>= 1.6, < 2)
faraday (0.17.3)
multipart-post (>= 1.2, < 3)
ffi (1.15.4)
ffi (1.15.5)
foreman (0.87.0)
forgery (0.7.0)
friendly_id (5.1.0)
activerecord (>= 4.0.0)
fugit (1.3.1)
fugit (1.5.2)
et-orbi (~> 1.1, >= 1.1.8)
raabro (~> 1.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
raabro (~> 1.4)
globalid (1.0.0)
activesupport (>= 5.0)
hashdiff (1.0.1)
hashery (2.1.2)
hashie (4.1.0)
@ -160,13 +164,13 @@ GEM
httparty (0.20.0)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
i18n (1.8.10)
i18n (1.10.0)
concurrent-ruby (~> 1.0)
icalendar (2.5.3)
ice_cube (~> 0.16)
ice_cube (0.16.3)
ice_nine (0.11.2)
image_processing (1.12.1)
image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
jaro_winkler (1.5.4)
@ -193,12 +197,12 @@ GEM
listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
loofah (2.9.1)
loofah (2.14.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (1.0.1)
marcel (1.0.2)
message_format (0.0.6)
twitter_cldr (~> 5.0)
method_source (1.0.0)
@ -209,9 +213,9 @@ GEM
nokogiri (~> 1)
rake
mini_magick (4.10.1)
mini_mime (1.1.0)
mini_portile2 (2.6.1)
minitest (5.14.4)
mini_mime (1.1.2)
mini_portile2 (2.8.0)
minitest (5.15.0)
minitest-reporters (1.4.2)
ansi
builder
@ -222,8 +226,8 @@ GEM
multi_xml (0.6.0)
multipart-post (2.1.1)
nio4r (2.5.8)
nokogiri (1.12.5)
mini_portile2 (~> 2.6.1)
nokogiri (1.13.3)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
notify_with (0.0.2)
jbuilder (~> 2.0)
@ -269,35 +273,35 @@ GEM
prawn-table (0.2.2)
prawn (>= 1.3.0, < 3.0.0)
public_suffix (4.0.6)
puma (4.3.9)
puma (4.3.11)
nio4r (~> 2.0)
pundit (2.1.0)
activesupport (>= 3.0.0)
raabro (1.1.6)
racc (1.5.2)
raabro (1.4.0)
racc (1.6.0)
rack (2.2.3)
rack-proxy (0.6.5)
rack-proxy (0.7.2)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
railroady (1.5.3)
rails (5.2.6)
actioncable (= 5.2.6)
actionmailer (= 5.2.6)
actionpack (= 5.2.6)
actionview (= 5.2.6)
activejob (= 5.2.6)
activemodel (= 5.2.6)
activerecord (= 5.2.6)
activestorage (= 5.2.6)
activesupport (= 5.2.6)
rails (5.2.6.3)
actioncable (= 5.2.6.3)
actionmailer (= 5.2.6.3)
actionpack (= 5.2.6.3)
actionview (= 5.2.6.3)
activejob (= 5.2.6.3)
activemodel (= 5.2.6.3)
activerecord (= 5.2.6.3)
activestorage (= 5.2.6.3)
activesupport (= 5.2.6.3)
bundler (>= 1.3.0)
railties (= 5.2.6)
railties (= 5.2.6.3)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
rails-html-sanitizer (1.4.2)
loofah (~> 2.3)
rails-observers (0.1.5)
activemodel (>= 4.0)
@ -306,14 +310,14 @@ GEM
rails_stdout_logging
rails_serve_static_assets (0.0.5)
rails_stdout_logging (0.0.5)
railties (5.2.6)
actionpack (= 5.2.6)
activesupport (= 5.2.6)
railties (5.2.6.3)
actionpack (= 5.2.6.3)
activesupport (= 5.2.6.3)
method_source
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
rake (13.0.3)
rake (13.0.6)
rb-fsevent (0.10.3)
rb-inotify (0.10.1)
ffi (~> 1.0)
@ -321,7 +325,7 @@ GEM
recurrence (1.3.0)
activesupport
i18n
redis (4.4.0)
redis (4.6.0)
repost (0.3.2)
responders (2.4.1)
actionpack (>= 4.2.0, < 6.0)
@ -337,31 +341,43 @@ GEM
unicode-display_width (~> 1.4.0)
ruby-progressbar (1.10.1)
ruby-rc4 (0.1.5)
ruby-vips (2.0.17)
ffi (~> 1.9)
ruby-vips (2.1.4)
ffi (~> 1.12)
rubyXL (3.4.14)
nokogiri (>= 1.10.8)
rubyzip (>= 1.3.0)
rubyzip (2.3.0)
rufus-scheduler (3.8.1)
fugit (~> 1.1, >= 1.1.6)
safe_yaml (1.0.5)
sassc (2.4.0)
ffi (~> 1.9)
seed_dump (3.3.1)
activerecord (>= 4)
activesupport (>= 4)
semantic_range (2.3.0)
semantic_range (3.0.0)
sha3 (1.0.1)
sidekiq (6.2.1)
shakapacker (6.2.0)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
sidekiq (6.4.1)
connection_pool (>= 2.2.2)
rack (~> 2.0)
redis (>= 4.2.0)
sidekiq-cron (1.1.0)
fugit (~> 1.1)
sidekiq (>= 4.2.1)
sidekiq-unique-jobs (6.0.22)
sidekiq-scheduler (3.1.1)
e2mmap
redis (>= 3, < 5)
rufus-scheduler (~> 3.2)
sidekiq (>= 3)
thwait
tilt (>= 1.4.0)
sidekiq-unique-jobs (7.1.15)
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
concurrent-ruby (~> 1.0, >= 1.0.5)
sidekiq (>= 4.0, < 7.0)
thor (~> 0)
sidekiq (>= 5.0, < 8.0)
thor (>= 0.20, < 3.0)
simplecov (0.19.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
@ -371,12 +387,12 @@ GEM
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (4.0.2)
sprockets (4.0.3)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.2)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets-rails (3.4.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
ssrf_filter (1.0.7)
stripe (5.29.0)
@ -387,6 +403,9 @@ GEM
tins (~> 1.0)
thor (0.20.3)
thread_safe (0.3.6)
thwait (0.2.0)
e2mmap
tilt (2.0.10)
tins (1.25.0)
sync
ttfunk (1.5.1)
@ -417,12 +436,7 @@ GEM
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webpacker (5.2.1)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
websocket-driver (0.7.3)
websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
@ -475,7 +489,7 @@ DEPENDENCIES
pg_search
prawn
prawn-table
puma (= 4.3.9)
puma (= 4.3.11)
pundit
railroady
rails (~> 5.2.4)
@ -492,9 +506,10 @@ DEPENDENCIES
sassc
seed_dump
sha3
shakapacker (= 6.2.0)
sidekiq (>= 6.0.7)
sidekiq-cron
sidekiq-unique-jobs (~> 6.0.22)
sidekiq-scheduler
sidekiq-unique-jobs (~> 7.1.15)
spring
spring-watcher-listen (~> 2.0.0)
stripe (= 5.29.0)
@ -503,7 +518,6 @@ DEPENDENCIES
vcr (= 6.0.0)
web-console (>= 3.3.0)
webmock
webpacker (~> 5.x)
BUNDLED WITH
2.2.21

View File

@ -1,4 +1,3 @@
web: bundle exec rails server puma -p $PORT
worker: bundle exec sidekiq -C ./config/sidekiq.yml
wp-client: bin/webpack-dev-server
wp-server: SERVER_BUNDLE_ONLY=yes bin/webpack --watch
webpack: bin/webpacker-dev-server

View File

@ -83,7 +83,7 @@ class API::AuthProvidersController < API::ApiController
params.require(:auth_provider)
.permit(:name, :providable_type,
providable_attributes: [:id, :base_url, :token_endpoint, :authorization_endpoint, :logout_endpoint,
:profile_url, :client_id, :client_secret,
:profile_url, :client_id, :client_secret, :scopes,
o_auth2_mappings_attributes: [:id, :local_model, :local_field, :api_field,
:api_endpoint, :api_data_type, :_destroy,
transformation: [:type, :format, :true_value,

View File

@ -4,7 +4,7 @@ import 'regenerator-runtime/runtime';
import 'jquery';
import {} from 'jquery-ujs';
import 'bootstrap-sass';
import '../src/javascript/lib/polyfill';
import 'src/javascript/lib/polyfill';
import 'angular';
<% unless Rails.application.secrets.angular_locale == 'en-us' %>
import 'angular-i18n/angular-locale_<%= Rails.application.secrets.angular_locale %>.js';
@ -31,16 +31,15 @@ import 'ngUpload';
import 'jasny-bootstrap/js/fileinput';
import 'holderjs';
import 'AngularDevise';
import '../src/javascript/lib/devise-modal';
import 'src/javascript/lib/devise-modal';
import 'angular-growl-v2';
import 'angular-xeditable';
import 'checklist-model/checklist-model';
import 'angular-unsavedchanges/lib/unsavedChanges';
import 'angular-loading-bar/src/loading-bar';
import 'angular-scroll/angular-scroll';
import 'angular-google-analytics/dist/angular-google-analytics';
import '../src/javascript/lib/dirDisqus';
import '../src/javascript/lib/humanize';
import 'src/javascript/lib/dirDisqus';
import 'src/javascript/lib/humanize';
import 'underscore/underscore';
import 'elasticsearch-browser/elasticsearch.angular';
import 'd3/d3';
@ -56,7 +55,7 @@ import 'summernote';
import 'summernote/lang/summernote-<%= Rails.application.secrets.summernote_locale %>.js';
<% end %>
import 'angular-summernote/dist/angular-summernote';
import '../src/javascript/lib/summernote-ext-nugget';
import 'src/javascript/lib/summernote-ext-nugget';
import '@claviska/jquery-minicolors/jquery.minicolors.js';
import 'angular-minicolors/angular-minicolors.js';
import 'angular-translate/dist/angular-translate';
@ -80,18 +79,18 @@ import 'angular-ui-tour/app/angular-ui-tour';
import '@fortawesome/fontawesome-free';
import '@fortawesome/fontawesome-free/js/v4-shims';
require('../src/javascript/app.js');
require('../src/javascript/router.js');
require('../src/javascript/plugins.js.erb');
require('src/javascript/app.js');
require('src/javascript/router.js');
require('src/javascript/plugins.js.erb');
function importAll (r) { r.keys().forEach(r); }
importAll(require.context('../src/javascript/components/', true, /.*/));
importAll(require.context('../src/javascript/controllers/', true, /.*/));
importAll(require.context('../src/javascript/services/', true, /.*/));
importAll(require.context('../src/javascript/directives/', true, /.*/));
importAll(require.context('../src/javascript/filters/', true, /.*/));
importAll(require.context('../src/javascript/typings/', true, /.*/));
importAll(require.context('src/javascript/components/', true, /.*/));
importAll(require.context('src/javascript/controllers/', true, /.*/));
importAll(require.context('src/javascript/services/', true, /.*/));
importAll(require.context('src/javascript/directives/', true, /.*/));
importAll(require.context('src/javascript/filters/', true, /.*/));
importAll(require.context('src/javascript/typings/', true, /.*/));
importAll(require.context('../images', true));
importAll(require.context('../templates', true));
importAll(require.context('images', true));
importAll(require.context('templates', true));

View File

@ -15,4 +15,4 @@
@import '~angular-aside/dist/css/angular-aside';
@import '~codemirror/lib/codemirror';
@import '../src/stylesheets/application.scss';
@import 'src/stylesheets/application.scss';

View File

@ -1,2 +0,0 @@
@import '../src/stylesheets/app.printer';

View File

@ -0,0 +1,2 @@
@import 'src/stylesheets/app.printer';

View File

@ -17,22 +17,17 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
'ngUpload', 'duScroll', 'application.filters', 'application.services', 'application.directives',
'frapontillo.bootstrap-switch', 'application.controllers', 'application.router', 'application.components',
'ui.select', 'ui.calendar', 'angularMoment', 'Devise', 'angular-growl', 'xeditable',
'checklist-model', 'unsavedChanges', 'angular-loading-bar', 'ngTouch', 'angular-google-analytics',
'checklist-model', 'unsavedChanges', 'angular-loading-bar', 'ngTouch',
'angularUtils.directives.dirDisqus', 'summernote', 'elasticsearch', 'angular-medium-editor', 'naif.base64',
'minicolors', 'pascalprecht.translate', 'ngFitText', 'ngAside', 'ngCapsLock', 'vcRecaptcha', 'ui.codemirror',
'bm.uiTour'])
.config(['$httpProvider', 'AuthProvider', 'growlProvider', 'unsavedWarningsConfigProvider', 'AnalyticsProvider', 'uibDatepickerPopupConfig', '$provide', '$translateProvider', 'TourConfigProvider',
function ($httpProvider, AuthProvider, growlProvider, unsavedWarningsConfigProvider, AnalyticsProvider, uibDatepickerPopupConfig, $provide, $translateProvider, TourConfigProvider) {
.config(['$httpProvider', 'AuthProvider', 'growlProvider', 'unsavedWarningsConfigProvider', 'uibDatepickerPopupConfig', '$provide', '$translateProvider', 'TourConfigProvider', '$sceDelegateProvider',
function ($httpProvider, AuthProvider, growlProvider, unsavedWarningsConfigProvider, uibDatepickerPopupConfig, $provide, $translateProvider, TourConfigProvider, $sceDelegateProvider) {
// Google analytics
// first we check the user acceptance
const cookiesConsent = document.cookie.replace(/(?:(?:^|.*;\s*)fab-manager-cookies-consent\s*=\s*([^;]*).*$)|^.*$/, '$1');
if (cookiesConsent === 'accept') {
AnalyticsProvider.setAccount(Fablab.trackingId);
// track all routes (or not)
AnalyticsProvider.trackPages(true);
AnalyticsProvider.setDomainName(Fablab.baseHostUrl);
AnalyticsProvider.useAnalytics(true);
AnalyticsProvider.setPageEvent('$stateChangeSuccess');
GTM.enableAnalytics(Fablab.trackingId);
} else {
// if the cookies were not explicitly accepted, delete them
document.cookie = '_ga=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
@ -65,8 +60,10 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
$translateProvider.preferredLanguage(Fablab.locale);
// End the tour when the user clicks the forward or back buttons of the browser
TourConfigProvider.enableNavigationInterceptors();
}]).run(['$rootScope', '$log', 'Auth', 'amMoment', '$state', 'editableOptions', 'Analytics',
function ($rootScope, $log, Auth, amMoment, $state, editableOptions, Analytics) {
$sceDelegateProvider.resourceUrlWhitelist(['self']);
}]).run(['$rootScope', '$transitions', '$log', 'Auth', 'amMoment', '$state', 'editableOptions',
function ($rootScope, $transitions, $log, Auth, amMoment, $state, editableOptions) {
// Angular-moment (date-time manipulations library)
amMoment.changeLocale(Fablab.moment_locale);
@ -75,9 +72,12 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
// Alter the UI-Router's $state, registering into some information concerning the previous $state.
// This is used to allow the user to navigate to the previous state
$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
$state.prevState = fromState;
$state.prevParams = fromParams;
$transitions.onSuccess({ }, function (trans) {
$state.prevState = trans.$from().name;
$state.prevParams = trans.$from().params;
const path = trans.router.stateService.href(trans.$to(), {}, { absolute: true });
GTM.trackPage(path, trans.$to().name);
});
// Global function to allow the user to navigate to the previous screen (ie. $state).
@ -85,7 +85,7 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
$rootScope.backPrevLocation = function (event) {
event.preventDefault();
event.stopPropagation();
if ($state.prevState.name === '') {
if ($state.prevState === '') {
$state.prevState = 'app.public.home';
}
$state.go($state.prevState, $state.prevParams);
@ -112,9 +112,9 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
// Prevent the usage of the application for members with incomplete profiles: they will be redirected to
// the 'profile completion' page. This is especially useful for user's accounts imported through SSO.
$rootScope.$on('$stateChangeStart', function (event, toState) {
$transitions.onStart({}, function (trans) {
Auth.currentUser().then(function (currentUser) {
if (currentUser.need_completion && toState.name !== 'app.logged.profileCompletion') {
if (currentUser.need_completion && trans.$to().name !== 'app.logged.profileCompletion') {
$state.go('app.logged.profileCompletion');
}
}).catch(() => {
@ -122,10 +122,6 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
});
});
// This code does nothing but it is here to remember to not remove the Analytics dependency,
// see https://github.com/revolunet/angular-google-analytics#automatic-page-view-tracking
Analytics.pageView();
/**
* This helper method builds and return an array containing every integers between
* the provided start and end.

View File

@ -52,6 +52,8 @@ interface AbstractPaymentModalProps {
modalSize?: ModalSize,
}
declare const GTM: any;
/**
* This component is an abstract modal that must be extended by each payment gateway to include its payment form.
*
@ -156,6 +158,7 @@ export const AbstractPaymentModal: React.FC<AbstractPaymentModalProps> = ({ isOp
*/
const handleFormSuccess = async (result: Invoice|PaymentSchedule): Promise<void> => {
setSubmitState(false);
GTM.trackPurchase(result.id, result.total);
afterSuccess(result);
};

View File

@ -318,8 +318,8 @@ Application.Controllers.controller('NewAuthenticationController', ['$scope', '$s
/**
* Page to edit an already added authentication provider
*/
Application.Controllers.controller('EditAuthenticationController', ['$scope', '$state', '$stateParams', '$rootScope', '$uibModal', 'dialogs', 'growl', 'providerPromise', 'mappingFieldsPromise', 'AuthProvider', '_t',
function ($scope, $state, $stateParams, $rootScope, $uibModal, dialogs, growl, providerPromise, mappingFieldsPromise, AuthProvider, _t) {
Application.Controllers.controller('EditAuthenticationController', ['$scope', '$state', '$rootScope', '$uibModal', 'dialogs', 'growl', 'providerPromise', 'mappingFieldsPromise', 'AuthProvider', '_t',
function ($scope, $state, $rootScope, $uibModal, dialogs, growl, providerPromise, mappingFieldsPromise, AuthProvider, _t) {
// parameters of the currently edited authentication provider
$scope.provider = providerPromise;

View File

@ -619,12 +619,12 @@ Application.Controllers.controller('NewEventController', ['$scope', '$state', 'C
/**
* Controller used in the events edition page
*/
Application.Controllers.controller('EditEventController', ['$scope', '$state', '$stateParams', 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '$uibModal', 'growl', '_t',
function ($scope, $state, $stateParams, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, $uibModal, growl, _t) {
Application.Controllers.controller('EditEventController', ['$scope', '$state', '$transition$', 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '$uibModal', 'growl', '_t',
function ($scope, $state, $transition$, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, $uibModal, growl, _t) {
/* PUBLIC SCOPE */
// API URL where the form will be posted
$scope.actionUrl = `/api/events/${$stateParams.id}`;
$scope.actionUrl = `/api/events/${$transition$.params().id}`;
// Form action on the above URL
$scope.method = 'put';

View File

@ -17,8 +17,8 @@
*/
'use strict';
Application.Controllers.controller('GraphsController', ['$scope', '$state', '$rootScope', 'es', 'Statistics', '_t',
function ($scope, $state, $rootScope, es, Statistics, _t) {
Application.Controllers.controller('GraphsController', ['$scope', '$state', '$rootScope', '$transitions', 'es', 'Statistics', '_t',
function ($scope, $state, $rootScope, $transitions, es, Statistics, _t) {
/* PRIVATE STATIC CONSTANTS */
// height of the HTML/SVG charts elements in pixels
@ -167,8 +167,8 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
// workaround for angular-bootstrap::tabs behavior: on tab deletion, another tab will be selected
// which will cause every tabs to reload, one by one, when the view is closed
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if ((fromState.name === 'app.admin.stats_graphs') && (Object.keys(fromParams).length === 0)) {
$transitions.onStart({ to: 'app.admin.stats_graphs' }, function (trans) {
if (Object.keys(trans.from().params).length === 0) {
return $scope.preventRefresh = true;
}
});

View File

@ -195,6 +195,14 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
name: 'accounting_Space_label',
value: settings.accounting_Space_label
},
packCode: {
name: 'accounting_Pack_code',
value: settings.accounting_Pack_code
},
packLabel: {
name: 'accounting_Pack_label',
value: settings.accounting_Pack_label
},
errorCode: {
name: 'accounting_Error_code',
value: settings.accounting_Error_code

View File

@ -650,12 +650,12 @@ 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', 'settingsPromise',
function ($scope, $state, $stateParams, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, activeProviderPromise, Wallet, settingsPromise) {
Application.Controllers.controller('EditMemberController', ['$scope', '$state', '$transition$', 'Member', 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'activeProviderPromise', 'Wallet', 'settingsPromise',
function ($scope, $state, $transition$, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, activeProviderPromise, Wallet, settingsPromise) {
/* PUBLIC SCOPE */
// API URL where the form will be posted
$scope.actionUrl = `/api/members/${$stateParams.id}`;
$scope.actionUrl = `/api/members/${$transition$.params().id}`;
// Form action on the above URL
$scope.method = 'patch';
@ -922,8 +922,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', 'settingsPromise',
function ($scope, $state, $stateParams, Member, Training, Group, CSRF, settingsPromise) {
Application.Controllers.controller('NewMemberController', ['$scope', '$state', 'Member', 'Training', 'Group', 'CSRF', 'settingsPromise',
function ($scope, $state, Member, Training, Group, CSRF, settingsPromise) {
CSRF.setMetaTags();
/* PUBLIC SCOPE */

View File

@ -224,8 +224,8 @@ Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal',
/**
* Controller used in the plan edition form
*/
Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'plans', 'planPromise', 'machines', 'spaces', 'prices', 'partners', 'CSRF', '$state', '$stateParams', 'growl', '$filter', '_t', 'Plan', 'planCategories',
function ($scope, groups, plans, planPromise, machines, spaces, prices, partners, CSRF, $state, $stateParams, growl, $filter, _t, Plan, planCategories) {
Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'plans', 'planPromise', 'machines', 'spaces', 'prices', 'partners', 'CSRF', '$state', '$transition$', 'growl', '$filter', '_t', 'Plan', 'planCategories',
function ($scope, groups, plans, planPromise, machines, spaces, prices, partners, CSRF, $state, $transition$, growl, $filter, _t, Plan, planCategories) {
/* PUBLIC SCOPE */
// List of spaces
@ -254,7 +254,7 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p
if ($scope.plan.disabled) { $scope.plan.disabled = 'true'; }
// API URL where the form will be posted
$scope.actionUrl = `/api/plans/${$stateParams.id}`;
$scope.actionUrl = `/api/plans/${$transition$.params().id}`;
// HTTP method for the rest API
$scope.method = 'PATCH';

View File

@ -15,8 +15,8 @@
*/
'use strict';
Application.Controllers.controller('StatisticsController', ['$scope', '$state', '$rootScope', '$uibModal', 'es', 'Member', '_t', 'membersPromise', 'statisticsPromise', 'uiTourService', 'settingsPromise',
function ($scope, $state, $rootScope, $uibModal, es, Member, _t, membersPromise, statisticsPromise, uiTourService, settingsPromise) {
Application.Controllers.controller('StatisticsController', ['$scope', '$state', '$transitions', '$rootScope', '$uibModal', 'es', 'Member', '_t', 'membersPromise', 'statisticsPromise', 'uiTourService', 'settingsPromise',
function ($scope, $state, $transitions, $rootScope, $uibModal, es, Member, _t, membersPromise, statisticsPromise, uiTourService, settingsPromise) {
/* PRIVATE STATIC CONSTANTS */
// search window size
@ -407,8 +407,8 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
const initialize = function () {
// workaround for angular-bootstrap::tabs behavior: on tab deletion, another tab will be selected
// which will cause every tabs to reload, one by one, when the view is closed
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if ((fromState.name === 'app.admin.statistics') && (Object.keys(fromParams).length === 0)) {
$transitions.onStart({ to: 'app.admin.statistics' }, function (trans) {
if (Object.keys(trans.from().params).length === 0) {
return $scope.preventRefresh = true;
}
});

View File

@ -114,15 +114,15 @@ Application.Controllers.controller('NewTrainingController', ['$scope', '$state',
/**
* Controller used in the training edition page (admin)
*/
Application.Controllers.controller('EditTrainingController', ['$scope', '$state', '$stateParams', 'trainingPromise', 'machinesPromise', 'CSRF',
function ($scope, $state, $stateParams, trainingPromise, machinesPromise, CSRF) {
Application.Controllers.controller('EditTrainingController', ['$scope', '$state', '$transition$', 'trainingPromise', 'machinesPromise', 'CSRF',
function ($scope, $state, $transition$, trainingPromise, machinesPromise, CSRF) {
/* PUBLIC SCOPE */
// Form action on the following URL
$scope.method = 'patch';
// API URL where the form will be posted
$scope.actionUrl = `/api/trainings/${$stateParams.id}`;
$scope.actionUrl = `/api/trainings/${$transition$.params().id}`;
// Details of the training to edit (id in URL)
$scope.training = trainingPromise;

View File

@ -12,8 +12,8 @@
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
Application.Controllers.controller('ApplicationController', ['$rootScope', '$scope', '$window', '$locale', '$timeout', 'Session', 'AuthService', 'Auth', '$uibModal', '$state', 'growl', 'Notification', '$interval', 'Setting', '_t', 'Version', 'Help',
function ($rootScope, $scope, $window, $locale, $timeout, Session, AuthService, Auth, $uibModal, $state, growl, Notification, $interval, Setting, _t, Version, Help) {
Application.Controllers.controller('ApplicationController', ['$rootScope', '$scope', '$transitions', '$window', '$locale', '$timeout', 'Session', 'AuthService', 'Auth', '$uibModal', '$state', 'growl', 'Notification', '$interval', 'Setting', '_t', 'Version', 'Help',
function ($rootScope, $scope, $transitions, $window, $locale, $timeout, Session, AuthService, Auth, $uibModal, $state, growl, Notification, $interval, Setting, _t, Version, Help) {
/* PRIVATE STATIC CONSTANTS */
// User's notifications will get refreshed every 30s
@ -325,19 +325,18 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
$rootScope.toCheckNotifications = false;
});
// bind to the $stateChangeStart event (AngularJS/UI-Router)
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
if (!toState.data) { return; }
// bind to the $transitions.onStart event (UI-Router)
$transitions.onStart({}, function (trans) {
if (!trans.$to().data) { return; }
const { authorizedRoles } = toState.data;
const { authorizedRoles } = trans.$to().data;
if (!AuthService.isAuthorized(authorizedRoles)) {
event.preventDefault();
if (AuthService.isAuthenticated()) {
// user is not allowed
console.error('[ApplicationController::initialize] user is not allowed');
} else {
// user is not logged in
openLoginModal(toState, toParams);
openLoginModal(trans.$to().name, trans.$to().params);
}
}
});
@ -462,6 +461,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
// what to do when the modal is closed
// authentication succeeded, set the session, gather the notifications and redirect
GTM.trackLogin();
$scope.setCurrentUser(user);
if ((toState !== null) && (toParams !== null)) {

View File

@ -13,28 +13,20 @@ Application.Controllers.controller('CookiesController', ['$scope', '$cookies', '
// link pointed by "learn more"
$scope.learnMoreUrl = 'https://www.cookiesandyou.com/';
// current user wallet
// add a cookie to the browser, saving the user choice to refuse cookies
$scope.declineCookies = function () {
const expires = moment().add(13, 'months').toDate();
$cookies.put('fab-manager-cookies-consent', 'decline', { expires });
readCookie();
};
// current wallet transactions
// add a cookie to the browser, saving the user choice to accept cookies.
// Then enable the analytics
$scope.acceptCookies = function () {
const expires = moment().add(13, 'months').toDate();
$cookies.put('fab-manager-cookies-consent', 'accept', { expires });
readCookie();
// enable tracking using code provided by google analytics
/* eslint-disable */
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', Fablab.trackingId, 'auto');
ga('send', 'pageview');
/* eslint-enable */
GTM.enableAnalytics(Fablab.trackingId);
};
/* PRIVATE SCOPE */
@ -44,7 +36,7 @@ Application.Controllers.controller('CookiesController', ['$scope', '$cookies', '
*/
const initialize = function () {
readCookie();
// if the privacy policy was defined, redirect the user to it
// if the privacy policy was defined, redirect the user to it when clicking on "read more"
Setting.get({ name: 'privacy_body' }, data => {
if (data.setting.value) {
$scope.learnMoreUrl = '#!/privacy-policy';

View File

@ -126,8 +126,8 @@ Application.Controllers.controller('EventsController', ['$scope', '$state', 'Eve
}
]);
Application.Controllers.controller('ShowEventController', ['$scope', '$state', '$stateParams', '$rootScope', 'Event', '$uibModal', 'Member', 'Reservation', 'Price', 'CustomAsset', 'Slot', 'eventPromise', 'growl', '_t', 'Wallet', 'AuthService', 'helpers', 'dialogs', 'priceCategoriesPromise', 'settingsPromise', 'LocalPayment',
function ($scope, $state, $stateParams, $rootScope, Event, $uibModal, Member, Reservation, Price, CustomAsset, Slot, eventPromise, growl, _t, Wallet, AuthService, helpers, dialogs, priceCategoriesPromise, settingsPromise, LocalPayment) {
Application.Controllers.controller('ShowEventController', ['$scope', '$state', '$rootScope', 'Event', '$uibModal', 'Member', 'Reservation', 'Price', 'CustomAsset', 'Slot', 'eventPromise', 'growl', '_t', 'Wallet', 'AuthService', 'helpers', 'dialogs', 'priceCategoriesPromise', 'settingsPromise', 'LocalPayment',
function ($scope, $state,$rootScope, Event, $uibModal, Member, Reservation, Price, CustomAsset, Slot, eventPromise, growl, _t, Wallet, AuthService, helpers, dialogs, priceCategoriesPromise, settingsPromise, LocalPayment) {
/* PUBLIC SCOPE */
// reservations for the currently shown event

View File

@ -1,11 +1,11 @@
'use strict';
Application.Controllers.controller('HeaderController', ['$scope', '$rootScope', '$state', 'settingsPromise',
function ($scope, $rootScope, $state, settingsPromise) {
Application.Controllers.controller('HeaderController', ['$scope', '$transitions', '$state', 'settingsPromise',
function ($scope, $transitions, $state, settingsPromise) {
$scope.aboutPage = ($state.current.name === 'app.public.about');
$rootScope.$on('$stateChangeStart', function (event, toState) {
$scope.aboutPage = (toState.name === 'app.public.about');
$transitions.onStart({}, function (trans) {
$scope.aboutPage = (trans.$to().name === 'app.public.about');
});
/**

View File

@ -1,7 +1,7 @@
'use strict';
Application.Controllers.controller('HomeController', ['$scope', '$stateParams', '$translatePartialLoader', 'AuthService', 'settingsPromise', 'Member', 'uiTourService', '_t',
function ($scope, $stateParams, $translatePartialLoader, AuthService, settingsPromise, Member, uiTourService, _t) {
Application.Controllers.controller('HomeController', ['$scope', '$transition$', '$translatePartialLoader', 'AuthService', 'settingsPromise', 'Member', 'uiTourService', '_t',
function ($scope, $transition$, $translatePartialLoader, AuthService, settingsPromise, Member, uiTourService, _t) {
/* PUBLIC SCOPE */
// Home page HTML content
@ -38,8 +38,8 @@ Application.Controllers.controller('HomeController', ['$scope', '$stateParams',
const initialize = function () {
// if we receive a token to reset the password as GET parameter, trigger the
// changePassword modal from the parent controller
if ($stateParams.reset_password_token) {
return $scope.$parent.editPassword($stateParams.reset_password_token);
if ($transition$.params().reset_password_token) {
return $scope.$parent.editPassword($transition$.params().reset_password_token);
}
// We set the home page content, with the directives replacing the placeholders

View File

@ -245,12 +245,12 @@ Application.Controllers.controller('NewMachineController', ['$scope', '$state',
/**
* Controller used in the machine edition page (admin)
*/
Application.Controllers.controller('EditMachineController', ['$scope', '$state', '$stateParams', 'machinePromise', 'CSRF',
function ($scope, $state, $stateParams, machinePromise, CSRF) {
Application.Controllers.controller('EditMachineController', ['$scope', '$state', '$transition$', 'machinePromise', 'CSRF',
function ($scope, $state, $transition$, machinePromise, CSRF) {
/* PUBLIC SCOPE */
// API URL where the form will be posted
$scope.actionUrl = `/api/machines/${$stateParams.id}`;
$scope.actionUrl = `/api/machines/${$transition$.params().id}`;
// Form action on the above URL
$scope.method = 'put';
@ -278,8 +278,8 @@ Application.Controllers.controller('EditMachineController', ['$scope', '$state',
/**
* Controller used in the machine details page (public)
*/
Application.Controllers.controller('ShowMachineController', ['$scope', '$state', '$uibModal', '$stateParams', '_t', 'Machine', 'growl', 'machinePromise', 'dialogs',
function ($scope, $state, $uibModal, $stateParams, _t, Machine, growl, machinePromise, dialogs) {
Application.Controllers.controller('ShowMachineController', ['$scope', '$state', '$uibModal', '_t', 'Machine', 'growl', 'machinePromise', 'dialogs',
function ($scope, $state, $uibModal, _t, Machine, growl, machinePromise, dialogs) {
// Retrieve the details for the machine id in the URL, if an error occurs redirect the user to the machines list
$scope.machine = machinePromise;
@ -357,8 +357,8 @@ Application.Controllers.controller('ShowMachineController', ['$scope', '$state',
* This controller workflow is pretty similar to the trainings reservation controller.
*/
Application.Controllers.controller('ReserveMachineController', ['$scope', '$stateParams', '_t', 'moment', 'Auth', '$timeout', 'Member', 'Availability', 'plansPromise', 'groupsPromise', 'machinePromise', 'settingsPromise', 'uiCalendarConfig', 'CalendarConfig', 'Reservation', 'growl',
function ($scope, $stateParams, _t, moment, Auth, $timeout, Member, Availability, plansPromise, groupsPromise, machinePromise, settingsPromise, uiCalendarConfig, CalendarConfig, Reservation, growl) {
Application.Controllers.controller('ReserveMachineController', ['$scope', '$transition$', '_t', 'moment', 'Auth', '$timeout', 'Member', 'Availability', 'plansPromise', 'groupsPromise', 'machinePromise', 'settingsPromise', 'uiCalendarConfig', 'CalendarConfig', 'Reservation', 'growl',
function ($scope, $transition$, _t, moment, Auth, $timeout, Member, Availability, plansPromise, groupsPromise, machinePromise, settingsPromise, uiCalendarConfig, CalendarConfig, Reservation, growl) {
/* PRIVATE STATIC CONSTANTS */
// Slot free to be booked
@ -660,7 +660,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
const initialize = function () {
$scope.eventSources.push({
events: function (start, end, timezone, callback) {
Availability.machine({ machineId: $stateParams.id }, function (availabilities) {
Availability.machine({ machineId: $transition$.params().id }, function (availabilities) {
callback(availabilities);
});
},

View File

@ -480,12 +480,12 @@ Application.Controllers.controller('NewProjectController', ['$rootScope', '$scop
/**
* Controller used in the project edition page
*/
Application.Controllers.controller('EditProjectController', ['$rootScope', '$scope', '$state', '$stateParams', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'projectPromise', 'Diacritics', 'dialogs', 'allowedExtensions', '_t',
function ($rootScope, $scope, $state, $stateParams, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, projectPromise, Diacritics, dialogs, allowedExtensions, _t) {
Application.Controllers.controller('EditProjectController', ['$rootScope', '$scope', '$state', '$transition$', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'projectPromise', 'Diacritics', 'dialogs', 'allowedExtensions', '_t',
function ($rootScope, $scope, $state, $transition$, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, projectPromise, Diacritics, dialogs, allowedExtensions, _t) {
/* PUBLIC SCOPE */
// API URL where the form will be posted
$scope.actionUrl = `/api/projects/${$stateParams.id}`;
$scope.actionUrl = `/api/projects/${$transition$.params().id}`;
// Form action on the above URL
$scope.method = 'put';

View File

@ -234,12 +234,12 @@ Application.Controllers.controller('NewSpaceController', ['$scope', '$state', 'C
/**
* Controller used in the space edition page (admin)
*/
Application.Controllers.controller('EditSpaceController', ['$scope', '$state', '$stateParams', 'spacePromise', 'CSRF',
function ($scope, $state, $stateParams, spacePromise, CSRF) {
Application.Controllers.controller('EditSpaceController', ['$scope', '$state', '$transition$', 'spacePromise', 'CSRF',
function ($scope, $state, $transition$, spacePromise, CSRF) {
CSRF.setMetaTags();
// API URL where the form will be posted
$scope.actionUrl = `/api/spaces/${$stateParams.id}`;
$scope.actionUrl = `/api/spaces/${$transition$.params().id}`;
// Form action on the above URL
$scope.method = 'put';
@ -307,8 +307,8 @@ Application.Controllers.controller('ShowSpaceController', ['$scope', '$state', '
* per slots.
*/
Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateParams', 'Auth', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'spacePromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Reservation',
function ($scope, $stateParams, Auth, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, spacePromise, _t, uiCalendarConfig, CalendarConfig, Reservation) {
Application.Controllers.controller('ReserveSpaceController', ['$scope', '$transition$', 'Auth', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'spacePromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Reservation',
function ($scope, $transition$, Auth, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, spacePromise, _t, uiCalendarConfig, CalendarConfig, Reservation) {
/* PRIVATE STATIC CONSTANTS */
// Color of the selected event backgound
@ -601,7 +601,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
// in the router because this allows to refetchEvents from fullCalendar API.
$scope.eventSources.push({
events: function (start, end, timezone, callback) {
Availability.spaces({ spaceId: $stateParams.id }, function (availabilities) {
Availability.spaces({ spaceId: $transition$.params().id }, function (availabilities) {
callback(availabilities);
});
},

View File

@ -91,8 +91,8 @@ Application.Controllers.controller('ShowTrainingController', ['$scope', '$state'
* training can be reserved during the reservation process (the shopping cart may contains only one training and a subscription).
*/
Application.Controllers.controller('ReserveTrainingController', ['$scope', '$stateParams', 'Auth', 'AuthService', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Reservation',
function ($scope, $stateParams, Auth, AuthService, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, trainingPromise, _t, uiCalendarConfig, CalendarConfig, Reservation) {
Application.Controllers.controller('ReserveTrainingController', ['$scope', '$transition$', 'Auth', 'AuthService', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Reservation',
function ($scope, $transition$, Auth, AuthService, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, trainingPromise, _t, uiCalendarConfig, CalendarConfig, Reservation) {
/* PRIVATE STATIC CONSTANTS */
// Color of the selected event backgound
@ -144,7 +144,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
$scope.training = trainingPromise;
// 'all' OR training's slug
$scope.mode = $stateParams.id;
$scope.mode = $transition$.params().id;
// fullCalendar (v2) configuration
$scope.calendarConfig = CalendarConfig({
@ -279,7 +279,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
if ($scope.ctrl.member) {
Member.get({ id: $scope.ctrl.member.id }, function (member) {
$scope.ctrl.member = member;
const id = $stateParams.id === 'all' ? $stateParams.id : $scope.training.id;
const id = $transition$.params().id === 'all' ? $transition$.params().id : $scope.training.id;
return Availability.trainings({ trainingId: id, member_id: $scope.ctrl.member.id }, function (trainings) {
uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');
return $scope.eventSources.splice(0, 1, {
@ -391,7 +391,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
// in the router because this allows to refetchEvents from fullCalendar API.
$scope.eventSources.push({
events: function (start, end, timezone, callback) {
Availability.trainings({ trainingId: $stateParams.id }, function (availabilities) {
Availability.trainings({ trainingId: $transition$.params().id }, function (availabilities) {
callback(availabilities);
});
},
@ -408,7 +408,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
*/
const calendarEventClickCb = function (event, jsEvent, view) {
$scope.selectedEvent = event;
if ($stateParams.id === 'all') {
if ($transition$.params().id === 'all') {
$scope.training = event.training;
}
return $scope.selectionTime = new Date();

View File

@ -1,8 +1,3 @@
/* eslint-disable
no-undef,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
@ -135,7 +130,7 @@ Application.Filters.filter('projectsCollabored', [function () {
};
}]);
// depend on humanize.js lib in /vendor
// depend on app/frontend/src/javascript/lib/humanize.js
Application.Filters.filter('humanize', [function () {
return (element, param) => Humanize.truncate(element, param, null);
}]);

View File

@ -0,0 +1,43 @@
// this script loads the google tag manager, used by Google Analytics V4
(function () {
const GTM = {};
window.dataLayer = window.dataLayer || [];
function gtag () { window.dataLayer.push(arguments); }
GTM.enableAnalytics = function (trackingId) {
gtag('js', new Date());
gtag('config', trackingId);
const node = document.createElement('script');
const firstScript = document.getElementsByTagName('script')[0];
node.async = true;
node.src = `//www.googletagmanager.com/gtag/js?id=${trackingId}`;
firstScript.parentNode.insertBefore(node, firstScript);
};
GTM.trackPage = function (url, title) {
gtag('event', 'page_view', {
page_location: url,
page_title: title
});
};
GTM.trackLogin = function () {
gtag('event', 'login');
};
GTM.trackPurchase = function (transactionId, value) {
gtag('event', 'purchase', {
transaction_id: transactionId,
value: value,
currency: Fablab.intl_currency
});
};
this.GTM = GTM;
if (typeof module !== 'undefined' && module !== null) {
module.exports = GTM;
}
}).call(this);

View File

@ -1,14 +1,3 @@
/* eslint-disable
no-return-assign,
no-undef,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
angular.module('application.router', ['ui.router'])
.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function ($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.hashPrefix('!');
@ -243,7 +232,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
memberPromise: ['$stateParams', 'Member', function ($stateParams, Member) { return Member.get({ id: $stateParams.id }).$promise; }]
memberPromise: ['$transition$', 'Member', function ($transition$, Member) { return Member.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.logged.members', {
@ -297,7 +286,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
projectPromise: ['$stateParams', 'Project', function ($stateParams, Project) { return Project.get({ id: $stateParams.id }).$promise; }],
projectPromise: ['$transition$', 'Project', function ($transition$, Project) { return Project.get({ id: $transition$.params().id }).$promise; }],
shortnamePromise: ['Setting', function (Setting) { return Setting.get({ name: 'disqus_shortname' }).$promise; }]
}
})
@ -310,7 +299,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
projectPromise: ['$stateParams', 'Project', function ($stateParams, Project) { return Project.get({ id: $stateParams.id }).$promise; }],
projectPromise: ['$transition$', 'Project', function ($transition$, Project) { return Project.get({ id: $transition$.params().id }).$promise; }],
allowedExtensions: ['Setting', function (Setting) { return Setting.get({ name: 'allowed_cad_extensions' }).$promise; }]
}
})
@ -347,7 +336,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
machinePromise: ['Machine', '$stateParams', function (Machine, $stateParams) { return Machine.get({ id: $stateParams.id }).$promise; }]
machinePromise: ['Machine', '$transition$', function (Machine, $transition$) { return Machine.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.logged.machines_reserve', {
@ -361,7 +350,7 @@ angular.module('application.router', ['ui.router'])
resolve: {
plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],
groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],
machinePromise: ['Machine', '$stateParams', function (Machine, $stateParams) { return Machine.get({ id: $stateParams.id }).$promise; }],
machinePromise: ['Machine', '$transition$', function (Machine, $transition$) { return Machine.get({ id: $transition$.params().id }).$promise; }],
settingsPromise: ['Setting', function (Setting) {
return Setting.query({
names: "['machine_explications_alert', 'booking_window_start', 'booking_window_end', 'booking_move_enable', " +
@ -380,7 +369,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
machinePromise: ['Machine', '$stateParams', function (Machine, $stateParams) { return Machine.get({ id: $stateParams.id }).$promise; }]
machinePromise: ['Machine', '$transition$', function (Machine, $transition$) { return Machine.get({ id: $transition$.params().id }).$promise; }]
}
})
@ -419,7 +408,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
spacePromise: ['Space', '$stateParams', function (Space, $stateParams) { return Space.get({ id: $stateParams.id }).$promise; }]
spacePromise: ['Space', '$transition$', function (Space, $transition$) { return Space.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.admin.space_edit', {
@ -432,7 +421,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
spacePromise: ['Space', '$stateParams', function (Space, $stateParams) { return Space.get({ id: $stateParams.id }).$promise; }]
spacePromise: ['Space', '$transition$', function (Space, $transition$) { return Space.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.logged.space_reserve', {
@ -445,7 +434,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
spacePromise: ['Space', '$stateParams', function (Space, $stateParams) { return Space.get({ id: $stateParams.id }).$promise; }],
spacePromise: ['Space', '$transition$', function (Space, $transition$) { return Space.get({ id: $transition$.params().id }).$promise; }],
plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],
groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],
settingsPromise: ['Setting', function (Setting) {
@ -482,7 +471,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
trainingPromise: ['Training', '$stateParams', function (Training, $stateParams) { return Training.get({ id: $stateParams.id }).$promise; }]
trainingPromise: ['Training', '$transition$', function (Training, $transition$) { return Training.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.logged.trainings_reserve', {
@ -498,8 +487,8 @@ angular.module('application.router', ['ui.router'])
explicationAlertPromise: ['Setting', function (Setting) { return Setting.get({ name: 'training_explications_alert' }).$promise; }],
plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],
groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],
trainingPromise: ['Training', '$stateParams', function (Training, $stateParams) {
if ($stateParams.id !== 'all') { return Training.get({ id: $stateParams.id }).$promise; }
trainingPromise: ['Training', '$transition$', function (Training, $transition$) {
if ($transition$.params().id !== 'all') { return Training.get({ id: $transition$.params().id }).$promise; }
}],
settingsPromise: ['Setting', function (Setting) {
return Setting.query({
@ -563,7 +552,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
eventPromise: ['Event', '$stateParams', function (Event, $stateParams) { return Event.get({ id: $stateParams.id }).$promise; }],
eventPromise: ['Event', '$transition$', function (Event, $transition$) { return Event.get({ id: $transition$.params().id }).$promise; }],
priceCategoriesPromise: ['PriceCategory', function (PriceCategory) { return PriceCategory.query().$promise; }],
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['booking_move_enable', 'booking_move_delay', 'booking_cancel_enable', 'booking_cancel_delay', 'event_explications_alert', 'online_payment_module']" }).$promise; }]
}
@ -694,7 +683,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
trainingPromise: ['Training', '$stateParams', function (Training, $stateParams) { return Training.get({ id: $stateParams.id }).$promise; }],
trainingPromise: ['Training', '$transition$', function (Training, $transition$) { return Training.get({ id: $transition$.params().id }).$promise; }],
machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }]
}
})
@ -740,7 +729,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
eventPromise: ['Event', '$stateParams', function (Event, $stateParams) { return Event.get({ id: $stateParams.id }).$promise; }],
eventPromise: ['Event', '$transition$', function (Event, $transition$) { return Event.get({ id: $transition$.params().id }).$promise; }],
categoriesPromise: ['Category', function (Category) { return Category.query().$promise; }],
themesPromise: ['EventTheme', function (EventTheme) { return EventTheme.query().$promise; }],
ageRangesPromise: ['AgeRange', function (AgeRange) { return AgeRange.query().$promise; }],
@ -756,8 +745,8 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
eventPromise: ['Event', '$stateParams', function (Event, $stateParams) { return Event.get({ id: $stateParams.id }).$promise; }],
reservationsPromise: ['Reservation', '$stateParams', function (Reservation, $stateParams) { return Reservation.query({ reservable_id: $stateParams.id, reservable_type: 'Event' }).$promise; }]
eventPromise: ['Event', '$transition$', function (Event, $transition$) { return Event.get({ id: $transition$.params().id }).$promise; }],
reservationsPromise: ['Reservation', '$transition$', function (Reservation, $transition$) { return Reservation.query({ reservable_id: $transition$.params().id, reservable_type: 'Event' }).$promise; }]
}
})
@ -820,7 +809,7 @@ angular.module('application.router', ['ui.router'])
spaces: ['Space', function (Space) { return Space.query().$promise; }],
machines: ['Machine', function (Machine) { return Machine.query().$promise; }],
plans: ['Plan', function (Plan) { return Plan.query().$promise; }],
planPromise: ['Plan', '$stateParams', function (Plan, $stateParams) { return Plan.get({ id: $stateParams.id }).$promise; }],
planPromise: ['Plan', '$transition$', function (Plan, $transition$) { return Plan.get({ id: $transition$.params().id }).$promise; }],
planCategories: ['PlanCategory', function (PlanCategory) { return PlanCategory.query().$promise; }]
}
})
@ -854,7 +843,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
couponPromise: ['Coupon', '$stateParams', function (Coupon, $stateParams) { return Coupon.get({ id: $stateParams.id }).$promise; }]
couponPromise: ['Coupon', '$transition$', function (Coupon, $transition$) { return Coupon.get({ id: $transition$.params().id }).$promise; }]
}
})
@ -879,7 +868,8 @@ angular.module('application.router', ['ui.router'])
"'accounting_Machine_code', 'accounting_Machine_label', 'accounting_Training_code', 'accounting_Training_label', " +
"'accounting_Event_code', 'accounting_Event_label', 'accounting_Space_code', 'accounting_Space_label', " +
"'payment_gateway', 'accounting_Error_code', 'accounting_Error_label', 'payment_schedule_prefix', " +
"'feature_tour_display', 'online_payment_module', 'stripe_public_key', 'stripe_currency', 'invoice_prefix']"
"'feature_tour_display', 'online_payment_module', 'stripe_public_key', 'stripe_currency', 'invoice_prefix', " +
"'accounting_Pack_code', 'accounting_Pack_label']"
}).$promise;
}],
stripeSecretKey: ['Setting', function (Setting) { return Setting.isPresent({ name: 'stripe_secret_key' }).$promise; }],
@ -958,7 +948,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
importItem: ['Import', '$stateParams', function (Import, $stateParams) { return Import.get({ id: $stateParams.id }).$promise; }]
importItem: ['Import', '$transition$', function (Import, $transition$) { return Import.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.admin.members_edit', {
@ -970,9 +960,9 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
memberPromise: ['Member', '$stateParams', function (Member, $stateParams) { return Member.get({ id: $stateParams.id }).$promise; }],
memberPromise: ['Member', '$transition$', function (Member, $transition$) { return Member.get({ id: $transition$.params().id }).$promise; }],
activeProviderPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.active().$promise; }],
walletPromise: ['Wallet', '$stateParams', function (Wallet, $stateParams) { return Wallet.getWalletByUser({ user_id: $stateParams.id }).$promise; }],
walletPromise: ['Wallet', '$transition$', function (Wallet, $transition$) { return Wallet.getWalletByUser({ user_id: $transition$.params().id }).$promise; }],
transactionsPromise: ['Wallet', 'walletPromise', function (Wallet, walletPromise) { return Wallet.transactions({ id: walletPromise.id }).$promise; }],
tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }],
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['phone_required', 'address_required']" }).$promise; }]
@ -1027,7 +1017,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
providerPromise: ['AuthProvider', '$stateParams', function (AuthProvider, $stateParams) { return AuthProvider.get({ id: $stateParams.id }).$promise; }],
providerPromise: ['AuthProvider', '$transition$', function (AuthProvider, $transition$) { return AuthProvider.get({ id: $transition$.params().id }).$promise; }],
mappingFieldsPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.mapping_fields().$promise; }]
}
})
@ -1083,7 +1073,7 @@ angular.module('application.router', ['ui.router'])
"'display_name_enable', 'machines_sort_by', 'fab_analytics', 'statistics_module', 'address_required', " +
"'link_name', 'home_content', 'home_css', 'phone_required', 'upcoming_events_shown', 'public_agenda_module'," +
"'renew_pack_threshold', 'pack_only_for_subscription', 'overlapping_categories', 'public_registrations'," +
"'extended_prices_in_same_day']"
"'extended_prices_in_same_day', 'recaptcha_site_key', 'recaptcha_secret_key']"
}).$promise;
}],
privacyDraftsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'privacy_draft', history: true }).$promise; }],

View File

@ -1,3 +1,5 @@
@use "sass:math";
// This is the default html and body font-size for the base rem value.
$rem-base: 10px !default;
@ -20,12 +22,12 @@ $modules: () !default;
// STRIP UNIT
// It strips the unit of measure and returns it
@function strip-unit($num) {
@return $num / ($num * 0 + 1);
@return math.div($num, $num * 0 + 1);
}
// CONVERT TO REM
@function convert-to-rem($value, $base-value: $rem-base) {
$value: strip-unit($value) / strip-unit($base-value) * 1rem;
$value: math.div(strip-unit($value), strip-unit($base-value)) * 1rem;
@if $value == 0rem {
$value: 0;

View File

@ -1,3 +1,5 @@
@use 'sass:math';
/*layout*/
.header,
.footer {
@ -286,8 +288,8 @@ body.container {
height: $header-md-height;
.navbar-form {
margin-top: floor(($header-md-height - 30) / 2);
margin-bottom: floor(($header-md-height - 30) / 2);
margin-top: floor(math.div($header-md-height - 30, 2));
margin-bottom: floor(math.div($header-md-height - 30, 2));
}
}
@ -689,7 +691,7 @@ body.container {
cursor: pointer;
& .Event-picture {opacity: 0.7;}
}
&-picture {
height: 250px;
background-color: #fff;
@ -701,7 +703,7 @@ body.container {
object-fit: cover;
}
}
&-desc {
position: relative;
padding: 15px;

View File

@ -1,3 +1,5 @@
@use 'sass:math';
/*primary nav*/
.navbar-header {
position: relative;
@ -42,7 +44,7 @@
.nav-primary {
li {
> a > i {
margin: floor(-($nav-primary-height - $line-height-computed) / 2) -10px;
margin: floor(math.div(-($nav-primary-height - $line-height-computed), 2)) -10px;
line-height: $nav-primary-height;
width: $nav-primary-height;
float: left;
@ -61,7 +63,7 @@
ul.nav {
> li {
> a {
padding: floor(($nav-primary-height - $line-height-computed) / 2) 15px;
padding: floor(math.div($nav-primary-height - $line-height-computed, 2)) 15px;
position: relative;
font-size: 14px;
@ -245,7 +247,7 @@
> .vbox > .header,
> .vbox > .footer {
padding: 0 floor(($nav-xs-width - 30px) / 2);
padding: 0 floor(math.div($nav-xs-width - 30px, 2));
}
.hidden-nav-xs {
@ -309,7 +311,7 @@
> li {
> a {
.header-md & {
padding: floor(($header-md-height - $line-height-computed) / 2 - 1);
padding: floor(math.div($header-md-height - $line-height-computed, 2) - 1);
}
}
}
@ -326,7 +328,7 @@
// + *{
// padding-top: 50px !important;
// }
}
.nav-bar-fixed-bottom {
@ -518,7 +520,7 @@
border-left: 3px solid;
// #870003;
}
}
}

View File

@ -1 +1,3 @@
@import "~fullcalendar/dist/fullcalendar.print";
@media print {
@import "~fullcalendar/dist/fullcalendar.print";
}

View File

@ -1,25 +1,28 @@
.cookies-consent {
display: flex;
position: fixed;
bottom: 3rem;
left: 3rem;
width: 40rem;
right: 0;
bottom: 0;
left: 0;
background-color: #f5f5f5;
padding: 3rem;
flex-direction: column;
z-index: 100;
-webkit-box-shadow: 0 4px 10px 2px rgba(224, 224, 224, 0.43);
-moz-box-shadow: 0 4px 10px 2px rgba(224, 224, 224, 0.43);
box-shadow: 0 4px 10px 2px rgba(224, 224, 224, 0.43);
-webkit-box-shadow: 0 4px 10px 2px rgba(0, 0, 0, 0.25);
-moz-box-shadow: 0 4px 10px 2px rgba(0, 0, 0, 0.25);
box-shadow: 0 4px 10px 2px rgba(0, 0, 0, 0.25);
.cookies-actions {
flex-wrap: wrap;
display: flex;
height: 45px;
justify-content: space-between;
gap: 1rem;
margin-top: 1rem;
button {
flex-basis: 50%;
@extend .fab-button;
flex: 1;
}
button.decline {
background-color: transparent;
border: 0;
@ -31,4 +34,10 @@
font-size: 17px;
}
}
@media (min-width: 480px) {
bottom: 3rem;
left: 3rem;
width: 40rem;
}
}

View File

@ -90,4 +90,15 @@
</div>
</div>
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[scopes]'].$dirty && providerForm['auth_provider[scopes]'].$invalid}">
<label for="provider_client_secret" class="col-sm-3 control-label" translate>{{ 'app.shared.oauth2.scopes' }}</label>
<div class="col-sm-9">
<input type="text"
ng-model="provider.providable_attributes.scopes"
class="form-control"
name="auth_provider[scopes]"
id="provider_scopes"
placeholder="profile,email...">
</div>
</div>
<ng-include src="'/admin/authentications/_oauth2_mapping.html'"></ng-include>

View File

@ -106,6 +106,16 @@
<input type="text" id="spaceLabel" ng-model="settings.spaceLabel.value" class="form-control" placeholder="{{ 'app.admin.invoices.general_space_label' | translate }}"/>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label for="packCode" translate>{{ 'app.admin.invoices.accounting_Pack_code' }}</label>
<input type="text" id="packCode" ng-model="settings.packCode.value" class="form-control" placeholder="{{ 'app.admin.invoices.general_pack_code' | translate }}"/>
</div>
<div class="col-md-6">
<label for="packLabel" translate>{{ 'app.admin.invoices.accounting_Pack_label' }}</label>
<input type="text" id="packLabel" ng-model="settings.packLabel.value" class="form-control" placeholder="{{ 'app.admin.invoices.general_pack_label' | translate }}"/>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label for="spaceCode" translate>{{ 'app.admin.invoices.accounting_Error_code' }}</label>

View File

@ -42,7 +42,7 @@
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-search"></i></div>
<input type="search" class="form-control" placeholder="Mots-clés" ng-model="search.q"/>
<input type="search" class="form-control" placeholder="{{ 'app.public.projects_list.keywords' | translate }}" ng-model="search.q"/>
<div class="input-group-btn">
<button type="submit" class="btn btn-warning" translate>{{ 'app.public.projects_list.search' }}</button>
</div>

View File

@ -19,6 +19,8 @@ class AccountingPeriod < ApplicationRecord
validates_with PeriodOverlapValidator
validates_with PeriodIntegrityValidator
belongs_to :user, class_name: 'User', foreign_key: 'closed_by'
def delete
false
end
@ -79,13 +81,15 @@ class AccountingPeriod < ApplicationRecord
end
def compute_totals
period_invoices = invoices_with_vat(invoices.where(type: nil))
period_avoirs = invoices_with_vat(invoices.where(type: 'Avoir'))
period_invoices = invoices_with_vat(invoices.where(type: nil).includes([:invoice_items]))
period_avoirs = invoices_with_vat(invoices.where(type: 'Avoir').includes([:invoice_items]))
self.period_total = (period_invoices.map(&method(:price_without_taxe)).reduce(:+) || 0) -
(period_avoirs.map(&method(:price_without_taxe)).reduce(:+) || 0)
all_invoices = invoices_with_vat(Invoice.where('CAST(created_at AS DATE) <= :end_date AND type IS NULL', end_date: end_at))
all_avoirs = invoices_with_vat(Invoice.where("CAST(created_at AS DATE) <= :end_date AND type = 'Avoir'", end_date: end_at))
all_invoices = invoices_with_vat(Invoice.where('CAST(created_at AS DATE) <= :end_date AND type IS NULL', end_date: end_at)
.includes([:invoice_items]))
all_avoirs = invoices_with_vat(Invoice.where("CAST(created_at AS DATE) <= :end_date AND type = 'Avoir'", end_date: end_at)
.includes([:invoice_items]))
self.perpetual_total = (all_invoices.map(&method(:price_without_taxe)).reduce(:+) || 0) -
(all_avoirs.map(&method(:price_without_taxe)).reduce(:+) || 0)
self.footprint = compute_footprint

View File

@ -8,11 +8,6 @@ class InvoiceItem < Footprintable
has_one :payment_gateway_object, as: :item
belongs_to :object, polymorphic: true
belongs_to :reservation, foreign_type: 'Reservation', foreign_key: 'object_id'
belongs_to :subscription, foreign_type: 'Subscription', foreign_key: 'object_id'
belongs_to :wallet_transaction, foreign_type: 'WalletTransaction', foreign_key: 'object_id'
belongs_to :offer_day, foreign_type: 'OfferDay', foreign_key: 'object_id'
belongs_to :statistic_profile_prepaid_pack, foreign_type: 'StatisticProfilePrepaidPack', foreign_key: 'object_id'
after_create :chain_record
after_update :log_changes

View File

@ -128,7 +128,9 @@ class Setting < ApplicationRecord
pack_only_for_subscription
overlapping_categories
extended_prices_in_same_day
public_registrations] }
public_registrations
accounting_Pack_code
accounting_Pack_label] }
# WARNING: when adding a new key, you may also want to add it in:
# - config/locales/en.yml#settings
# - app/frontend/src/javascript/models/setting.ts#SettingName
@ -195,4 +197,11 @@ class Setting < ApplicationRecord
setting = find_or_initialize_by(name: name)
setting.save && setting.history_values.create(invoicing_profile: user.invoicing_profile, value: value.to_s)
end
##
# Check if the given setting was set
##
def self.set?(name)
find_by(name: name)&.value.nil? ? false : true
end
end

View File

@ -49,6 +49,8 @@ class User < ApplicationRecord
has_one :payment_gateway_object, as: :item
has_many :accounting_periods, foreign_key: 'closed_by', dependent: :nullify
# fix for create admin user
before_save do
email&.downcase!

View File

@ -25,9 +25,9 @@ class PDF::Invoice < Prawn::Document
)
# logo
img_b64 = Setting.find_by(name: 'invoice_logo')
img_b64 = Setting.get('invoice_logo')
begin
image StringIO.new(Base64.decode64(img_b64.value)), fit: [415, 40]
image StringIO.new(Base64.decode64(img_b64)), fit: [415, 40]
rescue StandardError => e
puts "Unable to decode invoice logo from base64: #{e}"
end
@ -97,9 +97,9 @@ class PDF::Invoice < Prawn::Document
DATE: I18n.l(invoice.main_item.object.slots[0].start_at.to_date),
TIME: I18n.l(invoice.main_item.object.slots[0].start_at, format: :hour_minute))
invoice.invoice_items.each do |item|
next unless item.subscription
next unless item.object_type == Subscription.name
subscription = item.subscription
subscription = item.object
cancellation = invoice.is_a?(Avoir) ? I18n.t('invoices.cancellation') + ' - ' : ''
object = "\n- #{object}\n- #{cancellation + subscription_verbose(subscription, name)}"
break
@ -135,7 +135,7 @@ class PDF::Invoice < Prawn::Document
details = invoice.is_a?(Avoir) ? I18n.t('invoices.cancellation') + ' - ' : ''
if item.object_type == Subscription.name
subscription = item.subscription
subscription = item.object
if invoice.main_item.object_type == 'OfferDay'
details += I18n.t('invoices.subscription_extended_for_free_from_START_to_END',
START: I18n.l(invoice.main_item.object.start_at.to_date),

View File

@ -28,9 +28,9 @@ class PDF::PaymentSchedule < Prawn::Document
)
# logo
img_b64 = Setting.find_by(name: 'invoice_logo')
img_b64 = Setting.get('invoice_logo')
begin
image StringIO.new(Base64.decode64(img_b64.value)), fit: [415, 40]
image StringIO.new(Base64.decode64(img_b64)), fit: [415, 40]
rescue StandardError => e
puts "Unable to decode invoice logo from base64: #{e}"
end

View File

@ -69,6 +69,8 @@ class AccountingExportService
end
elsif invoice.main_item.object_type == 'WalletTransaction'
rows << "#{wallet_row(invoice)}\n"
elsif invoice.main_item.object_type == 'StatisticProfilePrepaidPack'
rows << "#{pack_row(invoice)}\n"
elsif invoice.main_item.object_type == 'Error'
items = invoice.invoice_items.reject { |ii| ii.object_type == 'Subscription' }
items.each do |item|
@ -131,6 +133,16 @@ class AccountingExportService
)
end
def pack_row(invoice)
row(
invoice,
account(invoice, :pack),
account(invoice, :pack, type: :label),
invoice.invoice_items.first.net_amount / 100.00,
line_label: label(invoice)
)
end
# Generate the "VAT" row, which contains the credit to the VAT account, with VAT amount only
def vat_row(invoice)
total = invoice.invoice_items.map(&:net_amount).sum
@ -195,29 +207,35 @@ class AccountingExportService
def account(invoice, account, type: :code, means: :other)
case account
when :projets
Setting.find_by(name: "accounting_#{means}_client_#{type}")&.value
Setting.get("accounting_#{means}_client_#{type}")
when :vat
Setting.find_by(name: "accounting_VAT_#{type}")&.value
Setting.get("accounting_VAT_#{type}")
when :subscription
if invoice.subscription_invoice?
Setting.find_by(name: "accounting_subscription_#{type}")&.value
Setting.get("accounting_subscription_#{type}")
else
puts "WARN: Invoice #{invoice.id} has no subscription"
end
when :reservation
if invoice.main_item.object_type == 'Reservation'
Setting.find_by(name: "accounting_#{invoice.main_item.object.reservable_type}_#{type}")&.value
Setting.get("accounting_#{invoice.main_item.object.reservable_type}_#{type}")
else
puts "WARN: Invoice #{invoice.id} has no reservation"
end
when :wallet
if invoice.main_item.object_type == 'WalletTransaction'
Setting.find_by(name: "accounting_wallet_#{type}")&.value
Setting.get("accounting_wallet_#{type}")
else
puts "WARN: Invoice #{invoice.id} is not a wallet credit"
end
when :pack
if invoice.main_item.object_type == 'StatisticProfilePrepaidPack'
Setting.get("accounting_Pack_#{type}")
else
puts "WARN: Invoice #{invoice.id} has no prepaid-pack"
end
when :error
Setting.find_by(name: "accounting_Error_#{type}")&.value
Setting.get("accounting_Error_#{type}")
else
puts "Unsupported account #{account}"
end || ''

View File

@ -46,7 +46,7 @@ class Members::MembersService
@member.update_statistic_profile
@member.generate_subscription_invoice(current_user.id)
@member.send_confirmation_instructions
UsersMailer.delay.notify_user_account_created(@member, @member.password)
UsersMailer.notify_user_account_created(@member, @member.password).deliver_later
true
else
false

View File

@ -126,13 +126,11 @@ class StatisticService
def subscriptions_list(options = default_options)
result = []
InvoiceItem.where('invoice_items.created_at >= :start_date AND invoice_items.created_at <= :end_date', options)
.eager_load(invoice: [:coupon], subscription: [:plan, statistic_profile: [:group]]).each do |i|
InvoiceItem.where("object_type = '#{Subscription.name}' AND invoice_items.created_at >= :start_date AND invoice_items.created_at <= :end_date", options)
.eager_load(invoice: [:coupon]).each do |i|
next if i.invoice.is_a?(Avoir)
sub = i.subscription
next unless sub
sub = i.object
ca = i.amount.to_i
cs = CouponService.new

View File

@ -46,7 +46,7 @@ class UserService
admin.send_confirmation_instructions
admin.add_role(:admin)
admin.remove_role(:member)
UsersMailer.delay.notify_user_account_created(admin, generated_password)
UsersMailer.notify_user_account_created(admin, generated_password).deliver_later
end
{ saved: saved, user: admin }
end
@ -61,7 +61,7 @@ class UserService
manager.send_confirmation_instructions
manager.add_role(:manager)
manager.remove_role(:member)
UsersMailer.delay.notify_user_account_created(manager, generated_password)
UsersMailer.notify_user_account_created(manager, generated_password).deliver_later
end
{ saved: saved, user: manager }
end

View File

@ -4,9 +4,9 @@ json.partial! 'api/auth_providers/auth_provider', auth_provider: @provider
if @provider.providable_type == OAuth2Provider.name
json.providable_attributes do
json.extract! @provider.providable, :id, :base_url, :token_endpoint, :authorization_endpoint, :profile_url, :client_id, :client_secret
json.extract! @provider.providable, :id, :base_url, :token_endpoint, :authorization_endpoint, :profile_url, :client_id, :client_secret, :scopes
json.o_auth2_mappings_attributes @provider.providable.o_auth2_mappings do |m|
json.extract! m, :id, :local_model, :local_field, :api_field, :api_endpoint, :api_data_type, :transformation
end
end
end
end

View File

@ -67,9 +67,7 @@
Fablab.sessionTours = [];
</script>
<%= stylesheet_packs_with_chunks_tag 'application', media: 'all' %>
<%= stylesheet_packs_with_chunks_tag 'plugins', media: 'all' %>
<%= stylesheet_packs_with_chunks_tag 'printer', media: 'print' %>
<%= stylesheet_pack_tag 'application', 'plugins', 'printer' %>
<% unless Stylesheet.theme.nil? %>
<link rel="stylesheet" media="all" href="<%= stylesheet_path(Stylesheet.theme.id) %>-<%= Stylesheet.theme.updated_at.to_i.to_s %>.css" />
<% end %>
@ -134,6 +132,6 @@
<span class="text-sm">Powered by <a href="http://www.fab-manager.com" target="_blank">Fab-manager</a></span>
</div>
<%= javascript_packs_with_chunks_tag 'application' %>
<%= javascript_pack_tag 'application' %>
</body>
</html>

View File

@ -1,3 +1,6 @@
# frozen_string_literal: true
# Send a reminder email to the user who has made a reservation
class ReservationReminderWorker
include Sidekiq::Worker
@ -5,25 +8,24 @@ class ReservationReminderWorker
DEFAULT_REMINDER_DELAY = 24.hours
def perform
enabled = Setting.find_by(name: 'reminder_enable').try(:value)
if enabled == 'true'
delay = Setting.find_by(name: 'reminder_delay').try(:value).try(:to_i).try(:hours) || DEFAULT_REMINDER_DELAY
return unless Setting.get('reminder_enable')
starting = DateTime.current.beginning_of_hour + delay
ending = starting + 1.hour
delay = Setting.find_by(name: 'reminder_delay').try(:value).try(:to_i).try(:hours) || DEFAULT_REMINDER_DELAY
Reservation.joins(:slots).where('slots.start_at >= ? AND slots.start_at <= ? AND slots.canceled_at IS NULL', starting, ending).each do |r|
already_sent = Notification.where(
attached_object_type: Reservation.name,
attached_object_id: r.id,
notification_type_id: NotificationType.find_by_name('notify_member_reservation_reminder')
).count
unless already_sent > 0
NotificationCenter.call type: 'notify_member_reservation_reminder',
receiver: r.user,
attached_object: r
end
end
starting = DateTime.current.beginning_of_hour + delay
ending = starting + 1.hour
Reservation.joins(:slots).where('slots.start_at >= ? AND slots.start_at <= ? AND slots.canceled_at IS NULL', starting, ending).each do |r|
already_sent = Notification.where(
attached_object_type: Reservation.name,
attached_object_id: r.id,
notification_type_id: NotificationType.find_by_name('notify_member_reservation_reminder')
).count
next if already_sent.positive?
NotificationCenter.call type: 'notify_member_reservation_reminder',
receiver: r.user,
attached_object: r
end
end
end
end

View File

@ -4,7 +4,6 @@ module.exports = function (api) {
const isDevelopmentEnv = api.env('development');
const isProductionEnv = api.env('production');
const isTestEnv = api.env('test');
const isWebpackDevServer = process.env.WEBPACK_DEV_SERVER;
if (!validEnv.includes(currentEnv)) {
throw new Error(
@ -16,39 +15,20 @@ module.exports = function (api) {
);
}
return {
const defaultConfigFunc = require('shakapacker/package/babel/preset.js');
const resultConfig = defaultConfigFunc(api);
const changesOnDefault = {
presets: [
isTestEnv && [
'@babel/preset-env',
{
targets: {
node: 'current'
},
modules: 'commonjs'
},
'@babel/preset-react'
],
(isProductionEnv || isDevelopmentEnv) && [
'@babel/preset-env',
{
forceAllTransforms: true,
useBuiltIns: 'entry',
corejs: 3,
modules: false,
exclude: ['transform-typeof-symbol']
}
],
[
'@babel/preset-react',
{
development: isDevelopmentEnv || isTestEnv,
useBuiltIns: true
}
],
['@babel/preset-typescript', { allExtensions: true, isTSX: true }]
]
].filter(Boolean),
plugins: [
isWebpackDevServer && 'react-refresh/babel',
'babel-plugin-macros',
'@babel/plugin-syntax-dynamic-import',
isTestEnv && 'babel-plugin-dynamic-import-node',
@ -56,7 +36,7 @@ module.exports = function (api) {
[
'@babel/plugin-proposal-class-properties',
{
loose: false
loose: true
}
],
[
@ -65,26 +45,28 @@ module.exports = function (api) {
useBuiltIns: true
}
],
[
'@babel/plugin-transform-runtime',
{
helpers: false,
regenerator: true,
corejs: false
}
],
[
'@babel/plugin-transform-regenerator',
{
async: false
}
],
isProductionEnv && [
'babel-plugin-transform-react-remove-prop-types',
isProductionEnv && ['babel-plugin-transform-react-remove-prop-types',
{
removeImport: true
}
],
process.env.WEBPACK_SERVE && [
'react-refresh/babel',
{
exclude: 'node_modules/**'
}
]
].filter(Boolean)
};
resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets];
resultConfig.plugins = [...resultConfig.plugins, ...changesOnDefault.plugins];
return resultConfig;
};

15
bin/webpacker Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env ruby
require "pathname"
require "bundler/setup"
require "webpacker"
require "webpacker/webpack_runner"
ENV["RAILS_ENV"] ||= "development"
ENV["NODE_ENV"] ||= ENV["RAILS_ENV"]
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath)
APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
Webpacker::WebpackRunner.run(ARGV)
end

18
bin/webpacker-dev-server Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env ruby
ENV["RAILS_ENV"] ||= "development"
ENV["NODE_ENV"] ||= ENV["RAILS_ENV"]
require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require "bundler/setup"
require "webpacker"
require "webpacker/dev_server_runner"
APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
Webpacker::DevServerRunner.run(ARGV)
end

View File

@ -1,9 +1,16 @@
#!/usr/bin/env ruby
APP_ROOT = File.expand_path('..', __dir__)
APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
begin
exec "yarnpkg", *ARGV
rescue Errno::ENOENT
yarn = ENV["PATH"].split(File::PATH_SEPARATOR).
select { |dir| File.expand_path(dir) != __dir__ }.
product(["yarn", "yarnpkg", "yarn.cmd", "yarn.ps1"]).
map { |dir, file| File.expand_path(file, dir) }.
find { |file| File.executable?(file) }
if yarn
exec yarn, *ARGV
else
$stderr.puts "Yarn executable was not detected in the system."
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
exit 1

View File

@ -1,10 +1,14 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Define an application-wide content security policy
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
# Rails.application.config.content_security_policy do |policy|
Rails.application.config.content_security_policy do |policy| # # If you are using webpack-dev-server then specify webpack-dev-server host
policy.connect_src :self, :https, 'http://localhost:3035', 'ws://localhost:3035' if Rails.env.development?
# policy.default_src :self, :https
# policy.font_src :self, :https, :data
# policy.img_src :self, :https, :data
@ -14,7 +18,7 @@
# # Specify URI for violation reports
# # policy.report_uri "/csp-violation-report-endpoint"
# end
end
# If you are using UJS then enable automatic nonce generation
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }

View File

@ -1,25 +1,42 @@
# frozen_string_literal: true
require 'sidekiq'
require 'sidekiq-scheduler'
redis_host = ENV['REDIS_HOST'] || 'localhost'
redis_url = "redis://#{redis_host}:6379"
Sidekiq.configure_server do |config|
config.redis = { url: redis_url }
# load sidekiq-cron schedule config
schedule_file = 'config/schedule.yml'
config.client_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Client
end
if File.exist?(schedule_file)
rendered_schedule_file = ERB.new(File.read(schedule_file)).result
Sidekiq::Cron::Job.load_from_hash YAML.safe_load(rendered_schedule_file)
config.server_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Server
end
SidekiqUniqueJobs::Server.configure(config)
config.on(:startup) do
# load sidekiq-scheduler schedule config
schedule_file = 'config/schedule.yml'
if File.exist?(schedule_file)
rendered_schedule_file = ERB.new(File.read(schedule_file)).result
Sidekiq.schedule = YAML.safe_load(rendered_schedule_file)
SidekiqScheduler::Scheduler.instance.reload_schedule!
end
end
end
Sidekiq.configure_client do |config|
config.redis = { url: redis_url }
end
Sidekiq::Extensions.enable_delay!
config.client_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Client
end
end
# Quieting logging in the test environment
if Rails.env.test?

View File

@ -673,6 +673,10 @@ de:
general_space_code: "Abrechnungscode für alle Räume"
accounting_Space_label: "Raumbezeichnung"
general_space_label: "Abrechnungs-Label für alle Räume"
accounting_Pack_code: "Prepaid-pack code"
general_pack_code: "Accounting code for prepaid-packs"
accounting_Pack_label: "Prepaid-pack label"
general_pack_label: "Account label for prepaid-packs"
accounting_Error_code: "Fehlercode"
general_error_code: "Rechnungscode für fehlerhafte Rechnungen"
accounting_Error_label: "Fehlerbezeichnung"
@ -983,7 +987,7 @@ de:
#add a new administrator to the platform
admins_new:
add_an_administrator: "Administrator hinzufügen"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Administrator erfolgreich erstellt. {GENDER, select, female{Sie} other{Er}} erhält {GENDER, select, female{ihre} other{seine}} Verbindungsanweisungen per E-Mail."
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Administrator erfolgreich erstellt. Er erhält seine Verbindungsanweisungen per E-Mail."
failed_to_create_admin: "Administrator konnte nicht erstellt werden:"
man: "Männlich"
woman: "Weiblich"
@ -1001,7 +1005,7 @@ de:
#add a new manager to the platform
manager_new:
add_a_manager: "Manager hinzufügen"
manager_successfully_created: "Manager erfolgreich erstellt. {GENDER, select, female{Sie} other{Er}} erhält {GENDER, select, female{ihre} other{seine}} Verbindungsanweisungen per E-Mail."
manager_successfully_created: "Manager erfolgreich erstellt. Er erhält seine Verbindungsanweisungen per E-Mail."
failed_to_create_manager: "Konnte den Manager nicht erstellen:"
man: "Männlich"
woman: "Weiblich"
@ -1032,7 +1036,7 @@ de:
oauth2_provider_successfully_added: "OAuth 2.0 Provider erfolgreich hinzugefügt."
#edit an authentication provider (SSO)
authentication_edit:
provider: "Provider:"
provider: "Anbieter:"
it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider: "Um diesen Provider hinzuzufügen, muss die Übereinstimmung zwischen User.uid und der API festgelegt werden."
provider_successfully_updated: "Anbieter erfolgreich aktualisiert."
an_error_occurred_unable_to_update_the_provider: "Ein Fehler ist aufgetreten: Der Anbieter konnte nicht aktualisiert werden."
@ -1381,7 +1385,7 @@ de:
online_payment: "Ist das Online-Zahlungsmodul aktiv?"
invoices: "Ist das Rechnungsmodul aktiv?"
openlab: "Ist das Projektteilungsmodul (OpenLab) aktiv?"
tracking_id_info_html: "<p>Um die statistische Analyse der Besuche mithilfe von Google Analytics zu ermöglichen, tragen Sie hier Ihre Tracking-ID in der Form UA-000000-0 ein. Besuchen Sie <a href='https://analytics.google.com/analytics/web/' target='_blank'>die Google Analytics Website</a>, um eine Tracking-ID zu erstellen.<br/><strong>Warnung:</strong> wenn Sie dieses Feature aktivieren, muss in Ihrer Datenschutzrichtlinie darauf hingewiesen werden.</p><p> Um Google Analytics verwenden zu können, benötigen Sie auch den Hostnamen. Klicken Sie auf die angrenzende Schaltfläche. Dieser letzte Parameter wird auch an anderen Stellen verwendet, bitte verwenden Sie ihn vorsichtig.</p>"
tracking_id_info_html: "Um die statistische Analyse der Besuche mithilfe von Google Analytics V4 zu ermöglichen, tragen Sie hier Ihre Tracking-ID in der Form G-XXXXXX ein. Besuchen Sie <a href='https://analytics.google.com/analytics/web/' target='_blank'>die Google Analytics Website</a>, um eine Tracking-ID zu erstellen.<br/><strong>Warnung:</strong> wenn Sie dieses Feature aktivieren, wird ein Cookie erstellt. Denken Sie daran, es oben in Ihrer Datenschutzrichtlinie darauf hingewiesen werden."
tracking_id: "Tracking-ID"
open_api_clients:
add_new_client: "Neuen API-Client erstellen"
@ -1395,7 +1399,7 @@ de:
client_name: "Kundenname"
confirmation_required: "Bestätigung erforderlich"
do_you_really_want_to_delete_this_open_api_client: "Möchten Sie diesen OpenAPI-Client wirklich löschen?"
do_you_really_want_to_revoke_this_open_api_access: "Möchten Sie diesen Zugriff wirklich widerrufen ? Er wird das aktuelle Token löschen und ersetzen."
do_you_really_want_to_revoke_this_open_api_access: "Möchten Sie diesen Zugriff wirklich widerrufen? Er wird das aktuelle Token löschen und ersetzen."
client_successfully_created: "Client erfolgreich erstellt."
client_successfully_updated: "Client erfolgreich aktualisiert."
client_successfully_deleted: "Client erfolgreich gelöscht."

View File

@ -15,7 +15,7 @@ en:
trainings: "Trainings"
machines: "Machines"
spaces: "Spaces"
events: "Eventos"
events: "Events"
availabilities: "Availabilities"
availabilities_notice: "Export to an Excel workbook every slots available for reservation, and their occupancy rate."
info: "Info"
@ -24,7 +24,7 @@ en:
ongoing_reservations: "Ongoing reservations"
without_reservation: "Without reservation"
confirmation_required: "Confirmation required"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Do you really {GENDER, select, other {want}} to cancel the {USER}'s reservation, the {DATE} at {TIME}, concerning {RESERVATION}?"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Do you really want to cancel {USER}'s reservation, the {DATE} at {TIME}, concerning {RESERVATION}?"
reservation_was_successfully_cancelled: "Reservation was successfully cancelled."
reservation_cancellation_failed: "Reservation cancellation failed."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "Unable to remove the last machine of the slot. Delete the slot rather."
@ -184,7 +184,7 @@ en:
NUMBER_reservation: "{NUMBER} {NUMBER, plural, one{reservation} other{reservations}}"
none: "None"
training_validation: "Training validation"
training_of_the_DATE_TIME_html : "Training of the <strong>{DATE} - {TIME}</strong>"
training_of_the_DATE_TIME_html: "Training of the <strong>{DATE} - {TIME}</strong>"
you_can_validate_the_training_of_the_following_members: "You can validate the training of the following members:"
deleted_user: "Deleted user"
no_reservation: "No reservation"
@ -271,7 +271,7 @@ en:
events_edit:
edit_the_event: "Edit the event"
confirmation_required: "Confirmation required"
edit_recurring_event: "You're about to update a periodic event. What do you want to update ?"
edit_recurring_event: "You're about to update a periodic event. What do you want to update?"
edit_this_event: "Only this event"
edit_this_and_next: "This event and the following"
edit_all: "All events"
@ -322,10 +322,10 @@ en:
none: "None" #grammar concordance with training.
an_error_occurred_while_saving_the_number_of_credits: "An error occurred while saving the number of credits."
an_error_occurred_while_deleting_credit_with_the_TRAINING: "An error occurred while deleting credit with the {TRAINING}."
an_error_occurred_unable_to_find_the_credit_to_revoke: "An error occurred : unable to find the credit to revoke."
an_error_occurred_unable_to_find_the_credit_to_revoke: "An error occurred: unable to find the credit to revoke."
an_error_occurred_while_creating_credit_with_the_TRAINING: "An error occurred while creating credit with the {TRAINING}."
not_set: "Not set"
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Error : a credit linking this machine with that subscription already exists."
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Error: a credit linking this machine with that subscription already exists."
changes_have_been_successfully_saved: "Changes have been successfully saved."
credit_was_successfully_saved: "Credit was successfully saved."
error_creating_credit: "Unable to create credit, an error occurred"
@ -365,7 +365,7 @@ en:
these_prices_match_space_hours_rates_html: "The prices below match one hour of space usage, <strong>without subscription</strong>."
add_a_space_credit: "Add a Space credit"
space: "Space"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "Error : a credit linking this space with that subscription already exists."
error_a_credit_linking_this_space_with_that_subscription_already_exists: "Error: a credit linking this space with that subscription already exists."
status_enabled: "Enabled"
status_disabled: "Disabled"
status_all: "All"
@ -482,7 +482,7 @@ en:
no_invoices_for_now: "No invoices for now."
payment_schedules_list: "Payment schedules"
invoicing_settings: "Invoicing settings"
warning_invoices_disabled: "Warning : invoices are not enabled. No invoices will be generated by Fab-manager. Nevertheless, you must correctly fill the information below, especially VAT."
warning_invoices_disabled: "Warning: invoices are not enabled. No invoices will be generated by Fab-manager. Nevertheless, you must correctly fill the information below, especially VAT."
change_logo: "Change logo"
john_smith: "John Smith"
john_smith_at_example_com: "jean.smith@example.com"
@ -673,6 +673,10 @@ en:
general_space_code: "Accounting code for all spaces"
accounting_Space_label: "Spaces label"
general_space_label: "Account label for all spaces"
accounting_Pack_code: "Prepaid-pack code"
general_pack_code: "Accounting code for prepaid-packs"
accounting_Pack_label: "Prepaid-pack label"
general_pack_label: "Account label for prepaid-packs"
accounting_Error_code: "Errors code"
general_error_code: "Accounting code for erroneous invoices"
accounting_Error_label: "Errors label"
@ -983,7 +987,7 @@ en:
#add a new administrator to the platform
admins_new:
add_an_administrator: "Add an administrator"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Administrator successfully created. {GENDER, select, female{She} other{He}} receive {GENDER, select, female{her} other{his}} connection directives by e-mail."
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Successful creation. Connection directives were sent to the new administrator by e-mail."
failed_to_create_admin: "Unable to create the administrator:"
man: "Man"
woman: "Woman"
@ -1001,7 +1005,7 @@ en:
#add a new manager to the platform
manager_new:
add_a_manager: "Add a manager"
manager_successfully_created: "Manager successfully created. {GENDER, select, female{She} other{He}} receive {GENDER, select, female{her} other{his}} connection directives by e-mail."
manager_successfully_created: "Successful creation. Connection directives were sent to the new manager by e-mail."
failed_to_create_manager: "Unable to create the manager:"
man: "Man"
woman: "Woman"
@ -1032,7 +1036,7 @@ en:
oauth2_provider_successfully_added: "OAuth 2.0 provider successfully added."
#edit an authentication provider (SSO)
authentication_edit:
provider: "Provider :"
provider: "Provider:"
it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider: "It is required to set the matching between User.uid and the API to add this provider."
provider_successfully_updated: "Provider successfully updated."
an_error_occurred_unable_to_update_the_provider: "An error occurred: unable to update the provider."
@ -1322,7 +1326,7 @@ en:
public_registrations_allowed: "Public registrations allowed"
help: "Help"
feature_tour: "Feature tour"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he/she visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"
feature_tour_display_mode: "Feature tour display mode"
display_mode:
once: "Once"
@ -1381,7 +1385,7 @@ en:
online_payment: "Is the online payment module active?"
invoices: "Is the invoicing module active?"
openlab: "Is the project sharing module (OpenLab) active?"
tracking_id_info_html: "<p>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 <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, remember to write it in your privacy policy, above.</p><p>The host name is also required to use Google Analytics. You can get it by clicking on the adjacent button. This last parameter is used elsewhere, please set it carefully.</p>"
tracking_id_info_html: "To enable the statistical tracking of the visits using Google Analytics V4, set your tracking ID here. It is in the form G-XXXXXX. Visit <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, a cookie will be created. Remember to write it down in your privacy policy, above."
tracking_id: "Tracking ID"
open_api_clients:
add_new_client: "Create new API client"
@ -1395,7 +1399,7 @@ en:
client_name: "Client's name"
confirmation_required: "Confirmation required"
do_you_really_want_to_delete_this_open_api_client: "Do you really want to delete this OpenAPI client?"
do_you_really_want_to_revoke_this_open_api_access: "Do you really want to revoke this access ? It will erase and replace the current token."
do_you_really_want_to_revoke_this_open_api_access: "Do you really want to revoke this access? It will erase and replace the current token."
client_successfully_created: "Client successfully created."
client_successfully_updated: "Client successfully updated."
client_successfully_deleted: "Client successfully deleted."

View File

@ -24,7 +24,7 @@ es:
ongoing_reservations: "Reservas en curso"
without_reservation: "Sin reserva"
confirmation_required: "Confirmación requerida"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Realmente quieres cancelar la reserva del {USER}, en {DATE} a las {TIME}, respecto {RESERVATION}?"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "¿Realmente quieres cancelar la reserva del {USER}, en {DATE} a las {TIME}, respecto {RESERVATION}?"
reservation_was_successfully_cancelled: "La reserva fué cancelada con éxito."
reservation_cancellation_failed: "Fallo al cancelar la reserva."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "No se puede quitar la última máquina de la ranura. Eliminar la ranura en su lugar."
@ -271,7 +271,7 @@ es:
events_edit:
edit_the_event: "Editar el evento"
confirmation_required: "Confirmation required"
edit_recurring_event: "You're about to update a periodic event. What do you want to update ?"
edit_recurring_event: "You're about to update a periodic event. What do you want to update?"
edit_this_event: "Only this event"
edit_this_and_next: "This event and the following"
edit_all: "All events"
@ -482,7 +482,7 @@ es:
no_invoices_for_now: "Sin facturas por ahora."
payment_schedules_list: "Payment schedules"
invoicing_settings: "Configuración de facturación"
warning_invoices_disabled: "Warning : invoices are not enabled. No invoices will be generated by Fab-manager. Nevertheless, you must correctly fill the information below, especially VAT."
warning_invoices_disabled: "Warning: invoices are not enabled. No invoices will be generated by Fab-manager. Nevertheless, you must correctly fill the information below, especially VAT."
change_logo: "Cambio de logotipo"
john_smith: "John Smith"
john_smith_at_example_com: "jean.smith@example.com"
@ -673,6 +673,10 @@ es:
general_space_code: "Accounting code for all spaces"
accounting_Space_label: "Spaces label"
general_space_label: "Account label for all spaces"
accounting_Pack_code: "Prepaid-pack code"
general_pack_code: "Accounting code for prepaid-packs"
accounting_Pack_label: "Prepaid-pack label"
general_pack_label: "Account label for prepaid-packs"
accounting_Error_code: "Errors code"
general_error_code: "Accounting code for erroneous invoices"
accounting_Error_label: "Errors label"
@ -838,7 +842,7 @@ es:
active: "Activo"
pending: "Pendiente"
previous_provider: "Proveedor anteriorr"
confirmation_required: "Delete the provider?"
confirmation_required: "¿Eliminar el proveedor?"
do_you_really_want_to_delete_the_TYPE_authentication_provider_NAME: "¿Realmente desea eliminar la {TYPE} proveedor de autenticación: {NAME}?"
authentication_provider_successfully_deleted: "El proveedor de autenticación se eliminó correctamente."
an_error_occurred_unable_to_delete_the_specified_provider: "Se ha producido un error: no se puede eliminar el proveedor especificado."
@ -983,7 +987,7 @@ es:
#add a new administrator to the platform
admins_new:
add_an_administrator: "Agregar un administrador"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "administrador creado correctamente. {GENDER, select, female{She} other{He}} receive {GENDER, select, female{her} other{his}} directivas de conexión por e-mail."
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Successful creation. Connection directives were sent to the new administrator by e-mail."
failed_to_create_admin: "No se puede crear el administrador :"
man: "Man"
woman: "Woman"
@ -1001,7 +1005,7 @@ es:
#add a new manager to the platform
manager_new:
add_a_manager: "Add a manager"
manager_successfully_created: "Manager successfully created. {GENDER, select, female{She} other{He}} receive {GENDER, select, female{her} other{his}} connection directives by e-mail."
manager_successfully_created: "Successful creation. Connection directives were sent to the new manager by e-mail."
failed_to_create_manager: "Unable to create the manager:"
man: "Man"
woman: "Woman"
@ -1032,7 +1036,7 @@ es:
oauth2_provider_successfully_added: "OAuth 2.0 proveedor agregado correctamente."
#edit an authentication provider (SSO)
authentication_edit:
provider: "Proveedor :"
provider: "Proveedor:"
it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider: "Es necesario establecer la coincidencia entre User.uid y la API para agregar este proveedor."
provider_successfully_updated: "Proveedor actualizado correctamente."
an_error_occurred_unable_to_update_the_provider: "Se ha producido un error: no se puede actualizar el proveedor."
@ -1322,7 +1326,7 @@ es:
public_registrations_allowed: "Public registrations allowed"
help: "Help"
feature_tour: "Feature tour"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he/she visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"
feature_tour_display_mode: "Feature tour display mode"
display_mode:
once: "Once"
@ -1381,7 +1385,7 @@ es:
online_payment: "Is the online payment module active?"
invoices: "Is the invoicing module active?"
openlab: "Is the project sharing module (OpenLab) active?"
tracking_id_info_html: "<p>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 <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, remember to write it in your privacy policy, above.</p><p>The host name is also required to use Google Analytics. You can get it by clicking on the adjacent button. This last parameter is used elsewhere, please set it carefully.</p>"
tracking_id_info_html: "To enable the statistical tracking of the visits using Google Analytics V4, set your tracking ID here. It is in the form G-XXXXXX. Visit <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, a cookie will be created. Remember to write it down in your privacy policy, above."
tracking_id: "Tracking ID"
open_api_clients:
add_new_client: "Crear un nuevo cliente de API"
@ -1395,7 +1399,7 @@ es:
client_name: "Nombre del cliente"
confirmation_required: "Confirmation required"
do_you_really_want_to_delete_this_open_api_client: "¿Desea realmente eliminar este cliente OpenAPI?"
do_you_really_want_to_revoke_this_open_api_access: "¿Realmente desea revocar este acceso? Se borrará y reemplazará el token actual."
do_you_really_want_to_revoke_this_open_api_access: "Do you really want to revoke this access? It will erase and replace the current token."
client_successfully_created: "Cliente creado correctamente."
client_successfully_updated: "Cliente actualizado correctamente."
client_successfully_deleted: "Cliente borrado correctamente."

View File

@ -24,7 +24,7 @@ fr:
ongoing_reservations: "Réservations en cours"
without_reservation: "Sans réservation"
confirmation_required: "Confirmation requise"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Êtes-vous {GENDER, select, female{sûre} other{sûr}} de vouloir annuler la réservation de {USER}, le {DATE} à {TIME}, concernant {RESERVATION} ?"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Voulez-vous vraiment annuler la réservation de {USER}, le {DATE} à {TIME}, concernant {RESERVATION} ?"
reservation_was_successfully_cancelled: "La réservation a bien été annulée."
reservation_cancellation_failed: "L'annulation de la réservation a échouée."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "Impossible de supprimer la dernière machine du créneau. Supprimez plutôt le créneau."
@ -271,7 +271,7 @@ fr:
events_edit:
edit_the_event: "Éditer lévénement"
confirmation_required: "Confirmation requise"
edit_recurring_event: "Vous êtes sur le point de modifier un événement périodique. Que voulez-vous modifier ?"
edit_recurring_event: "Vous êtes sur le point de mettre à jour un événement périodique. Que voulez-vous mettre à jour ?"
edit_this_event: "Uniquement cet événement"
edit_this_and_next: "Cet événement et tous les suivants"
edit_all: "Tous les événements"
@ -673,6 +673,10 @@ fr:
general_space_code: "Code comptable pour tous les espaces"
accounting_Space_label: "Libellé espaces"
general_space_label: "Libellé du compte pour tous les espaces"
accounting_Pack_code: "Code pack prépayé"
general_pack_code: "Code comptable pour tous les packs prépayés"
accounting_Pack_label: "Libellé pack prépayé"
general_pack_label: "Libellé du compte pour tous les packs prépayés"
accounting_Error_code: "Code erreurs"
general_error_code: "Code comptable pour les factures en erreur"
accounting_Error_label: "Libellé erreurs"
@ -983,7 +987,7 @@ fr:
#add a new administrator to the platform
admins_new:
add_an_administrator: "Ajouter un administrateur"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "L'administrateur a bien été créé. {GENDER, select, female{Elle} other{Il}} recevra ses instructions de connexion par email."
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Création réussie. Les directives de connexion ont été envoyées à l'administrateur par e-mail."
failed_to_create_admin: "Impossible de créer l'administrateur :"
man: "Homme"
woman: "Femme"
@ -1001,7 +1005,7 @@ fr:
#add a new manager to the platform
manager_new:
add_a_manager: "Ajouter un gestionnaire"
manager_successfully_created: "Le gestionnaire a bien été créé. {GENDER, select, female{Elle} other{Il}} recevra ses instructions de connexion par courriel."
manager_successfully_created: "Création réussie. Les directives de connexion ont été envoyées au nouveau gestionnaire par e-mail."
failed_to_create_manager: "Impossible de créer le gestionnaire :"
man: "Homme"
woman: "Femme"
@ -1381,7 +1385,7 @@ 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 ?"
tracking_id_info_html: "<p>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 <a href='https://analytics.google.com/analytics/web/' target='_blank'>le site web de Google Analytics</a> pour en obtenir un.<br/><strong>Attention :</strong> si vous activez cette fonctionnalité, pensez à l'indiquer dans votre politique de confidentialité, ci-dessus.</p><p>Le nom d'hôte est également requis pour pouvoir utiliser Google Analytics. Vous pouvez l'obtenir en cliquant sur le bouton adjacent. Ce dernier paramètre est utilisé ailleurs, veuillez le définir avec soin.</p>"
tracking_id_info_html: "Pour activer les suivi statistique des visites utilisant Google Analytics V4, définissez ici votre ID de suivi. Il se présente sous la forme G-XXXXXX. Visitez <a href='https://analytics.google.com/analytics/web/' target='_blank'>le site web de Google Analytics</a> pour en obtenir un.<br/><strong>Attention :</strong> si vous activez cette fonctionnalité, une cookie sera créé. 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"

View File

@ -24,7 +24,7 @@
ongoing_reservations: "Pågående reservasjoner"
without_reservation: "Ikke reservert"
confirmation_required: "Bekreftelse nødvendig"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "{GENDER, select, other {Ønsker du å}} kansellere {USER} sin reservasjon {DATE}, {TIME} for {RESERVATION}?"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Ønsker du å kansellere {USER} sin reservasjon {DATE}, {TIME} for {RESERVATION}?"
reservation_was_successfully_cancelled: "Kansellering av reservasjon er gjennomført."
reservation_cancellation_failed: "Det gikk ikke an å kansellere reservasjonen."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "Kan ikke fjerne siste maskinen fra reservasjonen. Slett reservasjonen."
@ -325,7 +325,7 @@
an_error_occurred_unable_to_find_the_credit_to_revoke: "En feil oppstod: kunne ikke finne kreditten som skal tilbakekalles."
an_error_occurred_while_creating_credit_with_the_TRAINING: "Det oppstod en feil under oppretting av kreditt med {TRAINING}."
not_set: "Ikke angitt"
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Feil : en kreditnota på denne maskinen med dette abonnementet finnes allerede."
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Feil: en kreditnota på denne maskinen med dette abonnementet finnes allerede."
changes_have_been_successfully_saved: "Endringene er lagret."
credit_was_successfully_saved: "Kreditten ble lagret."
error_creating_credit: "Kan ikke opprette kreditt, feil oppstod"
@ -365,7 +365,7 @@
these_prices_match_space_hours_rates_html: "Prisene under samsvarer med en time maskinbruk <strong>uten abonnement</strong>."
add_a_space_credit: "Legg til en plass/romkreditt"
space: "Plass/rom"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "Feil : en kreditnota på denne maskinen med dette abonnementet finnes allerede."
error_a_credit_linking_this_space_with_that_subscription_already_exists: "Feil: en kreditnota på denne maskinen med dette abonnementet finnes allerede."
status_enabled: "Aktivert"
status_disabled: "Deaktivert"
status_all: "Alle"
@ -673,6 +673,10 @@
general_space_code: "Regnskapskode for plasser/rom"
accounting_Space_label: "Etikett, plasser/rom"
general_space_label: "Regnskapskode for alle plasser/rom"
accounting_Pack_code: "Prepaid-pack code"
general_pack_code: "Accounting code for prepaid-packs"
accounting_Pack_label: "Prepaid-pack label"
general_pack_label: "Account label for prepaid-packs"
accounting_Error_code: "Kode for feil"
general_error_code: "Regnskapskode for fakturafeil"
accounting_Error_label: "Etikett for feil"
@ -1295,7 +1299,7 @@
training_reservations: "Trainings"
machine_reservations: "Machines"
space_reservations: "Spaces"
events_reservations: "Events"
events_reservations: "Arrangementer"
general:
general: "Generelt"
title: "Tittel"
@ -1322,7 +1326,7 @@
public_registrations_allowed: "Public registrations allowed"
help: "Hjelp"
feature_tour: "Funksjonsgjennomgang"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he/she visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"
feature_tour_info_html: "<p>Når en administrator eller en leder er innlogget En fremvisning utløses første gang han besøker hver del av applikasjonen. Du kan endre denne adferden til en av følgende verdier:</p><ul><li>« Once » for å beholde standardvirkemåten.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » for å forhindre at turene vises automatisk. Det vil fortsatt være mulig å utløse dem ved å trykke F1-tasten eller ved å klikke på « Hjelp » i brukermenyen.</li></ul>"
feature_tour_display_mode: "Modus for funksjonsgjennomgang"
display_mode:
once: "Én gang"
@ -1381,7 +1385,7 @@
online_payment: "Is the online payment module active?"
invoices: "Is the invoicing module active?"
openlab: "Is the project sharing module (OpenLab) active?"
tracking_id_info_html: "<p>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 <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, remember to write it in your privacy policy, above.</p><p>The host name is also required to use Google Analytics. You can get it by clicking on the adjacent button. This last parameter is used elsewhere, please set it carefully.</p>"
tracking_id_info_html: "To enable the statistical tracking of the visits using Google Analytics V4, set your tracking ID here. It is in the form G-XXXXXX. Visit <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, a cookie will be created. Remember to write it down in your privacy policy, above."
tracking_id: "Tracking ID"
open_api_clients:
add_new_client: "Lage ny API-klient"
@ -1395,7 +1399,7 @@
client_name: "Klientens navn"
confirmation_required: "Confirmation required"
do_you_really_want_to_delete_this_open_api_client: "Do you really want to delete this OpenAPI client?"
do_you_really_want_to_revoke_this_open_api_access: "Do you really want to revoke this access ? It will erase and replace the current token."
do_you_really_want_to_revoke_this_open_api_access: "Do you really want to revoke this access? It will erase and replace the current token."
client_successfully_created: "Client successfully created."
client_successfully_updated: "Client successfully updated."
client_successfully_deleted: "Client successfully deleted."
@ -1595,7 +1599,7 @@
content: "Create and manage promotional coupons allowing to offer punctual discounts to their holders."
events:
welcome:
title: "Events"
title: "Arrangementer"
content: "Create events, track their reservations and organize them from this page."
list:
title: "The events"

View File

@ -15,7 +15,7 @@ pt:
trainings: "Treinamentos"
machines: "Máquinas"
spaces: "Espaços"
events: "Eventos"
events: "Events"
availabilities: "Disponíveis"
availabilities_notice: "Exportar para Excel livro com todos os slots disponíveis para reserva, e suas ocupações."
info: "Informações"
@ -24,7 +24,7 @@ pt:
ongoing_reservations: "Reservas em curso"
without_reservation: "Sem reservas"
confirmation_required: "Confirmação Obrigatória"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Você realmente deseja cancelar a reserva do usuário {USER}, em {DATE} ás {TIME}, sobre {RESERVATION}?"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Realmente deseja cancelar a reserva do usuário {USER}, em {DATE} ás {TIME}, sobre {RESERVATION}?"
reservation_was_successfully_cancelled: "A reserva foi cancelada com sucesso"
reservation_cancellation_failed: "Cancelamento da reserva falhou."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "Não é possível remover a última máquina do slot. Delete o slot primeiramente."
@ -271,7 +271,7 @@ pt:
events_edit:
edit_the_event: "Editar evento"
confirmation_required: "Confirmação obrigatória"
edit_recurring_event: "Você está prestes a atualizar um evento periódico. O que você quer atualizar ?"
edit_recurring_event: "Você está prestes a atualizar um evento periódico. O que você quer atualizar?"
edit_this_event: "Apenas este evento"
edit_this_and_next: "Este evento e os seguintes"
edit_all: "Todos eventos"
@ -322,10 +322,10 @@ pt:
none: "Vazio" #grammar concordance with training.
an_error_occurred_while_saving_the_number_of_credits: "Um erro ocorreu enquanto era salvo o número de créditos."
an_error_occurred_while_deleting_credit_with_the_TRAINING: "Um erro ocorreu enquanto o crédito era deletado do {TRAINING}."
an_error_occurred_unable_to_find_the_credit_to_revoke: "Um erro ocorreu : incapaz de encontrar o crédito para revogar."
an_error_occurred_unable_to_find_the_credit_to_revoke: "An error occurred: unable to find the credit to revoke."
an_error_occurred_while_creating_credit_with_the_TRAINING: "Ocorreu um erro ao criar o crédito com o {TRAINING}."
not_set: "Não definido"
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Erro : um link de crédito entre esta máquina e esta assinatura já existe."
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Erro: uma conexão de crédito entre esta máquina e esta assinatura já existe."
changes_have_been_successfully_saved: "As modificações foram salvas com sucesso."
credit_was_successfully_saved: "Crédito salvo com sucesso."
error_creating_credit: "Não foi possível criar crédito, um erro ocorreu"
@ -673,6 +673,10 @@ pt:
general_space_code: "Código de contabilidade para todos os espaços"
accounting_Space_label: "Rótulo de espaços"
general_space_label: "Rótulo de conta para todos os espaços"
accounting_Pack_code: "Prepaid-pack code"
general_pack_code: "Accounting code for prepaid-packs"
accounting_Pack_label: "Prepaid-pack label"
general_pack_label: "Account label for prepaid-packs"
accounting_Error_code: "Código do erro"
general_error_code: "Código de contabilidade para faturas erradas"
accounting_Error_label: "Rótulo dos erros"
@ -983,7 +987,7 @@ pt:
#add a new administrator to the platform
admins_new:
add_an_administrator: "Adicionar administrador"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Administrator criado com sucesso. {GENDER, select, female{Ela} other{Ele}} receberá {GENDER, select, female{sua} other{seu}} diretivas de conexão por e-mail."
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Successful creation. Connection directives were sent to the new administrator by e-mail."
failed_to_create_admin: "Não é possível criar administrador:"
man: "Homem"
woman: "Mulher"
@ -1001,7 +1005,7 @@ pt:
#add a new manager to the platform
manager_new:
add_a_manager: "Adicionar Gestor"
manager_successfully_created: "Gerente criado com sucesso. {GENDER, select, female{Ela} other{Ele}} receberá {GENDER, select, female{Suas diretrizes de conexão por e-mail} other{Suas diretrizes de conexão por e-mail}}"
manager_successfully_created: "Successful creation. Connection directives were sent to the new manager by e-mail."
failed_to_create_manager: "Não foi possível criar o gerente:"
man: "Homem"
woman: "Mulher"
@ -1032,7 +1036,7 @@ pt:
oauth2_provider_successfully_added: "Provedor OAuth 2.0 adicionado com sucesso."
#edit an authentication provider (SSO)
authentication_edit:
provider: "Provedor :"
provider: "Provedor:"
it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider: "É necessário definir a correspondência entre User.uid ea API para adicionar este fornecedor."
provider_successfully_updated: "Provedor modificado com sucesso."
an_error_occurred_unable_to_update_the_provider: "Um erro ocorreu: não é possível atualizar provedor."
@ -1322,7 +1326,7 @@ pt:
public_registrations_allowed: "Public registrations allowed"
help: "Ajuda"
feature_tour: "Tour de recursos"
feature_tour_info_html: "<p>Quando um administrador ou um gerente está logado, um tour de recurso será acionado na primeira vez que ele/ela visita cada seção do aplicativo. Você pode mudar esse comportamento para um dos seguintes valores:</p><ul><li>« Uma vez » para manter o comportamento padrão.</li><li>« Por sessão » para exibir os tours cada vez que você reabrir o aplicativo.</li><li>« Ativação manual » para evitar a exibição automática dos tours. Ainda será possível ativá-los pressionando a tecla F1 ou clicando em « Ajuda » no menu do usuário.</li></ul>"
feature_tour_info_html: "<p>Quando um administrador ou um gerente está logado, um tour de recurso será acionado na primeira vez que ele visita cada seção do aplicativo. Você pode mudar esse comportamento para um dos seguintes valores:</p><ul><li>« Uma vez » para manter o comportamento padrão.</li><li>« Por sessão » para exibir os tours cada vez que você reabrir o aplicativo.</li><li>« Ativação manual » para evitar a exibição automática dos tours. Ainda será possível ativá-los pressionando a tecla F1 ou clicando em « Ajuda » no menu do usuário.</li></ul>"
feature_tour_display_mode: "Modo de exibição de recursos do tour"
display_mode:
once: "Uma vez"
@ -1381,7 +1385,7 @@ pt:
online_payment: "O módulo de pagamento online está ativo?"
invoices: "O módulo de faturação está ativo?"
openlab: "O módulo de compartilhamento de projetos (OpenLab) está ativo?"
tracking_id_info_html: "<p>Para ativar o rastreamento estatístico das visitas usando o Google Analytics, defina seu ID de rastreamento aqui. Está na forma de UA-000000-2. Visite <a href='https://analytics.google.com/analytics/web/' target='_blank'>o site do Google Analytics</a> para obter um.<br/><strong>Aviso:</strong> se você ativar este recurso, lembre-se de escrevê-lo na sua política de privacidade.</p><p>O nome do host também é necessário para usar o Google Analytics. Você pode obtê-lo clicando no botão adjacente. Este último parâmetro é usado em outro lugar, por favor, defina-o com cuidado.</p>"
tracking_id_info_html: "Para ativar o rastreamento estatístico das visitas usando o Google Analytics, defina seu ID de rastreamento aqui. Está na forma de G-XXXXXX. Visite <a href='https://analytics.google.com/analytics/web/' target='_blank'>o site do Google Analytics</a> para obter um.<br/><strong>Aviso:</strong> se você ativar este recurso, um cookie será criado. Lembre-se de escrevê-lo na sua política de privacidade."
tracking_id: "ID de rastreamento"
open_api_clients:
add_new_client: "Criar novo cliente de API"

View File

@ -15,7 +15,7 @@ zu:
trainings: "crwdns6709:0crwdne6709:0"
machines: "crwdns6711:0crwdne6711:0"
spaces: "crwdns6713:0crwdne6713:0"
events: "crwdns6715:0crwdne6715:0"
events: "crwdns22406:0crwdne22406:0"
availabilities: "crwdns6717:0crwdne6717:0"
availabilities_notice: "crwdns6719:0crwdne6719:0"
info: "crwdns20468:0crwdne20468:0"
@ -24,7 +24,7 @@ zu:
ongoing_reservations: "crwdns6721:0crwdne6721:0"
without_reservation: "crwdns20326:0crwdne20326:0"
confirmation_required: "crwdns6725:0crwdne6725:0"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "crwdns20296:0GENDER={GENDER}crwdnd20296:0USER={USER}crwdnd20296:0DATE={DATE}crwdnd20296:0TIME={TIME}crwdnd20296:0RESERVATION={RESERVATION}crwdne20296:0"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "crwdns22408:0{USER}crwdnd22408:0{DATE}crwdnd22408:0{TIME}crwdnd22408:0{RESERVATION}crwdne22408:0"
reservation_was_successfully_cancelled: "crwdns6729:0crwdne6729:0"
reservation_cancellation_failed: "crwdns6731:0crwdne6731:0"
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "crwdns6733:0crwdne6733:0"
@ -271,7 +271,7 @@ zu:
events_edit:
edit_the_event: "crwdns7095:0crwdne7095:0"
confirmation_required: "crwdns19784:0crwdne19784:0"
edit_recurring_event: "crwdns19786:0crwdne19786:0"
edit_recurring_event: "crwdns22410:0crwdne22410:0"
edit_this_event: "crwdns19788:0crwdne19788:0"
edit_this_and_next: "crwdns19790:0crwdne19790:0"
edit_all: "crwdns19792:0crwdne19792:0"
@ -322,10 +322,10 @@ zu:
none: "crwdns19808:0crwdne19808:0" #grammar concordance with training.
an_error_occurred_while_saving_the_number_of_credits: "crwdns7173:0crwdne7173:0"
an_error_occurred_while_deleting_credit_with_the_TRAINING: "crwdns7175:0{TRAINING}crwdne7175:0"
an_error_occurred_unable_to_find_the_credit_to_revoke: "crwdns7177:0crwdne7177:0"
an_error_occurred_unable_to_find_the_credit_to_revoke: "crwdns22412:0crwdne22412:0"
an_error_occurred_while_creating_credit_with_the_TRAINING: "crwdns7179:0{TRAINING}crwdne7179:0"
not_set: "crwdns7181:0crwdne7181:0"
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "crwdns7183:0crwdne7183:0"
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "crwdns22414:0crwdne22414:0"
changes_have_been_successfully_saved: "crwdns7185:0crwdne7185:0"
credit_was_successfully_saved: "crwdns7187:0crwdne7187:0"
error_creating_credit: "crwdns7189:0crwdne7189:0"
@ -365,7 +365,7 @@ zu:
these_prices_match_space_hours_rates_html: "crwdns20480:0crwdne20480:0"
add_a_space_credit: "crwdns7259:0crwdne7259:0"
space: "crwdns7261:0crwdne7261:0"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "crwdns7263:0crwdne7263:0"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "crwdns22416:0crwdne22416:0"
status_enabled: "crwdns7265:0crwdne7265:0"
status_disabled: "crwdns7267:0crwdne7267:0"
status_all: "crwdns7269:0crwdne7269:0"
@ -482,7 +482,7 @@ zu:
no_invoices_for_now: "crwdns7337:0crwdne7337:0"
payment_schedules_list: "crwdns21058:0crwdne21058:0"
invoicing_settings: "crwdns7339:0crwdne7339:0"
warning_invoices_disabled: "crwdns7341:0crwdne7341:0"
warning_invoices_disabled: "crwdns22418:0crwdne22418:0"
change_logo: "crwdns7343:0crwdne7343:0"
john_smith: "crwdns7345:0crwdne7345:0"
john_smith_at_example_com: "crwdns7347:0crwdne7347:0"
@ -673,6 +673,10 @@ zu:
general_space_code: "crwdns7677:0crwdne7677:0"
accounting_Space_label: "crwdns7679:0crwdne7679:0"
general_space_label: "crwdns7681:0crwdne7681:0"
accounting_Pack_code: "crwdns22446:0crwdne22446:0"
general_pack_code: "crwdns22448:0crwdne22448:0"
accounting_Pack_label: "crwdns22450:0crwdne22450:0"
general_pack_label: "crwdns22452:0crwdne22452:0"
accounting_Error_code: "crwdns21470:0crwdne21470:0"
general_error_code: "crwdns21472:0crwdne21472:0"
accounting_Error_label: "crwdns21474:0crwdne21474:0"
@ -983,7 +987,7 @@ zu:
#add a new administrator to the platform
admins_new:
add_an_administrator: "crwdns8027:0crwdne8027:0"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "crwdns8029:0GENDER={GENDER}crwdnd8029:0GENDER={GENDER}crwdne8029:0"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "crwdns22420:0crwdne22420:0"
failed_to_create_admin: "crwdns8031:0crwdne8031:0"
man: "crwdns8033:0crwdne8033:0"
woman: "crwdns8035:0crwdne8035:0"
@ -1001,7 +1005,7 @@ zu:
#add a new manager to the platform
manager_new:
add_a_manager: "crwdns20348:0crwdne20348:0"
manager_successfully_created: "crwdns20350:0GENDER={GENDER}crwdnd20350:0GENDER={GENDER}crwdne20350:0"
manager_successfully_created: "crwdns22422:0crwdne22422:0"
failed_to_create_manager: "crwdns20352:0crwdne20352:0"
man: "crwdns20354:0crwdne20354:0"
woman: "crwdns20356:0crwdne20356:0"
@ -1032,7 +1036,7 @@ zu:
oauth2_provider_successfully_added: "crwdns8081:0crwdne8081:0"
#edit an authentication provider (SSO)
authentication_edit:
provider: "crwdns8083:0crwdne8083:0"
provider: "crwdns22424:0crwdne22424:0"
it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider: "crwdns20208:0crwdne20208:0"
provider_successfully_updated: "crwdns20210:0crwdne20210:0"
an_error_occurred_unable_to_update_the_provider: "crwdns8089:0crwdne8089:0"
@ -1322,7 +1326,7 @@ zu:
public_registrations_allowed: "crwdns22283:0crwdne22283:0"
help: "crwdns20764:0crwdne20764:0"
feature_tour: "crwdns20766:0crwdne20766:0"
feature_tour_info_html: "crwdns20768:0crwdne20768:0"
feature_tour_info_html: "crwdns22426:0crwdne22426:0"
feature_tour_display_mode: "crwdns20770:0crwdne20770:0"
display_mode:
once: "crwdns20772:0crwdne20772:0"
@ -1381,7 +1385,7 @@ zu:
online_payment: "crwdns19892:0crwdne19892:0"
invoices: "crwdns19894:0crwdne19894:0"
openlab: "crwdns19896:0crwdne19896:0"
tracking_id_info_html: "crwdns20812:0crwdne20812:0"
tracking_id_info_html: "crwdns22442:0crwdne22442:0"
tracking_id: "crwdns20814:0crwdne20814:0"
open_api_clients:
add_new_client: "crwdns8443:0crwdne8443:0"
@ -1395,7 +1399,7 @@ zu:
client_name: "crwdns8459:0crwdne8459:0"
confirmation_required: "crwdns8461:0crwdne8461:0"
do_you_really_want_to_delete_this_open_api_client: "crwdns8463:0crwdne8463:0"
do_you_really_want_to_revoke_this_open_api_access: "crwdns8465:0crwdne8465:0"
do_you_really_want_to_revoke_this_open_api_access: "crwdns22428:0crwdne22428:0"
client_successfully_created: "crwdns8467:0crwdne8467:0"
client_successfully_updated: "crwdns8469:0crwdne8469:0"
client_successfully_deleted: "crwdns8471:0crwdne8471:0"

View File

@ -165,6 +165,7 @@ de:
openlab_search_not_available_at_the_moment: "Suche über das gesamte Netzwerk ist derzeit nicht verfügbar. Sie können nach Projekten auf dieser Plattform suchen."
project_search_result_is_empty: "Leider haben wir keine Ergebnisse gefunden, die Ihren Suchkriterien entsprechen."
reset_all_filters: "Alle Filter zurücksetzen"
keywords: "Schlüsselwörter"
search: "Suche"
all_projects: "Alle Projekte"
my_projects: "Meine Projekte"
@ -251,9 +252,9 @@ de:
no_plans: "Für Ihre Gruppe sind keine Pläne verfügbar"
AMOUNT_per_month: "{AMOUNT} / monate"
my_group: "Meine Gruppe"
his_group: "{GENDER, select, male{Seine} female{Ihre} other{Seine}} Gruppe"
he_wants_to_change_group: "{ROLE, select, member{Ich möchte} other{Der Benutzer möchte}} die Gruppe wechseln"
change_my_group: "Ändere {ROLE, select, member{meine} other{{GENDER, select, male{seine} female{ihre} other{seine}}}} Gruppe"
his_group: "User's group"
he_wants_to_change_group: "Change group"
change_my_group: "Validate group change"
summary: "Zusammenfassung"
your_subscription_has_expired_on_the_DATE: "Ihr Abonnement ist am {DATE} abgelaufen"
subscription_price: "Abonnementspreis"

View File

@ -165,6 +165,7 @@ en:
openlab_search_not_available_at_the_moment: "Search over the whole network is not available at the moment. You still can search over the projects of this platform."
project_search_result_is_empty: "Sorry, we found no results matching your search criteria."
reset_all_filters: "Reset all filters"
keywords: "Keywords"
search: "Search"
all_projects: "All projects"
my_projects: "My projects"
@ -251,9 +252,9 @@ en:
no_plans: "No plans are available for your group"
AMOUNT_per_month: "{AMOUNT} / month"
my_group: "My group"
his_group: "{GENDER, select, male{His} female{Her} other{Its}} group"
he_wants_to_change_group: "{ROLE, select, member{I want} other{The user wants}} to change group"
change_my_group: "Change {ROLE, select, member{my} other{{GENDER, select, male{his} female{her} other{its}}}} group"
his_group: "User's group"
he_wants_to_change_group: "Change group"
change_my_group: "Validate group change"
summary: "Summary"
your_subscription_has_expired_on_the_DATE: "Your subscription has expired on the {DATE}"
subscription_price: "Subscription price"

View File

@ -165,6 +165,7 @@ es:
openlab_search_not_available_at_the_moment: "La busqueda en toda la red no está disponible en este momento. Puede seguir buscando proyectos en este FabLab."
project_search_result_is_empty: "Lo sentimos, no hemos encontrado nada."
reset_all_filters: "Limpiar filtros"
keywords: "Keywords"
search: "Buscar"
all_projects: "Todos los proyectos"
my_projects: "Mis proyectos"
@ -251,9 +252,9 @@ es:
no_plans: "No plans are available for your group"
AMOUNT_per_month: "{AMOUNT} / month"
my_group: "My grupo"
his_group: "{GENDER, select, male{His} female{Her} other{Its}} group"
he_wants_to_change_group: "{ROLE, select, member{Quiero} other{El usuario quiere}} cambiar el grupo"
change_my_group: "Cambiar {ROLE, select, member{mi} other{{GENDER, select, other{su}}}} grupo"
his_group: "User's group"
he_wants_to_change_group: "Change group"
change_my_group: "Validate group change"
summary: "Summary"
your_subscription_has_expired_on_the_DATE: "Sus suscripcion expiró el {DATE}"
subscription_price: "Subscription price"

View File

@ -165,6 +165,7 @@ fr:
openlab_search_not_available_at_the_moment: "La recherche sur tout le réseau n'est pas disponible pour le moment. Vous pouvez cependant effectuer une recherche parmi les projets de cette plateforme."
project_search_result_is_empty: "Il n'y a pas de projets correspondant à vos critères de recherche."
reset_all_filters: "Réinitialiser tous les filtres"
keywords: "Mots-clés"
search: "Rechercher"
all_projects: "Tous les projets"
my_projects: "Mes projets"
@ -251,9 +252,9 @@ fr:
no_plans: "Aucun abonnement n'est disponible pour votre groupe"
AMOUNT_per_month: "{AMOUNT} / mois"
my_group: "Mon groupe"
his_group: "Son groupe"
he_wants_to_change_group: "{ROLE, select, member{Je veux} other{L'utilisateur veut}} changer de groupe"
change_my_group: "Changer {ROLE, select, member{mon} other{{GENDER, select, other{son}}}} groupe"
his_group: "Groupe de l'utilisateur"
he_wants_to_change_group: "Changer de groupe"
change_my_group: "Valider le changement"
summary: "Résumé"
your_subscription_has_expired_on_the_DATE: "Votre abonnement a expiré au {DATE}"
subscription_price: "Coût de l'abonnement"

View File

@ -165,6 +165,7 @@
openlab_search_not_available_at_the_moment: "Det er ikke mulig å søke over hele nettverket for øyeblikket. Du kan fortsatt søke over prosjektene her."
project_search_result_is_empty: "Beklager, fant vi ingen resultater som samsvarte med dine søkekriterier."
reset_all_filters: "Tilbakestill alle filtre"
keywords: "Keywords"
search: "Søk"
all_projects: "Alle prosjekter"
my_projects: "Mine prosjekter"
@ -251,9 +252,9 @@
no_plans: "Ingen planer er tilgjengelige for din gruppe"
AMOUNT_per_month: "{AMOUNT} / måned"
my_group: "Min gruppe"
his_group: "Gruppen"
he_wants_to_change_group: "{ROLE, select, member{Jeg vil} other{Brukeren vil}} endre gruppe"
change_my_group: "Endre {ROLE, select, member{min} other{{GENDER, select, male{hans} female{henne} other{den! den}}}} gruppe"
his_group: "User's group"
he_wants_to_change_group: "Change group"
change_my_group: "Validate group change"
summary: "Sammendrag"
your_subscription_has_expired_on_the_DATE: "Ditt abonnement har utløpt {DATE}"
subscription_price: "Pris, medlemskap/abonnement"

View File

@ -165,6 +165,7 @@ pt:
openlab_search_not_available_at_the_moment: "A busca em toda a rede de FabLabs não está disponível no momento. Você pode procurar por projetos nesta plataforma."
project_search_result_is_empty: "Desculpe, nós não achamos nenhum resultado para sua pesquisa."
reset_all_filters: "Resetar todos os filtros"
keywords: "Keywords"
search: "Procurar"
all_projects: "Todos os projetos"
my_projects: "Meus Projetos"
@ -251,9 +252,9 @@ pt:
no_plans: "Não há planos disponíveis para o seu grupo"
AMOUNT_per_month: "{AMOUNT} / meses"
my_group: "Meu grupo"
his_group: "{GENDER, select, male{Ele} female{Ela} other{Esses}} grupo"
he_wants_to_change_group: "{ROLE, select, member{Eu quero} other{O usuário quer}} trocar de grupo"
change_my_group: "Mudar {ROLE, select, member{meu} other{{GENDER, select, other{seu}}}} grupo"
his_group: "User's group"
he_wants_to_change_group: "Change group"
change_my_group: "Validate group change"
summary: "Sumário"
your_subscription_has_expired_on_the_DATE: "Sua inscrição expirou em {DATE}"
subscription_price: "Preço da assinatura"

View File

@ -165,6 +165,7 @@ zu:
openlab_search_not_available_at_the_moment: "crwdns9045:0crwdne9045:0"
project_search_result_is_empty: "crwdns9047:0crwdne9047:0"
reset_all_filters: "crwdns9049:0crwdne9049:0"
keywords: "crwdns22404:0crwdne22404:0"
search: "crwdns9051:0crwdne9051:0"
all_projects: "crwdns9053:0crwdne9053:0"
my_projects: "crwdns9055:0crwdne9055:0"
@ -251,9 +252,9 @@ zu:
no_plans: "crwdns20912:0crwdne20912:0"
AMOUNT_per_month: "crwdns21052:0{AMOUNT}crwdne21052:0"
my_group: "crwdns9181:0crwdne9181:0"
his_group: "crwdns9183:0GENDER={GENDER}crwdne9183:0"
he_wants_to_change_group: "crwdns20396:0ROLE={ROLE}crwdne20396:0"
change_my_group: "crwdns20398:0ROLE={ROLE}crwdnd20398:0GENDER={GENDER}crwdne20398:0"
his_group: "crwdns22430:0crwdne22430:0"
he_wants_to_change_group: "crwdns22432:0crwdne22432:0"
change_my_group: "crwdns22434:0crwdne22434:0"
summary: "crwdns9189:0crwdne9189:0"
your_subscription_has_expired_on_the_DATE: "crwdns9191:0{DATE}crwdne9191:0"
subscription_price: "crwdns9193:0crwdne9193:0"

View File

@ -267,6 +267,7 @@ de:
obtain_it_when_registering_with_your_provider: "Wird während der Registrierung bei Ihrem Provider erhalten."
client_secret: "Client-Geheimnis"
oauth2_client_secret_is_required: "OAuth 2.0 Client-Geheimnis ist erforderlich."
scopes: "Scopes"
define_the_fields_mapping: "Definieren Sie die Zuordnung der Felder"
add_a_match: "Fügen Sie eine Zuordnung hinzu"
model: "Modell"

View File

@ -267,6 +267,7 @@ en:
obtain_it_when_registering_with_your_provider: "Obtain it when registering with your provider."
client_secret: "Client secret"
oauth2_client_secret_is_required: "OAuth 2.0 client secret is required."
scopes: "Scopes"
define_the_fields_mapping: "Define the fields mapping"
add_a_match: "Add a match"
model: "Model"
@ -423,7 +424,7 @@ en:
confirm_and_pay: "Confirm and pay"
you_have_settled_the_following_TYPE: "You have settled the following {TYPE, select, Machine{machine slots} Training{training} other{elements}}:"
you_have_settled_a_: "You have settled a"
total_: "TOTAL :"
total_: "TOTAL:"
thank_you_your_payment_has_been_successfully_registered: "Thank you. Your payment has been successfully registered !"
your_invoice_will_be_available_soon_from_your_: "Your invoice will be available soon form your"
dashboard: "Dashboard"

View File

@ -267,6 +267,7 @@ es:
obtain_it_when_registering_with_your_provider: "Obtengalo al registrarse con su proveedor."
client_secret: "Secreto del cliente"
oauth2_client_secret_is_required: "Se requiere el secreto de cliente OAuth 2.0."
scopes: "Scopes"
define_the_fields_mapping: "Definir el mapeo de campos"
add_a_match: "agregar coincidencia"
model: "Model"
@ -423,7 +424,7 @@ es:
confirm_and_pay: "Confirmar y pagar"
you_have_settled_the_following_TYPE: "Acaba de seleccionar {TYPE, select, Machine{machine slots} Training{training} other{elements}}:"
you_have_settled_a_: "Ha establecido una"
total_: "TOTAL :"
total_: "TOTAL:"
thank_you_your_payment_has_been_successfully_registered: "Gracias. Su pago se ha registrado con éxito."
your_invoice_will_be_available_soon_from_your_: "Su factura pronto estará disponible"
dashboard: "Panel"

View File

@ -267,6 +267,7 @@ fr:
obtain_it_when_registering_with_your_provider: "Enregistrez-vous auprès du fournisseur pour l'obtenir."
client_secret: "Secret client"
oauth2_client_secret_is_required: "Le secret client OAuth 2 est requis."
scopes: "Portée de lautorisation"
define_the_fields_mapping: "Définir la correspondance des champs"
add_a_match: "Ajouter une correspondance"
model: "Modèle"

View File

@ -267,6 +267,7 @@
obtain_it_when_registering_with_your_provider: "Få det når du registrerer deg hos leverandøren din."
client_secret: "Klienthemmelighet"
oauth2_client_secret_is_required: "OAuth 2.0 klient-hemmelighet er nødvendig."
scopes: "Scopes"
define_the_fields_mapping: "Definer tilordning av felter"
add_a_match: "Legg til en match"
model: "Modell"
@ -423,7 +424,7 @@
confirm_and_pay: "Bekreft og betal"
you_have_settled_the_following_TYPE: "Du har betalt for følgende {TYPE, select, Machine{maskinplasser} Training{opplæring/kurs} other{elementer}}:"
you_have_settled_a_: "Du har gjort opp en"
total_: "TOTALT :"
total_: "TOTALT:"
thank_you_your_payment_has_been_successfully_registered: "Tusen takk, betalingen din er registrert!"
your_invoice_will_be_available_soon_from_your_: "Din faktura vil snart være tilgjengelig"
dashboard: "Kontrollpanel"

View File

@ -267,6 +267,7 @@ pt:
obtain_it_when_registering_with_your_provider: "Obtenha-o ao se registrar no seu provedor."
client_secret: "Chave secreta"
oauth2_client_secret_is_required: "A senha do cliente OAuth 2.0 é necessário."
scopes: "Scopes"
define_the_fields_mapping: "Defina o mapeamento dos campos"
add_a_match: "Adicionar uma correspondência"
model: "Modelo"
@ -423,7 +424,7 @@ pt:
confirm_and_pay: "Confirmar e pagar"
you_have_settled_the_following_TYPE: "Você liquidou o seguinte {TYPE, select, Machine{slots de máquina} Training{training} other{elements}}:"
you_have_settled_a_: "Você tem liquidado:"
total_: "TOTAL :"
total_: "TOTAL:"
thank_you_your_payment_has_been_successfully_registered: "Obrigado. Seu pagamento foi registrado com sucesso !"
your_invoice_will_be_available_soon_from_your_: "Sua fatura estará disponível em breve"
dashboard: "Painel de controle"

View File

@ -267,6 +267,7 @@ zu:
obtain_it_when_registering_with_your_provider: "crwdns9801:0crwdne9801:0"
client_secret: "crwdns9803:0crwdne9803:0"
oauth2_client_secret_is_required: "crwdns9805:0crwdne9805:0"
scopes: "crwdns22444:0crwdne22444:0"
define_the_fields_mapping: "crwdns9807:0crwdne9807:0"
add_a_match: "crwdns9809:0crwdne9809:0"
model: "crwdns9811:0crwdne9811:0"
@ -423,7 +424,7 @@ zu:
confirm_and_pay: "crwdns10057:0crwdne10057:0"
you_have_settled_the_following_TYPE: "crwdns10059:0TYPE={TYPE}crwdne10059:0"
you_have_settled_a_: "crwdns10061:0crwdne10061:0"
total_: "crwdns10063:0crwdne10063:0"
total_: "crwdns22436:0crwdne22436:0"
thank_you_your_payment_has_been_successfully_registered: "crwdns10065:0crwdne10065:0"
your_invoice_will_be_available_soon_from_your_: "crwdns10067:0crwdne10067:0"
dashboard: "crwdns10069:0crwdne10069:0"

View File

@ -268,9 +268,9 @@ de:
notify_admin_subscription_will_expire_in_7_days:
USER_s_subscription_will_expire_in_7_days: "Das Abonnement von %{USER} wird in 7 Tagen ablaufen."
notify_admin_user_group_changed:
user_NAME_changed_his_group_html: "Benutzer <strong><em>{NAME}</strong></em> hat {GENDER, select, true{seine} other{ihre}} Gruppe geändert." #messageFormat interpolation
user_NAME_changed_his_group_html: "User <strong><em>{NAME}</strong></em> changed group." #messageFormat interpolation
notify_admin_user_merged:
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "Nutzer <strong><em>{NAME}</strong></em> hat {GENDER, select, true{seinen} other{ihren}} Account mit dem von <strong><em>{PROVIDER} </strong> ({UID})</em> importierten Account zusammengeführt." #messageFormat interpolation
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "<strong><em>{NAME}</strong></em>'s account was merged with the one imported from <strong><em>{PROVIDER} </strong> ({%UID})</em>." #messageFormat interpolation
notify_admin_when_project_published:
project_NAME_has_been_published_html: "Projekt <a href='/#!/projects/%{ID}'><strong><em>%{NAME}<em></strong></a> wurde veröffentlicht."
notify_admin_when_user_is_created:

View File

@ -268,9 +268,9 @@ en:
notify_admin_subscription_will_expire_in_7_days:
USER_s_subscription_will_expire_in_7_days: "%{USER}'s subscription will expire in 7 days."
notify_admin_user_group_changed:
user_NAME_changed_his_group_html: "User <strong><em>{NAME}</strong></em> changed {GENDER, select, true{his} other{her}} group." #messageFormat interpolation
user_NAME_changed_his_group_html: "User <strong><em>{NAME}</strong></em> changed group." #messageFormat interpolation
notify_admin_user_merged:
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "User <strong><em>{NAME}</strong></em> has merged {GENDER, select, true{his} other{her}} account with the one imported from <strong><em>{PROVIDER} </strong> ({UID})</em>." #messageFormat interpolation
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "<strong><em>{NAME}</strong></em>'s account was merged with the one imported from <strong><em>{PROVIDER} </strong> ({%UID})</em>." #messageFormat interpolation
notify_admin_when_project_published:
project_NAME_has_been_published_html: "Project <a href='/#!/projects/%{ID}'><strong><em>%{NAME}<em></strong></a> has been published."
notify_admin_when_user_is_created:

View File

@ -268,9 +268,9 @@ es:
notify_admin_subscription_will_expire_in_7_days:
USER_s_subscription_will_expire_in_7_days: "La suscripción de %{USER} expirará en 7 días."
notify_admin_user_group_changed:
user_NAME_changed_his_group_html: "El usuario <strong><em>{NAME}</strong></em> ha cambiado {GENDER, select, true{his} other{her}} el grupo." #messageFormat interpolation
user_NAME_changed_his_group_html: "User <strong><em>{NAME}</strong></em> changed group." #messageFormat interpolation
notify_admin_user_merged:
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "El usuario <strong><em>{NAME}</strong></em> se ha fusionado {GENDER, select, true{his} other{her}} con la cuenta importada desde <strong><em>{PROVIDER} </strong> ({UID})</em>." #messageFormat interpolation
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "<strong><em>{NAME}</strong></em>'s account was merged with the one imported from <strong><em>{PROVIDER} </strong> ({%UID})</em>." #messageFormat interpolation
notify_admin_when_project_published:
project_NAME_has_been_published_html: "Proyecto <a href='/#!/projects/%{ID}'><strong><em>%{NAME}<em></strong></a> ha sido publicado."
notify_admin_when_user_is_created:

View File

@ -270,7 +270,7 @@ fr:
notify_admin_user_group_changed:
user_NAME_changed_his_group_html: "L'utilisateur <strong><em>{NAME}</strong></em> a changé de groupe." #messageFormat interpolation
notify_admin_user_merged:
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "L'utilisateur <strong><em>{NAME}</strong></em> a fusionné son compte avec le compte importé depuis <strong><em>{PROVIDER} </strong> ({UID})</em>." #messageFormat interpolation
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "<strong><em>Le compte de {NAME}</strong></em> a été fusionné à celui importé de <strong><em>{PROVIDER} </strong> ({%UID})</em>." #messageFormat interpolation
notify_admin_when_project_published:
project_NAME_has_been_published_html: "Le projet <a href='/#!/projects/%{ID}'><strong><em>%{NAME}<em></strong></a> vient d'être publié."
notify_admin_when_user_is_created:

View File

@ -313,13 +313,13 @@ de:
body:
remember: "Gemäß dem Zahlungsplan von %{REFERENCE} wurde für %{DATE} eine Belastung der Karte in Höhe von %{AMOUNT} geplant."
error: "Leider konnte die Abbuchung über die Karte nicht erfolgreich abgeschlossen werden."
action: "Bitte kontaktieren Sie das Mitglied so bald wie möglich und lösen Sie dann das Problem in der Verwaltung der Zahlungsfristen. Nach etwa 24 Stunden wird das Kartenabonnement storniert."
action: "Please contact the member as soon as possible, then go to the payment schedule management interface to resolve the problem. After a certain period of time, the card subscription could be cancelled."
notify_member_payment_schedule_failed:
subject: "[URGENT] Kartenbelastungsfehler"
body:
remember: "Gemäß Ihrem Zahlungsplan von %{REFERENCE} wurde für %{DATE} eine Belastung der Karte in Höhe von %{AMOUNT} geplant."
error: "Leider konnte die Abbuchung über die Karte nicht erfolgreich abgeschlossen werden."
action_html: "Bitte überprüfen Sie %{DASHBOARD} oder kontaktieren Sie einen Manager innerhalb von 24 Stunden. Andernfalls kann Ihr Abonnement unterbrochen werden."
action_html: "Please check %{DASHBOARD} or contact a manager quickly, otherwise your subscription may be interrupted."
your_dashboard: "Ihr Dashboard"
notify_admin_payment_schedule_gateway_canceled:
subject: "[URGENT] Zahlungsplan vom Zahlungs-Gateway abgebrochen"

View File

@ -313,13 +313,13 @@ en:
body:
remember: "In accordance with the %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}."
error: "Unfortunately, this card debit was unable to complete successfully."
action: "Please contact the member as soon as possible, then go to the payment schedule management interface to resolve the problem. After about 24 hours, the card subscription will be cancelled."
action: "Please contact the member as soon as possible, then go to the payment schedule management interface to resolve the problem. After a certain period of time, the card subscription could be cancelled."
notify_member_payment_schedule_failed:
subject: "[URGENT] Card debit failure"
body:
remember: "In accordance with your %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}."
error: "Unfortunately, this card debit was unable to complete successfully."
action_html: "Please check %{DASHBOARD} or contact a manager before 24 hours, otherwise your subscription may be interrupted."
action_html: "Please check %{DASHBOARD} or contact a manager quickly, otherwise your subscription may be interrupted."
your_dashboard: "your dashboard"
notify_admin_payment_schedule_gateway_canceled:
subject: "[URGENT] Payment schedule canceled by the payment gateway"

View File

@ -313,13 +313,13 @@ es:
body:
remember: "In accordance with the %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}."
error: "Unfortunately, this card debit was unable to complete successfully."
action: "Please contact the member as soon as possible, then go to the payment schedule management interface to resolve the problem. After about 24 hours, the card subscription will be cancelled."
action: "Please contact the member as soon as possible, then go to the payment schedule management interface to resolve the problem. After a certain period of time, the card subscription could be cancelled."
notify_member_payment_schedule_failed:
subject: "[URGENT] Card debit failure"
body:
remember: "In accordance with your %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}."
error: "Unfortunately, this card debit was unable to complete successfully."
action_html: "Please check %{DASHBOARD} or contact a manager before 24 hours, otherwise your subscription may be interrupted."
action_html: "Please check %{DASHBOARD} or contact a manager quickly, otherwise your subscription may be interrupted."
your_dashboard: "your dashboard"
notify_admin_payment_schedule_gateway_canceled:
subject: "[URGENT] Payment schedule canceled by the payment gateway"

View File

@ -313,13 +313,13 @@ fr:
body:
remember: "Conformément à l'échéancier de paiement %{REFERENCE}, un prélèvement par carte de %{AMOUNT} était prévu le %{DATE}."
error: "Malheureusement, ce prélèvement n'a pas pu être effectué correctement."
action: "Veuillez vous mettre en relation avec le membre au plus tôt, puis vous rendre dans l'interface de gestion des échéanciers afin de régler le problème. Au delà d'environ 24 heures, l'abonnement par carte bancaire sera annulé."
action: "Veuillez vous mettre en relation avec le membre au plus tôt, puis vous rendre dans l'interface de gestion des échéanciers afin de régler le problème. Au delà d'un certain délai, l'abonnement par carte bancaire pourrait être annulé."
notify_member_payment_schedule_failed:
subject: "[URGENT] Échec du prélèvement par carte"
body:
remember: "Conformément à votre échéancier de paiement %{REFERENCE}, un prélèvement par carte de %{AMOUNT} était prévu le %{DATE}."
error: "Malheureusement, ce prélèvement n'a pas pu être effectué correctement."
action_html: "Veuillez vous rendre dans %{DASHBOARD} ou prendre contact avec un gestionnaire sous 24 heures, faute de quoi votre abonnement risque d'être interrompu."
action_html: "Veuillez vous rendre dans %{DASHBOARD} ou prendre contact avec un gestionnaire rapidement, faute de quoi votre abonnement risque d'être interrompu."
your_dashboard: "votre tableau de bord"
notify_admin_payment_schedule_gateway_canceled:
subject: "[URGENT] Échéancier de paiement annulé par la passerelle de paiement"

View File

@ -313,13 +313,13 @@
body:
remember: "In accordance with the %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}."
error: "Unfortunately, this card debit was unable to complete successfully."
action: "Please contact the member as soon as possible, then go to the payment schedule management interface to resolve the problem. After about 24 hours, the card subscription will be cancelled."
action: "Please contact the member as soon as possible, then go to the payment schedule management interface to resolve the problem. After a certain period of time, the card subscription could be cancelled."
notify_member_payment_schedule_failed:
subject: "[URGENT] Card debit failure"
body:
remember: "In accordance with your %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}."
error: "Unfortunately, this card debit was unable to complete successfully."
action_html: "Please check %{DASHBOARD} or contact a manager before 24 hours, otherwise your subscription may be interrupted."
action_html: "Please check %{DASHBOARD} or contact a manager quickly, otherwise your subscription may be interrupted."
your_dashboard: "your dashboard"
notify_admin_payment_schedule_gateway_canceled:
subject: "[URGENT] Payment schedule canceled by the payment gateway"

View File

@ -313,13 +313,13 @@ pt:
body:
remember: "De acordo com o calendário de pagamento de %{REFERENCE}, um débito por cartão de %{AMOUNT} foi agendado em %{DATE}."
error: "Infelizmente, não foi possível completar o débito no cartão com sucesso."
action: "Por favor, entre em contato com o membro assim que possível, depois vá à interface de gestão de horários de pagamento para resolver o problema. Após cerca de 24 horas, a assinatura do cartão será cancelada."
action: "Please contact the member as soon as possible, then go to the payment schedule management interface to resolve the problem. After a certain period of time, the card subscription could be cancelled."
notify_member_payment_schedule_failed:
subject: "[URGENT] Falha no débito do cartão"
body:
remember: "De acordo com a sua agenda de pagamentos %{REFERENCE}, um débito por cartão de %{AMOUNT} foi agendado para %{DATE}."
error: "Infelizmente, não foi possível completar o débito no cartão com sucesso."
action_html: "Por favor, verifique %{DASHBOARD} ou entre em contato com um gerente antes de 24 horas, caso contrário sua assinatura pode ser interrompida."
action_html: "Please check %{DASHBOARD} or contact a manager quickly, otherwise your subscription may be interrupted."
your_dashboard: "seu dashboard"
notify_admin_payment_schedule_gateway_canceled:
subject: "[URGENT] Payment schedule canceled by the payment gateway"

View File

@ -313,13 +313,13 @@ zu:
body:
remember: "crwdns21134:0%{REFERENCE}crwdnd21134:0%{AMOUNT}crwdnd21134:0%{DATE}crwdne21134:0"
error: "crwdns21136:0crwdne21136:0"
action: "crwdns21138:0crwdne21138:0"
action: "crwdns22400:0crwdne22400:0"
notify_member_payment_schedule_failed:
subject: "crwdns21140:0[URGENT]crwdne21140:0"
body:
remember: "crwdns21142:0%{REFERENCE}crwdnd21142:0%{AMOUNT}crwdnd21142:0%{DATE}crwdne21142:0"
error: "crwdns21144:0crwdne21144:0"
action_html: "crwdns21146:0%{DASHBOARD}crwdne21146:0"
action_html: "crwdns22402:0%{DASHBOARD}crwdne22402:0"
your_dashboard: "crwdns21148:0crwdne21148:0"
notify_admin_payment_schedule_gateway_canceled:
subject: "crwdns22389:0[URGENT]crwdne22389:0"

View File

@ -268,9 +268,9 @@
notify_admin_subscription_will_expire_in_7_days:
USER_s_subscription_will_expire_in_7_days: "%{USER} sitt abonnement utløper om 7 dager."
notify_admin_user_group_changed:
user_NAME_changed_his_group_html: "Bruker <strong><em>{NAME}</strong></em> har endret gruppe." #messageFormat interpolation
user_NAME_changed_his_group_html: "User <strong><em>{NAME}</strong></em> changed group." #messageFormat interpolation
notify_admin_user_merged:
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "Bruker <strong><em>{NAME}</strong></em> har slått sammen sin konto med den som er importert fra <strong><em>{PROVIDER} </strong> ({UID})</em>." #messageFormat interpolation
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "<strong><em>{NAME}</strong></em>'s account was merged with the one imported from <strong><em>{PROVIDER} </strong> ({%UID})</em>." #messageFormat interpolation
notify_admin_when_project_published:
project_NAME_has_been_published_html: "Prosjekt <a href='/#!/projects/%{ID}'><strong><em>%{NAME}<em></strong></a> har blitt publisert."
notify_admin_when_user_is_created:

View File

@ -268,9 +268,9 @@ pt:
notify_admin_subscription_will_expire_in_7_days:
USER_s_subscription_will_expire_in_7_days: "A assinatura do usuário %{USER} expira em 7 dias."
notify_admin_user_group_changed:
user_NAME_changed_his_group_html: "Usuário <strong><em>{NAME}</strong></em> mudou {GENDER, select, true{seu} other{seu}} grupo." #messageFormat interpolation
user_NAME_changed_his_group_html: "User <strong><em>{NAME}</strong></em> changed group." #messageFormat interpolation
notify_admin_user_merged:
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "Usuário <strong><em>{NAME}</strong></em> vinculou {GENDER, select, true{sua} other{sua}} conta com a importada de <strong> <em> {PROVIDER} </strong> ({UID}) </em>." #messageFormat interpolation
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "<strong><em>{NAME}</strong></em>'s account was merged with the one imported from <strong><em>{PROVIDER} </strong> ({%UID})</em>." #messageFormat interpolation
notify_admin_when_project_published:
project_NAME_has_been_published_html: "Projeto <a href='/#!/projects/%{ID}'><strong><em>%{NAME}<em></strong></a> foi publicado."
notify_admin_when_user_is_created:

View File

@ -268,9 +268,9 @@ zu:
notify_admin_subscription_will_expire_in_7_days:
USER_s_subscription_will_expire_in_7_days: "crwdns3577:0%{USER}crwdne3577:0"
notify_admin_user_group_changed:
user_NAME_changed_his_group_html: "crwdns3579:0NAME={NAME}crwdnd3579:0GENDER={GENDER}crwdne3579:0" #messageFormat interpolation
user_NAME_changed_his_group_html: "crwdns22438:0{NAME}crwdne22438:0" #messageFormat interpolation
notify_admin_user_merged:
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "crwdns3581:0NAME={NAME}crwdnd3581:0GENDER={GENDER}crwdnd3581:0PROVIDER={PROVIDER}crwdnd3581:0UID={UID}crwdne3581:0" #messageFormat interpolation
user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "crwdns22440:0{NAME}crwdnd22440:0{PROVIDER}crwdne22440:0" #messageFormat interpolation
notify_admin_when_project_published:
project_NAME_has_been_published_html: "crwdns3583:0%{ID}crwdnd3583:0%{NAME}crwdne3583:0"
notify_admin_when_user_is_created:

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'sidekiq_unique_jobs/web'
require 'sidekiq/cron/web'
require 'sidekiq-scheduler/web'
Rails.application.routes.draw do
if AuthProvider.active.providable_type == DatabaseProvider.name

View File

@ -1,51 +1,51 @@
subscription_expire_in_7_days:
cron: "0 0 * * *"
class: "SubscriptionExpireWorker"
class: SubscriptionExpireWorker
queue: default
args: [7]
subscription_is_expired:
cron: "0 23 * * *"
class: "SubscriptionExpireWorker"
class: SubscriptionExpireWorker
queue: default
args: [0]
generate_statistic:
cron: "0 1 * * *"
class: "StatisticWorker"
class: StatisticWorker
queue: default
i_calendar_import:
cron: "0 * * * *"
class: "ICalendarImportWorker"
class: ICalendarImportWorker
queue: default
reservation_reminder:
cron: "1 * * * *"
class: "ReservationReminderWorker"
class: ReservationReminderWorker
queue: default
close_period_reminder_worker:
cron: "0 12 * * 1" # every monday at 12pm
class: "ClosePeriodReminderWorker"
class: ClosePeriodReminderWorker
queue: default
free_disk_space:
cron: "0 5 * * 0" # every sunday at 5am
class: "FreeDiskSpaceWorker"
class: FreeDiskSpaceWorker
queue: system
# schedule a version check, every week at the current day+time
# this will prevent that all the instances query the hub simultaneously
<% m = DateTime.current.minute - 1; h = DateTime.current.hour; d = DateTime.current.cwday %>
<% h = DateTime.current - 1.minute %>
version_check:
cron: <%="#{m} #{h} * * #{d}" %>
class: 'VersionCheckWorker'
cron: <%="#{h.strftime('%M %H')} * * #{h.cwday}" %>
class: VersionCheckWorker
queue: system
payment_schedule_item:
cron: "0 * * * *" # every day, every hour
class: 'PaymentScheduleItemWorker'
class: PaymentScheduleItemWorker
queue: default
<%= PluginRegistry.insert_code('yml.schedule') %>

Some files were not shown because too many files have changed in this diff Show More