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

enable/disable statistics module fomr the UI

This commit is contained in:
Sylvain 2020-06-17 12:20:51 +02:00
parent d2b57b89b3
commit 40dd39304e
15 changed files with 111 additions and 36 deletions

View File

@ -121,12 +121,6 @@ Application.Controllers.controller('MainNavController', ['$scope', function ($sc
linkIcon: 'file-pdf-o', linkIcon: 'file-pdf-o',
authorizedRoles: ['admin', 'manager'] authorizedRoles: ['admin', 'manager']
}, },
{
state: 'app.admin.statistics',
linkText: 'app.public.common.statistics',
linkIcon: 'bar-chart-o',
authorizedRoles: ['admin']
},
{ {
class: 'menu-spacer', class: 'menu-spacer',
authorizedRoles: ['admin'] authorizedRoles: ['admin']
@ -154,11 +148,20 @@ Application.Controllers.controller('MainNavController', ['$scope', function ($sc
$scope.adminNavLinks = adminNavLinks; $scope.adminNavLinks = adminNavLinks;
if ($scope.modules.spaces) { if ($scope.modules.spaces) {
return $scope.adminNavLinks.splice(3, 0, { $scope.adminNavLinks.splice(3, 0, {
state: 'app.public.spaces_list', state: 'app.public.spaces_list',
linkText: 'app.public.common.manage_the_spaces', linkText: 'app.public.common.manage_the_spaces',
linkIcon: 'rocket' linkIcon: 'rocket'
}); });
} }
if ($scope.modules.statistics) {
$scope.adminNavLinks.splice($scope.modules.spaces ? 9 : 8, 0, {
state: 'app.admin.statistics',
linkText: 'app.public.common.statistics',
linkIcon: 'bar-chart-o',
authorizedRoles: ['admin']
});
}
} }
]); ]);

View File

@ -37,7 +37,7 @@ angular.module('application.router', ['ui.router'])
logoFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-file' }).$promise; }], logoFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-file' }).$promise; }],
logoBlackFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-black-file' }).$promise; }], logoBlackFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-black-file' }).$promise; }],
sharedTranslations: ['Translations', function (Translations) { return Translations.query(['app.shared', 'app.public.common']).$promise; }], sharedTranslations: ['Translations', function (Translations) { return Translations.query(['app.shared', 'app.public.common']).$promise; }],
modulesPromise: ['Setting', function (Setting) { return Setting.query({ names: "['spaces_module', 'plans_module', 'invoicing_module', 'wallet_module']" }).$promise; }] modulesPromise: ['Setting', function (Setting) { return Setting.query({ names: "['spaces_module', 'plans_module', 'invoicing_module', 'wallet_module', 'statistics_module']" }).$promise; }]
}, },
onEnter: ['$rootScope', 'logoFile', 'logoBlackFile', 'modulesPromise', 'CSRF', function ($rootScope, logoFile, logoBlackFile, modulesPromise, CSRF) { onEnter: ['$rootScope', 'logoFile', 'logoBlackFile', 'modulesPromise', 'CSRF', function ($rootScope, logoFile, logoBlackFile, modulesPromise, CSRF) {
// Retrieve Anti-CSRF tokens from cookies // Retrieve Anti-CSRF tokens from cookies
@ -50,6 +50,7 @@ angular.module('application.router', ['ui.router'])
plans: (modulesPromise.plans_module === 'true'), plans: (modulesPromise.plans_module === 'true'),
invoicing: (modulesPromise.invoicing_module === 'true'), invoicing: (modulesPromise.invoicing_module === 'true'),
wallet: (modulesPromise.wallet_module === 'true'), wallet: (modulesPromise.wallet_module === 'true'),
statistics: (modulesPromise.statistics_module === 'true')
}; };
}] }]
}) })
@ -993,6 +994,7 @@ angular.module('application.router', ['ui.router'])
// statistics // statistics
.state('app.admin.statistics', { .state('app.admin.statistics', {
url: '/admin/statistics', url: '/admin/statistics',
abstract: !Fablab.statisticsModule,
views: { views: {
'main@': { 'main@': {
templateUrl: '<%= asset_path "admin/statistics/index.html.erb" %>', templateUrl: '<%= asset_path "admin/statistics/index.html.erb" %>',
@ -1007,6 +1009,7 @@ angular.module('application.router', ['ui.router'])
}) })
.state('app.admin.stats_graphs', { .state('app.admin.stats_graphs', {
url: '/admin/statistics/evolution', url: '/admin/statistics/evolution',
abstract: !Fablab.statisticsModule,
views: { views: {
'main@': { 'main@': {
templateUrl: '<%= asset_path "admin/statistics/graphs.html" %>', templateUrl: '<%= asset_path "admin/statistics/graphs.html" %>',
@ -1036,7 +1039,7 @@ angular.module('application.router', ['ui.router'])
'booking_cancel_delay', 'main_color', 'secondary_color', 'spaces_module', 'twitter_analytics', \ 'booking_cancel_delay', 'main_color', 'secondary_color', 'spaces_module', 'twitter_analytics', \
'fablab_name', 'name_genre', 'reminder_enable', 'plans_module', 'confirmation_required', \ 'fablab_name', 'name_genre', 'reminder_enable', 'plans_module', 'confirmation_required', \
'reminder_delay', 'visibility_yearly', 'visibility_others', 'wallet_module', \ 'reminder_delay', 'visibility_yearly', 'visibility_others', 'wallet_module', \
'display_name_enable', 'machines_sort_by', 'fab_analytics', \ 'display_name_enable', 'machines_sort_by', 'fab_analytics', 'statistics_module', \
'link_name', 'home_content', 'home_css', 'phone_required']` }).$promise; 'link_name', 'home_content', 'home_css', 'phone_required']` }).$promise;
}], }],
privacyDraftsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'privacy_draft', history: true }).$promise; }], privacyDraftsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'privacy_draft', history: true }).$promise; }],

View File

@ -475,15 +475,25 @@
yes-label="app.shared.buttons.yes" yes-label="app.shared.buttons.yes"
no-label="app.shared.buttons.no"></boolean-setting> no-label="app.shared.buttons.no"></boolean-setting>
</div> </div>
<div class="row"> <div class="row">
<h3 class="m-l" translate>{{ 'app.admin.settings.general.wallet' }}</h3> <h3 class="m-l" translate>{{ 'app.admin.settings.general.wallet' }}</h3>
<p class="alert alert-warning m-h-md" ng-bind-html="'app.admin.settings.general.wallet_info_html' | translate"></p> <p class="alert alert-warning m-h-md" ng-bind-html="'app.admin.settings.general.wallet_info_html' | translate"></p>
<boolean-setting name="wallet_module" <boolean-setting name="wallet_module"
settings="allSettings" settings="allSettings"
label="app.admin.settings.general.enable_wallet" label="app.admin.settings.general.enable_wallet"
classes="m-l" classes="m-l"
yes-label="app.shared.buttons.yes" yes-label="app.shared.buttons.yes"
no-label="app.shared.buttons.no"></boolean-setting> no-label="app.shared.buttons.no"></boolean-setting>
</div> </div>
<div class="row">
<h3 class="m-l" translate>{{ 'app.admin.settings.general.statistics' }}</h3>
<p class="alert alert-warning m-h-md" ng-bind-html="'app.admin.settings.general.statistics_info_html' | translate"></p>
<boolean-setting name="statistics_module"
settings="allSettings"
label="app.admin.settings.general.enable_statistics"
classes="m-l"
yes-label="app.shared.buttons.yes"
no-label="app.shared.buttons.no"></boolean-setting>
</div>
</div> </div>
</div> </div>

View File

@ -104,7 +104,8 @@ class Setting < ApplicationRecord
stripe_currency stripe_currency
invoice_prefix invoice_prefix
confirmation_required confirmation_required
wallet_module] } wallet_module
statistics_module] }
# WARNING: when adding a new key, you may also want to add it in app/policies/setting_policy.rb#public_whitelist # WARNING: when adding a new key, you may also want to add it in app/policies/setting_policy.rb#public_whitelist
def value def value
@ -117,6 +118,11 @@ class Setting < ApplicationRecord
last_value&.created_at last_value&.created_at
end end
def previous_update
previous_value = history_values.order(HistoryValue.arel_table['created_at'].desc).limit(2).last
previous_value&.created_at
end
def value=(val) def value=(val)
admin = User.admins.first admin = User.admins.first
save && history_values.create(invoicing_profile: admin.invoicing_profile, value: val) save && history_values.create(invoicing_profile: admin.invoicing_profile, value: val)

View File

@ -16,9 +16,12 @@ class SettingService
Stylesheet.home_page&.rebuild! if setting.name == 'home_css' Stylesheet.home_page&.rebuild! if setting.name == 'home_css'
# notify about a change in privacy policy # notify about a change in privacy policy
NotifyPrivacyUpdateWorker.perform_async(id) if setting.name == 'privacy_body' NotifyPrivacyUpdateWorker.perform_async(setting.id) if setting.name == 'privacy_body'
# sync all users on stripe # sync all users on stripe
SyncMembersOnStripeWorker.perform_async(setting.history_values.last&.invoicing_profile&.user&.id) if setting.name == 'stripe_secret_key' SyncMembersOnStripeWorker.perform_async(setting.history_values.last&.invoicing_profile&.user&.id) if setting.name == 'stripe_secret_key'
# generate statistics
PeriodStatisticsWorker.perform_async(setting.previous_update) if setting.name == 'statistics_module' && setting.value == 'true'
end end
end end

View File

@ -26,6 +26,7 @@
Fablab.plansModule = ('<%= Setting.get('plans_module') %>' === 'true'); Fablab.plansModule = ('<%= Setting.get('plans_module') %>' === 'true');
Fablab.spacesModule = ('<%= Setting.get('spaces_module') %>' === 'true'); Fablab.spacesModule = ('<%= Setting.get('spaces_module') %>' === 'true');
Fablab.walletModule = ('<%= Setting.get('wallet_module') %>' === 'true'); Fablab.walletModule = ('<%= Setting.get('wallet_module') %>' === 'true');
Fablab.statisticsModule = ('<%= Setting.get('statistics_module') %>' === 'true');
Fablab.defaultHost = "<%= Rails.application.secrets.default_host %>"; Fablab.defaultHost = "<%= Rails.application.secrets.default_host %>";
Fablab.trackingId = "<%= Setting.get('tracking_id') %>"; Fablab.trackingId = "<%= Setting.get('tracking_id') %>";
Fablab.superadminId = parseInt("<%= User.superadmin&.id %>", 10); Fablab.superadminId = parseInt("<%= User.superadmin&.id %>", 10);

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
# Asynchronously generate the statistics for the given period
# This worker is triggered when enabling the statistics and with `rails fablab:es:generate_stats`
class PeriodStatisticsWorker
include Sidekiq::Worker
# @param period {String|Integer} date string or number of days until current date
def perform(period)
days = date_to_days(period)
puts "\n==> generating statistics for the last #{days} days <==\n"
if days.zero?
StatisticService.new.generate_statistic(start_date: DateTime.current.beginning_of_day, end_date: DateTime.current.end_of_day)
else
days.times.each do |i|
StatisticService.new.generate_statistic(start_date: i.day.ago.beginning_of_day, end_date: i.day.ago.end_of_day)
end
end
end
def date_to_days(value)
date = Date.parse(value.to_s)
(DateTime.current.to_date - date).to_i
rescue ArgumentError
value.to_i
end
end

View File

@ -1,7 +1,13 @@
# frozen_string_literal: true
# Asynchronously generate the statistics for the last passed day.
# This worker is triggered every nights, see schedule.yml
class StatisticWorker class StatisticWorker
include Sidekiq::Worker include Sidekiq::Worker
def perform def perform
return unless Setting.get('statistics_module')
StatisticService.new.generate_statistic StatisticService.new.generate_statistic
end end
end end

View File

@ -1111,6 +1111,7 @@ en:
confirmation_required_info: "Optionally, you can force the users to confirm their email address before being able to access Fab-manager." confirmation_required_info: "Optionally, you can force the users to confirm their email address before being able to access Fab-manager."
confirmation_is_required: "Confirmation required" confirmation_is_required: "Confirmation required"
wallet_module: "wallet module" wallet_module: "wallet module"
statistics_module: "statistics module"
general: general:
general: "General" general: "General"
title: "Title" title: "Title"
@ -1147,6 +1148,9 @@ en:
wallet: "Wallet" wallet: "Wallet"
wallet_info_html: "<p>The virtual wallet allows you to allocate a sum of money to users. Then, can spend this money as they wish, in Fab-manager.</p><p>Members cannot credit their wallet themselves, it's a privilege of managers and administrators.</p>" wallet_info_html: "<p>The virtual wallet allows you to allocate a sum of money to users. Then, can spend this money as they wish, in Fab-manager.</p><p>Members cannot credit their wallet themselves, it's a privilege of managers and administrators.</p>"
enable_wallet: "Enable wallet" enable_wallet: "Enable wallet"
statistics: "Statistics"
statistics_info_html: "<p>Enable or disable the statistics module.</p><p>If enabled, every nights, the data of the day just passed will be consolidated in the database of a powerful analysis engine. Then, every administrators will be able to browse statistical charts and tables in the corresponding section.</p>"
enable_statistics: "Enable statistics"
privacy: privacy:
title: "Privacy" title: "Privacy"
privacy_policy: "Privacy policy" privacy_policy: "Privacy policy"

View File

@ -1111,6 +1111,7 @@ fr:
confirmation_required_info: "De manière optionnelle, vous pouvez forcer les utilisateurs à confirmer leur adresse électronique avant de pouvoir accéder à Fab-manager." confirmation_required_info: "De manière optionnelle, vous pouvez forcer les utilisateurs à confirmer leur adresse électronique avant de pouvoir accéder à Fab-manager."
confirmation_is_required: "Confirmation requise" confirmation_is_required: "Confirmation requise"
wallet_module: "module porte-monnaie" wallet_module: "module porte-monnaie"
statistics_module: "module de statistiques"
general: general:
general: "Général" general: "Général"
title: "Titre" title: "Titre"
@ -1147,6 +1148,9 @@ fr:
wallet: "Porte-monnaie" wallet: "Porte-monnaie"
wallet_info_html: "<p>Le porte-monnaie virtuel vous permet d'allouer une certaine somme d'argent aux utilisateurs. Ils peuvent ensuite dépenser cet argent comment bon leur semble, dans Fab-manager.</p><p>Les membres ne peuvent pas créditer leur porte-monnaie eux-même, c'est un privilège des gestionnaires et des administrateurs.</p>" wallet_info_html: "<p>Le porte-monnaie virtuel vous permet d'allouer une certaine somme d'argent aux utilisateurs. Ils peuvent ensuite dépenser cet argent comment bon leur semble, dans Fab-manager.</p><p>Les membres ne peuvent pas créditer leur porte-monnaie eux-même, c'est un privilège des gestionnaires et des administrateurs.</p>"
enable_wallet: "Activer le porte-monnaie" enable_wallet: "Activer le porte-monnaie"
statistics: "Statistiques"
statistics_info_html: "<p>Activer ou désactiver le module de statistiques.</p><p>Si activé, chaque nuit, les données de la journée qui vient de s'écouler seront consolidées dans la base de données d'un puissant moteur d'analyse. Ensuite, chaque administrateur pourra parcourir les tableaux et graphiques statistiques dans la section correspondante.</p>"
enable_statistics: "Activer les statistiques"
privacy: privacy:
title: "Confidentialité" title: "Confidentialité"
privacy_policy: "Politique de confidentialité" privacy_policy: "Politique de confidentialité"

View File

@ -888,6 +888,8 @@ Setting.set('confirmation_required', false) unless Setting.find_by(name: 'confir
Setting.set('wallet_module', true) unless Setting.find_by(name: 'wallet_module').try(:value) Setting.set('wallet_module', true) unless Setting.find_by(name: 'wallet_module').try(:value)
Setting.set('statistics_module', true) unless Setting.find_by(name: 'statistics_module').try(:value)
if StatisticCustomAggregation.count.zero? if StatisticCustomAggregation.count.zero?
# available reservations hours for machines # available reservations hours for machines
machine_hours = StatisticType.find_by(key: 'hour', statistic_index_id: 2) machine_hours = StatisticType.find_by(key: 'hour', statistic_index_id: 2)

View File

@ -168,22 +168,13 @@ namespace :fablab do
task :generate_stats, [:period] => :environment do |_task, args| task :generate_stats, [:period] => :environment do |_task, args|
raise 'FATAL ERROR: You must pass a number of days (=> past period) OR a date to generate statistics' unless args.period raise 'FATAL ERROR: You must pass a number of days (=> past period) OR a date to generate statistics' unless args.period
days = date_to_days(args.period) unless Setting.get('statistics_module')
puts "\n==> generating statistics for the last #{days} days <==\n" print 'Statistics are disabled. Do you still want to generate? (y/N) '
if days.zero? confirm = STDIN.gets.chomp
StatisticService.new.generate_statistic(start_date: DateTime.current.beginning_of_day, end_date: DateTime.current.end_of_day) raise 'Interrupted by user' unless confirm == 'y'
else
days.times.each do |i|
StatisticService.new.generate_statistic(start_date: i.day.ago.beginning_of_day, end_date: i.day.ago.end_of_day)
end
end end
end
def date_to_days(value) PeriodStatisticsWorker.perform(args.period)
date = Date.parse(value.to_s)
(DateTime.current.to_date - date).to_i
rescue ArgumentError
value.to_i
end end
end end
end end

View File

@ -132,7 +132,8 @@ namespace :fablab do
%w[_ STRIPE_CURRENCY stripe_currency], %w[_ STRIPE_CURRENCY stripe_currency],
%w[_ INVOICE_PREFIX invoice_prefix FabManager_invoice], %w[_ INVOICE_PREFIX invoice_prefix FabManager_invoice],
%w[_ USER_CONFIRMATION_NEEDED_TO_SIGN_IN confirmation_required false], %w[_ USER_CONFIRMATION_NEEDED_TO_SIGN_IN confirmation_required false],
%w[! FABLAB_WITHOUT_WALLET wallet_module false] %w[! FABLAB_WITHOUT_WALLET wallet_module false],
%w[! FABLAB_WITHOUT_STATISTICS statistics_module false]
] ]
mapping.each do |m| mapping.each do |m|

View File

@ -685,3 +685,11 @@ history_value_72:
value: true value: true
created_at: 2020-06-15 10:04:06.216541000 Z created_at: 2020-06-15 10:04:06.216541000 Z
updated_at: 2020-06-15 10:04:06.216541000 Z updated_at: 2020-06-15 10:04:06.216541000 Z
history_value_73:
id: 73
setting_id: 73
invoicing_profile_id: 1
value: true
created_at: 2020-06-17 10:48:19.002417000 Z
updated_at: 2020-06-17 10:48:19.002417000 Z

View File

@ -425,3 +425,9 @@ setting_72:
created_at: 2020-06-15 10:04:06.216541000 Z created_at: 2020-06-15 10:04:06.216541000 Z
updated_at: 2020-06-15 10:04:06.216541000 Z updated_at: 2020-06-15 10:04:06.216541000 Z
setting_73:
id: 73
name: statistics_module
created_at: 2020-06-17 10:48:19.002417000 Z
updated_at: 2020-06-17 10:48:19.002417000 Z