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

Merge branch 'dev' into host

This commit is contained in:
Sylvain 2019-02-14 16:35:38 +01:00
commit cf23fae73c
23 changed files with 427 additions and 392 deletions

View File

@ -10,6 +10,9 @@ Metrics/AbcSize:
Max: 45
Metrics/ClassLength:
Max: 200
Metrics/BlockLength:
Exclude:
- 'lib/tasks/**/*.rake'
Style/BracesAroundHashParameters:
EnforcedStyle: context_dependent
Style/RegexpLiteral:

View File

@ -1,5 +1,10 @@
# Changelog Fab Manager
- Refactored rake tasks to use namespaces and descriptions
- Fix a bug: unable to create a new oAuth 2.0 provider
- Fix a bug: application in unavailable if a SSO is active
- Fixed missing translations in authentication providers form
## v2.8.3 2019 January 29
- Added user's manual (fr)
@ -54,7 +59,7 @@
# v2.7.3 2018 December 03
- Updated Uglifier gem to support ES6 syntax
- Fix rake task fablab:es_build_projects_index for ElasticSearch > 1.7
- Fix rake task `fablab:es:build_projects_index` for ElasticSearch > 1.7
- Fix Dockerfile: yarn was not setup correctly
- Fix: unable to build assets
@ -96,7 +101,7 @@
- Ability to parametrize machines order on the booking page
- Ability to set a neutral gender for the fablab's title (#108)
- Fix a bug: rake task fablab:fix:categories_slugs bash interpretation error
- Fix a bug: rake task `fablab:fix:categories_slugs` bash interpretation error
- Fix a bug: file inputs filled with long filenames render improperly with an overflow
- Fix a bug: title concordance radio buttons render improperly on smaller screens
- Improved verifications in ElasticSearch upgrade script
@ -290,7 +295,7 @@
- Fix a bug: new plans statistics are not shown
- [TODO DEPLOY] `rake db:migrate`, then `rake db:seed`
- [TODO DEPLOY] add the `FABLAB_WITHOUT_SPACES` environment variable
- [TODO DEPLOY] `rake fablab:es_add_spaces`
- [TODO DEPLOY] `rake fablab:es:add_spaces`
- [TODO DEPLOY] `rake fablab:fix:new_plans_statistics` if you have created plans from v2.4.10
## v2.4.11 2017 March 15
@ -306,7 +311,7 @@
- Fix a bug: navigation to about page duplicates admin's links in left menu
- Fix a bug: changing the price of a plan lost its past statistics
- [TODO DEPLOY] `rake db:migrate`
- [TODO DEPLOY] `rake fablab:set_plans_slugs`
- [TODO DEPLOY] `rake fablab:fix:set_plans_slugs`
## v2.4.9 2017 January 4
@ -321,8 +326,8 @@
- Fix a bug: when regenerating statistics, previous values are not fully removed (only 10 firsts), resulting in wrong statistics generation (2)
- Fix a bug: when deleting an availability just after its creation, the indexer workers crash and retries for a month
- [TODO DEPLOY] remove possible value `application/` in `ALLOWED_MIME_TYPES` list, in environment variable
- [TODO DEPLOY] `rails runner StatisticCustomAggregation.destroy_all`, then `rake db:seed`, then `rake fablab:es_build_availabilities_index` (1)
- [TODO DEPLOY] `rake fablab:generate_stats[1095]` if you already has regenerated the statistics in the past, then they are very likely corrupted. Run this task to fix (2)
- [TODO DEPLOY] `rails runner StatisticCustomAggregation.destroy_all`, then `rake db:seed`, then `rake fablab:es:build_availabilities_index` (1)
- [TODO DEPLOY] `rake fablab:es:generate_stats[1095]` if you already has regenerated the statistics in the past, then they are very likely corrupted. Run this task to fix (2)
## v2.4.8 2016 December 15
@ -450,8 +455,8 @@
- Fix a bug: reordering project's steps trigger the unsaved-warning dialog
- Fix a bug: unable to compile assets in Docker with CoffeeScript error
- Fix a bug: do not force HTTPS for URLs in production environments
- [TODO DEPLOY] `rake fablab:es_build_availabilities_index`
- [TODO DEPLOY] `rake fablab:es_add_event_filters`
- [TODO DEPLOY] `rake fablab:es:build_availabilities_index`
- [TODO DEPLOY] `rake fablab:es:add_event_filters`
- [TODO DEPLOY] `rake db:migrate`
- [TODO DEPLOY] `bundle install`
- [TODO DEPLOY] add `EXCEL_DATE_FORMAT`, `ALLOWED_EXTENSIONS` and `ALLOWED_MIME_TYPES` environment variable in `application.yml`

View File

@ -164,7 +164,7 @@ This procedure is not easy to follow so if you don't need to write some code for
rake db:create
rake db:migrate
ADMIN_EMAIL='youradminemail' ADMIN_PASSWORD='youradminpassword' rake db:seed
rake fablab:es_build_stats
rake fablab:es:build_stats
# for tests
RAILS_ENV=test rake db:create
RAILS_ENV=test rake db:migrate
@ -255,7 +255,7 @@ environment.
rake db:create
rake db:migrate
ADMIN_EMAIL='youradminemail' ADMIN_PASSWORD='youradminpassword' rake db:seed
rake fablab:es_build_stats
rake fablab:es:build_stats
# for tests
RAILS_ENV=test rake db:create
RAILS_ENV=test rake db:migrate
@ -393,7 +393,7 @@ If the scheduled task wasn't executed for any reason (eg. you are in a dev envir
```bash
# Here for the 50 last days
rake fablab:generate_stats[50]
rake fablab:es:generate_stats[50]
```
<a name="backup-and-restore-elasticsearch"></a>

View File

@ -411,10 +411,10 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
}).result['finally'](null).then(function () { growl.info(_t('you_will_receive_in_a_moment_an_email_with_instructions_to_reset_your_password')); });
}
});
};
// otherwise the user just closed the modal
<% end %>
};
/**
* Detect if the current page (tab/window) is active of put as background.

View File

@ -92,6 +92,7 @@ Application.Directives.directive('disableAnimation', ['$animate', ($animate) =>
/**
* Isolate a form's scope from its parent : no nested validation
* @see https://stackoverflow.com/a/37481846/1039377
*/
Application.Directives.directive('isolateForm', [ () =>
({
@ -100,30 +101,13 @@ Application.Directives.directive('isolateForm', [ () =>
link (scope, elm, attrs, ctrl) {
if (!ctrl) { return; }
// Do a copy of the controller
const ctrlCopy = {};
angular.copy(ctrl, ctrlCopy);
// Get the form's parent
const parent = elm.parent().controller('form');
// Remove parent link to the controller
parent.$removeControl(ctrl);
// Replace form controller with a "isolated form"
const isolatedFormCtrl = {
$setValidity (validationToken, isValid, control) {
ctrlCopy.$setValidity(validationToken, isValid, control);
return parent.$setValidity(validationToken, true, ctrl);
},
$setDirty () {
elm.removeClass('ng-pristine').addClass('ng-dirty');
ctrl.$dirty = true;
return ctrl.$pristine = false;
const parentForm = ctrl.$$parentForm; // Note this uses private API
if (!parentForm) {
return;
}
};
return angular.extend(ctrl, isolatedFormCtrl);
// Remove this form from parent controller
parentForm.$removeControl(ctrl);
}
})

View File

@ -19,7 +19,7 @@ class AuthProvider < ActiveRecord::Base
before_create :set_initial_state
def build_providable(params)
def build_providable(params, _assignment_options)
raise "Unknown providable_type: #{providable_type}" unless PROVIDABLE_TYPES.include?(providable_type)
self.providable = providable_type.constantize.new(params)

View File

@ -125,7 +125,7 @@ class Invoice < ActiveRecord::Base
reference
end
# for debug & used by rake task "fablab:regenerate_invoices"
# for debug & used by rake task "fablab:maintenance:regenerate_invoices"
def regenerate_invoice_pdf
pdf = ::PDF::Invoice.new(self, nil).render
File.binwrite(file, pdf)

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
# @deprecated
# <b>DEPRECATED:</b> Feature removed in v2.8.2
json.title notification.notification_type
json.description _t('.invoices_generation_was_STATUS_for_user_NAME_html',
STATUS: notification.attached_object.invoicing_disabled.to_s,
NAME: notification.attached_object.profile.full_name) # messageFormat
json.url notification_url(notification, format: :json)

View File

@ -1,3 +1,7 @@
# frozen_string_literal: true
# @deprecated
# <b>DEPRECATED:</b> Feature removed in v1 (87dd9ba0 2015-06-04)
json.title notification.notification_type
json.description t('.you_have_changed_your_subscription_to_PLAN_html',
PLAN: notification.attached_object.plan.name)

View File

@ -526,6 +526,8 @@ en:
authentication_new:
# add a new authentication provider (SSO)
local_database: "Local Database"
o_auth2: "OAuth 2.0"
add_a_new_authentication_provider: "Add a new authentication provider"
a_local_database_provider_already_exists_unable_to_create_another: "A \"Local Database\" provider already exists. Unable to create another."
local_provider_successfully_saved: "Local provider successfully saved."

View File

@ -526,6 +526,8 @@ es:
authentication_new:
# add a new authentication provider (SSO)
local_database: "Base de datos local"
o_auth2: "OAuth 2.0"
add_a_new_authentication_provider: "Agregar un nuevo proveedor de autenticación"
a_local_database_provider_already_exists_unable_to_create_another: "A proveedor de \"Base de datos local\" ya existe. No se puede crear otro."
local_provider_successfully_saved: "Proveedor local guardado correctamente."

View File

@ -526,6 +526,8 @@ fr:
authentication_new:
# ajouter un nouveau fournisseur d'authentification (SSO)
local_database: "Base de données locale"
o_auth2: "OAuth 2.0"
add_a_new_authentication_provider: "Ajouter un fournisseur d'authentification"
a_local_database_provider_already_exists_unable_to_create_another: "Un fournisseur de type \"Base de données locale\" existe déjà. Impossible d'en créer un second."
local_provider_successfully_saved: "Le fournisseur local a bien été enregistré."

View File

@ -526,6 +526,8 @@ pt:
authentication_new:
# add a new authentication provider (SSO)
local_database: "Local Database"
o_auth2: "OAuth 2.0"
add_a_new_authentication_provider: "Adicionar novo provedor de autenticação"
a_local_database_provider_already_exists_unable_to_create_another: "Um provedor \"Local Database\" já existe. Não foi possível criar outro."
local_provider_successfully_saved: "Provedor local salvo com sucesso."

View File

@ -145,7 +145,7 @@ Copy [elasticsearch.yml](../docker/elasticsearch.yml) and [log4j2.properties](..
Finally reindex your data:
```bash
rake fablab:es_build_stats
rake fablab:generate_stats[3000]
rake fablab:es_build_projects_index
rake fablab:es:build_stats
rake fablab:es:generate_stats[3000]
rake fablab:es:build_projects_index
```

View File

@ -53,7 +53,7 @@ For this guide, we will use [GitHub](https://developer.github.com/v3/oauth/) as
```bash
# replace GitHub with the name of the provider you just created
rake fablab:switch_auth_provider[GitHub]
rake fablab:auth:switch_provider[GitHub]
```
- As the command just prompted you, you have to re-compile the assets
@ -62,5 +62,5 @@ rake fablab:switch_auth_provider[GitHub]
- Then restart the web-server or the container.
- Finally, to notify all existing users about the change (and send them their migration code/link), run:
```bash
rake fablab:notify_auth_changed
rake fablab:auth:notify_changed
```

View File

@ -236,7 +236,7 @@ docker-compose run --rm -e ADMIN_EMAIL=xxx -e ADMIN_PASSWORD=xxx fabmanager bund
### prepare Elasticsearch (search engine)
`docker-compose run --rm fabmanager bundle exec rake fablab:es_build_stats`
`docker-compose run --rm fabmanager bundle exec rake fablab:es:build_stats`
### start all services

View File

@ -1,328 +0,0 @@
namespace :fablab do
# desc "Get all stripe plans and create in fablab app"
# task stripe_plan: :environment do
# Stripe::Plan.all.data.each do |plan|
# unless Plan.find_by(stp_plan_id: plan.id)
# group = Group.friendly.find(plan.id.split('-').first)
# if group
# Plan.create(stp_plan_id: plan.id, name: plan.name, amount: plan.amount, interval: plan.interval, group_id: group.id, skip_create_stripe_plan: true)
# else
# puts plan.name + " n'a pas été créé. [error]"
# end
# end
# end
#
# if Plan.column_names.include? "training_credit_nb"
# Plan.all.each do |p|
# p.update_columns(training_credit_nb: (p.interval == 'month' ? 1 : 5))
# end
# end
# end
desc 'Regenerate the invoices'
task :regenerate_invoices, [:year, :month] => :environment do |task, args|
year = args.year || Time.now.year
month = args.month || Time.now.month
start_date = Time.new(year.to_i, month.to_i, 1)
end_date = start_date.next_month
puts "-> Start regenerate the invoices between #{I18n.l start_date, format: :long} in #{I18n.l end_date-1.minute, format: :long}"
invoices = Invoice.only_invoice.where('created_at >= :start_date AND created_at < :end_date', {start_date: start_date, end_date: end_date}).order(created_at: :asc)
invoices.each(&:regenerate_invoice_pdf)
puts '-> Done'
end
desc 'Cancel stripe subscriptions'
task cancel_subscriptions: :environment do
Subscription.where('expiration_date >= ?', Time.now.at_beginning_of_day).each do |s|
puts "-> Start cancel subscription of #{s.user.email}"
s.cancel
puts '-> Done'
end
end
desc '(re)Build ElasticSearch fablab base for stats'
task es_build_stats: :environment do
puts 'DELETE stats'
`curl -XDELETE http://#{ENV["ELASTICSEARCH_HOST"]}:9200/stats`
puts 'PUT index stats'
`curl -XPUT http://#{ENV["ELASTICSEARCH_HOST"]}:9200/stats -d'
{
"settings" : {
"index" : {
"number_of_replicas" : 0
}
}
}
'`
%w[account event machine project subscription training user space].each do |stat|
puts "PUT Mapping stats/#{stat}"
`curl -XPUT http://#{ENV["ELASTICSEARCH_HOST"]}:9200/stats/#{stat}/_mapping -d '
{
"properties": {
"type": {
"type": "string",
"index" : "not_analyzed"
},
"subType": {
"type": "string",
"index" : "not_analyzed"
},
"date": {
"type": "date"
},
"name": {
"type": "string",
"index" : "not_analyzed"
}
}
}';`
end
es_add_event_filters
end
desc 'add event filters to statistics'
task es_add_event_filters: :environment do
es_add_event_filters
end
def es_add_event_filters
`curl -XPUT http://#{ENV["ELASTICSEARCH_HOST"]}:9200/stats/event/_mapping -d '
{
"properties": {
"ageRange": {
"type": "string",
"index" : "not_analyzed"
},
"eventTheme": {
"type": "string",
"index" : "not_analyzed"
}
}
}';`
end
desc 'add spaces reservations to statistics'
task es_add_spaces: :environment do
`curl -XPUT http://#{ENV["ELASTICSEARCH_HOST"]}:9200/stats/space/_mapping -d '
{
"properties": {
"type": {
"type": "string",
"index" : "not_analyzed"
},
"subType": {
"type": "string",
"index" : "not_analyzed"
},
"date": {
"type": "date"
},
"name": {
"type": "string",
"index" : "not_analyzed"
}
}
}';`
end
desc 'sync all/one project in ElasticSearch index'
task :es_build_projects_index, [:id] => :environment do |task, args|
client = Project.__elasticsearch__.client
# create index if not exists
unless client.indices.exists? index: Project.index_name
Project.__elasticsearch__.create_index! force: true
end
# index requested documents
if args.id
ProjectIndexerWorker.perform_async(:index, id)
else
Project.pluck(:id).each do |project_id|
ProjectIndexerWorker.perform_async(:index, project_id)
end
end
end
desc 'sync all/one availabilities in ElasticSearch index'
task :es_build_availabilities_index, [:id] => :environment do |task, args|
client = Availability.__elasticsearch__.client
# create index if not exists
unless client.indices.exists? index: Availability.index_name
Availability.__elasticsearch__.create_index! force: true
end
# delete doctype if exists
if client.indices.exists_type? index: Availability.index_name, type: Availability.document_type
client.indices.delete_mapping index: Availability.index_name, type: Availability.document_type
end
# create doctype
client.indices.put_mapping index: Availability.index_name, type: Availability.document_type, body: Availability.mappings.to_hash
# verify doctype creation was successful
if client.indices.exists_type? index: Availability.index_name, type: Availability.document_type
puts "[ElasticSearch] #{Availability.index_name}/#{Availability.document_type} successfully created with its mapping."
# index requested documents
if args.id
AvailabilityIndexerWorker.perform_async(:index, id)
else
Availability.pluck(:id).each do |availability_id|
AvailabilityIndexerWorker.perform_async(:index, availability_id)
end
end
else
puts "[ElasticSearch] An error occurred while creating #{Availability.index_name}/#{Availability.document_type}. Please check your ElasticSearch configuration."
puts "\nCancelling..."
end
end
desc 'recreate every versions of images'
task build_images_versions: :environment do
Project.find_each do |project|
project.project_image.attachment.recreate_versions! if project.project_image.present? and project.project_image.attachment.present?
end
ProjectStepImage.find_each do |project_step_image|
project_step_image.attachment.recreate_versions! if project_step_image.present? and project_step_image.attachment.present?
end
Machine.find_each do |machine|
machine.machine_image.attachment.recreate_versions! if machine.machine_image.present?
end
Event.find_each do |event|
event.event_image.attachment.recreate_versions! if event.event_image.present?
end
end
desc 'switch the active authentication provider'
task :switch_auth_provider, [:provider] => :environment do |task, args|
unless args.provider
fail 'FATAL ERROR: You must pass a provider name to activate'
end
unless AuthProvider.find_by(name: args.provider) != nil
providers = AuthProvider.all.inject('') do |str, item|
str += item[:name]+', '
end
fail "FATAL ERROR: the provider '#{args.provider}' does not exists. Available providers are: #{providers[0..-3]}"
end
if AuthProvider.active.name == args.provider
fail "FATAL ERROR: the provider '#{args.provider}' is already enabled"
end
# disable previous provider
prev_prev = AuthProvider.find_by(status: 'previous')
unless prev_prev.nil?
prev_prev.update_attribute(:status, 'pending')
end
AuthProvider.active.update_attribute(:status, 'previous')
# enable given provider
AuthProvider.find_by(name: args.provider).update_attribute(:status, 'active')
# migrate the current users.
if AuthProvider.active.providable_type != DatabaseProvider.name
User.all.each do |user|
# Concerns any providers except local database
user.generate_auth_migration_token
end
else
User.all.each do |user|
# Concerns local database provider
user.update_attribute(:auth_token, nil)
end
end
# ask the user to restart the application
puts "\nActivation successful"
puts "\n/!\\ WARNING: Please consider the following, otherwise the authentication will be bogus:"
puts "\t1) CLEAN the cache with `rake tmp:clear`"
puts "\t2) REBUILD the assets with `rake assets:precompile`"
puts "\t3) RESTART the application"
puts "\t4) NOTIFY the current users with `rake fablab:notify_auth_changed`\n\n"
end
desc 'notify users that the auth provider has changed'
task notify_auth_changed: :environment do
I18n.locale = I18n.default_locale
# notify every users if the provider is not local database provider
if AuthProvider.active.providable_type != DatabaseProvider.name
User.all.each do |user|
NotificationCenter.call type: 'notify_user_auth_migration',
receiver: user,
attached_object: user
end
end
puts "\nUsers successfully notified\n\n"
end
desc 'generate fixtures from db'
task generate_fixtures: :environment do
Rails.application.eager_load!
ActiveRecord::Base.descendants.reject { |c| c == ActiveRecord::SchemaMigration or c == PartnerPlan }.each do |ar_base|
p "========== #{ar_base} =============="
ar_base.dump_fixtures
end
end
desc 'clean stripe secrets from VCR cassettes'
task clean_cassettes_secrets: :environment do
Dir['test/vcr_cassettes/*.yml'].each do |cassette_file|
cassette = File.read(cassette_file)
cassette.gsub!(Rails.application.secrets.stripe_api_key, 'sk_test_testfaketestfaketestfake')
cassette.gsub!(Rails.application.secrets.stripe_publishable_key, 'pk_test_faketestfaketestfaketest')
puts cassette
File.write(cassette_file, cassette)
end
end
desc '(re)generate statistics in elasticsearch for the past period'
task :generate_stats, [:period] => :environment do |task, args|
unless args.period
fail 'FATAL ERROR: You must pass a number of days (=> past period) to generate statistics on'
end
days = args.period.to_i
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
desc 'set slugs to plans'
task set_plans_slugs: :environment do
# this will maintain compatibility with existing statistics
Plan.all.each do |p|
p.slug = p.stp_plan_id
p.save
end
end
desc 'get incoherent invoice'
task :get_incoherent_invoice, [:start_date] => :environment do |task, args|
date = Date.parse('2017-05-01')
if args.start_date
begin
date = Date.parse(args.start_date)
rescue => e
fail e
end
end
Invoice.where('created_at > ? AND stp_invoice_id IS NOT NULL', date).each do |invoice|
stp_invoice = Stripe::Invoice.retrieve(invoice.stp_invoice_id)
if invoice.amount_paid != stp_invoice.total
puts "Id: #{invoice.id}, reference: #{invoice.reference}, stripe id: #{stp_invoice.id}, invoice total: #{invoice.amount_paid / 100.0}, stripe invoice total: #{stp_invoice.total / 100.0}, date: #{invoice.created_at}"
end
end
end
end

View File

@ -0,0 +1,66 @@
# frozen_string_literal: true
# SSO and authentication relative tasks
namespace :fablab do
namespace :auth do
desc 'switch the active authentication provider'
task :switch_provider, [:provider] => :environment do |_task, args|
raise 'FATAL ERROR: You must pass a provider name to activate' unless args.provider
if AuthProvider.find_by(name: args.provider).nil?
providers = AuthProvider.all.inject('') { |str, item| str + item[:name] + ', ' }
raise "FATAL ERROR: the provider '#{args.provider}' does not exists. Available providers are: #{providers[0..-3]}"
end
raise "FATAL ERROR: the provider '#{args.provider}' is already enabled" if AuthProvider.active.name == args.provider
# disable previous provider
prev_prev = AuthProvider.find_by(status: 'previous')
prev_prev&.update_attribute(:status, 'pending')
AuthProvider.active.update_attribute(:status, 'previous')
# enable given provider
AuthProvider.find_by(name: args.provider).update_attribute(:status, 'active')
# migrate the current users.
if AuthProvider.active.providable_type != DatabaseProvider.name
# Concerns any providers except local database
User.all.each(&:generate_auth_migration_token)
else
User.all.each do |user|
# Concerns local database provider
user.update_attribute(:auth_token, nil)
end
end
# ask the user to restart the application
puts "\nActivation successful"
puts "\n/!\\ WARNING: Please consider the following, otherwise the authentication will be bogus:"
puts "\t1) CLEAN the cache with `rake tmp:clear`"
puts "\t2) REBUILD the assets with `rake assets:precompile`"
puts "\t3) RESTART the application"
puts "\t4) NOTIFY the current users with `rake fablab:auth:notify_changed`\n\n"
end
desc 'notify users that the auth provider has changed'
task notify_changed: :environment do
I18n.locale = I18n.default_locale
# notify every users if the provider is not local database provider
if AuthProvider.active.providable_type != DatabaseProvider.name
User.all.each do |user|
NotificationCenter.call type: 'notify_user_auth_migration',
receiver: user,
attached_object: user
end
end
puts "\nUsers successfully notified\n\n"
end
end
end

165
lib/tasks/fablab/es.rake Normal file
View File

@ -0,0 +1,165 @@
# frozen_string_literal: true
# ElasticSearch relative tasks
namespace :fablab do
namespace :es do
desc '(re)Build ElasticSearch fablab base for stats'
task build_stats: :environment do
delete_stats_index
create_stats_index
create_stats_mappings
add_event_filters
end
def delete_stats_index
puts 'DELETE stats'
`curl -XDELETE http://#{ENV['ELASTICSEARCH_HOST']}:9200/stats`
end
def create_stats_index
puts 'PUT index stats'
`curl -XPUT http://#{ENV['ELASTICSEARCH_HOST']}:9200/stats -d'
{
"settings" : {
"index" : {
"number_of_replicas" : 0
}
}
}
'`
end
def create_stats_mappings
%w[account event machine project subscription training user space].each do |stat|
puts "PUT Mapping stats/#{stat}"
`curl -XPUT http://#{ENV['ELASTICSEARCH_HOST']}:9200/stats/#{stat}/_mapping -d '
{
"properties": {
"type": {
"type": "string",
"index" : "not_analyzed"
},
"subType": {
"type": "string",
"index" : "not_analyzed"
},
"date": {
"type": "date"
},
"name": {
"type": "string",
"index" : "not_analyzed"
}
}
}';`
end
end
desc 'add event filters to statistics'
task add_event_filters: :environment do
add_event_filters
end
def add_event_filters
`curl -XPUT http://#{ENV['ELASTICSEARCH_HOST']}:9200/stats/event/_mapping -d '
{
"properties": {
"ageRange": {
"type": "string",
"index" : "not_analyzed"
},
"eventTheme": {
"type": "string",
"index" : "not_analyzed"
}
}
}';`
end
desc 'add spaces reservations to statistics'
task add_spaces: :environment do
`curl -XPUT http://#{ENV['ELASTICSEARCH_HOST']}:9200/stats/space/_mapping -d '
{
"properties": {
"type": {
"type": "string",
"index" : "not_analyzed"
},
"subType": {
"type": "string",
"index" : "not_analyzed"
},
"date": {
"type": "date"
},
"name": {
"type": "string",
"index" : "not_analyzed"
}
}
}';`
end
desc 'sync all/one project in ElasticSearch index'
task :build_projects_index, [:id] => :environment do |_task, args|
client = Project.__elasticsearch__.client
# create index if not exists
Project.__elasticsearch__.create_index! force: true unless client.indices.exists? index: Project.index_name
# index requested documents
if args.id
ProjectIndexerWorker.perform_async(:index, id)
else
Project.pluck(:id).each do |project_id|
ProjectIndexerWorker.perform_async(:index, project_id)
end
end
end
desc 'sync all/one availabilities in ElasticSearch index'
task :build_availabilities_index, [:id] => :environment do |_task, args|
client = Availability.__elasticsearch__.client
# create index if not exists
Availability.__elasticsearch__.create_index! force: true unless client.indices.exists? index: Availability.index_name
# delete doctype if exists
if client.indices.exists_type? index: Availability.index_name, type: Availability.document_type
client.indices.delete_mapping index: Availability.index_name, type: Availability.document_type
end
# create doctype
client.indices.put_mapping index: Availability.index_name,
type: Availability.document_type,
body: Availability.mappings.to_hash
# verify doctype creation was successful
if client.indices.exists_type? index: Availability.index_name, type: Availability.document_type
puts "[ElasticSearch] #{Availability.index_name}/#{Availability.document_type} successfully created with its mapping."
# index requested documents
if args.id
AvailabilityIndexerWorker.perform_async(:index, id)
else
Availability.pluck(:id).each do |availability_id|
AvailabilityIndexerWorker.perform_async(:index, availability_id)
end
end
else
puts "[ElasticSearch] An error occurred while creating #{Availability.index_name}/#{Availability.document_type}. " \
'Please check your ElasticSearch configuration.'
puts "\nCancelling..."
end
end
desc '(re)generate statistics in ElasticSearch for the past period'
task :generate_stats, [:period] => :environment do |_task, args|
raise 'FATAL ERROR: You must pass a number of days (=> past period) to generate statistics on' unless args.period
days = args.period.to_i
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

View File

@ -1,5 +1,9 @@
# frozen_string_literal: true
# Correctives for bugs or upgrades migrations tasks
namespace :fablab do
namespace :fix do
desc '[release 2.3.0] update reservations referencing reservables not present in database'
task reservations_not_existing_reservable: :environment do
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.connection.execute(
@ -9,23 +13,26 @@ namespace :fablab do
)
end
desc '[release 2.4.0] put every non-categorized events into a new category called "No Category", to ease re-categorization'
task assign_category_to_uncategorized_events: :environment do
c = Category.find_or_create_by!({name: 'No category'})
c = Category.find_or_create_by!(name: 'No category')
Event.where(category: nil).each do |e|
e.category = c
e.save!
end
end
desc '[release 2.4.11] fix is_rolling for edited plans'
task rolling_plans: :environment do
Plan.where(is_rolling: nil).each do |p|
if p.is_rolling.nil? and p.is_rolling != false
if p.is_rolling.nil? && p.is_rolling != false
p.is_rolling = true
p.save!
end
end
end
desc '[release 2.5.0] create missing plans in statistics'
task new_plans_statistics: :environment do
StatisticSubType.where(key: nil).each do |sst|
p = Plan.find_by(name: sst.label)
@ -36,6 +43,7 @@ namespace :fablab do
end
end
desc '[release 2.5.5] create missing space prices'
task new_group_space_prices: :environment do
Space.all.each do |space|
Group.all.each do |group|
@ -48,6 +56,7 @@ namespace :fablab do
end
end
desc '[release 2.5.11] put all admins in a special group'
task migrate_admins_group: :environment do
admins = Group.find_by(slug: 'admins')
User.all.each do |user|
@ -58,38 +67,39 @@ namespace :fablab do
end
end
desc '[release 2.5.14] fix times of recursive events that crosses DST periods'
task recursive_events_over_DST: :environment do
include ApplicationHelper
failed_ids = []
groups = Event.group(:recurrence_id).count
groups.keys.each do |recurrent_event_id|
if recurrent_event_id
next unless recurrent_event_id
begin
initial_event = Event.find(recurrent_event_id)
Event.where(recurrence_id: recurrent_event_id).where.not(id: recurrent_event_id).each do |event|
availability = event.availability
if initial_event.availability.start_at.hour != availability.start_at.hour
next if initial_event.availability.start_at.hour == availability.start_at.hour
availability.start_at = dst_correction(initial_event.availability.start_at, availability.start_at)
availability.end_at = dst_correction(initial_event.availability.end_at, availability.end_at)
availability.save!
end
end
rescue ActiveRecord::RecordNotFound
failed_ids.push recurrent_event_id
end
end
end
if failed_ids.size > 0
puts "WARNING: The events with IDs #{failed_ids} were not found.\n These were initial events of a recurrence.\n\n You may have to correct the following events manually (IDs): "
puts "#{Event.where(recurrence_id: failed_ids).map(&:id)}"
if failed_ids.size.positive?
puts "WARNING: The events with IDs #{failed_ids} were not found.\n These were initial events of a recurrence.\n\n" \
"You may have to correct the following events manually (IDs): #{Event.where(recurrence_id: failed_ids).map(&:id)}"
end
end
desc 'reset slug in events categories'
desc '[release 2.6.6] reset slug in events categories'
task categories_slugs: :environment do
Category.all.each do |cat|
`curl -XPOST http://#{ENV["ELASTICSEARCH_HOST"]}:9200/stats/event/_update_by_query?conflicts=proceed\\&refresh\\&wait_for_completion -d '
`curl -XPOST http://#{ENV['ELASTICSEARCH_HOST']}:9200/stats/event/_update_by_query?conflicts=proceed\\&refresh\\&wait_for_completion -d '
{
"script": {
"source": "ctx._source.subType = params.slug",
@ -106,5 +116,14 @@ namespace :fablab do
}';`
end
end
desc '[release 2.4.10] set slugs to plans'
task set_plans_slugs: :environment do
# this will maintain compatibility with existing statistics
Plan.all.each do |p|
p.slug = p.stp_plan_id
p.save
end
end
end
end

View File

@ -0,0 +1,49 @@
# frozen_string_literal: true
# Maintenance tasks
namespace :fablab do
namespace :maintenance do
desc 'Regenerate the invoices PDF'
task :regenerate_invoices, %i[year month] => :environment do |_task, args|
year = args.year || Time.now.year
month = args.month || Time.now.month
start_date = Time.new(year.to_i, month.to_i, 1)
end_date = start_date.next_month
puts "-> Start regenerate the invoices PDF between #{I18n.l start_date, format: :long} in " \
" #{I18n.l end_date - 1.minute, format: :long}"
invoices = Invoice.only_invoice
.where('created_at >= :start_date AND created_at < :end_date', start_date: start_date, end_date: end_date)
.order(created_at: :asc)
invoices.each(&:regenerate_invoice_pdf)
puts '-> Done'
end
desc 'recreate every versions of images'
task build_images_versions: :environment do
Project.find_each do |project|
if project.project_image.present? && project.project_image.attachment.present?
project.project_image.attachment.recreate_versions!
end
end
ProjectStepImage.find_each do |project_step_image|
project_step_image.attachment.recreate_versions! if project_step_image.present? && project_step_image.attachment.present?
end
Machine.find_each do |machine|
machine.machine_image.attachment.recreate_versions! if machine.machine_image.present?
end
Event.find_each do |event|
event.event_image.attachment.recreate_versions! if event.event_image.present?
end
end
desc 'generate fixtures from db'
task generate_fixtures: :environment do
Rails.application.eager_load!
ActiveRecord::Base.descendants.reject { |c| [ActiveRecord::SchemaMigration, PartnerPlan].include? c }.each do |ar_base|
p "========== #{ar_base} =============="
ar_base.dump_fixtures
end
end
end
end

View File

@ -1,3 +1,6 @@
# frozen_string_literal: true
# OpenLab Projects tasks
namespace :fablab do
namespace :openlab do
desc 'bulk and export projects to openlab'

View File

@ -0,0 +1,48 @@
# frozen_string_literal: true
# Stripe relative tasks
namespace :fablab do
namespace :stripe do
desc 'Cancel stripe subscriptions'
task cancel_subscriptions: :environment do
Subscription.where('expiration_date >= ?', Time.now.at_beginning_of_day).each do |s|
puts "-> Start cancel subscription of #{s.user.email}"
s.cancel
puts '-> Done'
end
end
desc 'find any invoices with incoherent total between stripe and DB'
task :find_incoherent_invoices, [:start_date] => :environment do |_task, args|
date = Date.parse('2017-05-01')
if args.start_date
begin
date = Date.parse(args.start_date)
rescue ArgumentError => e
raise e
end
end
Invoice.where('created_at > ? AND stp_invoice_id IS NOT NULL', date).each do |invoice|
stp_invoice = Stripe::Invoice.retrieve(invoice.stp_invoice_id)
next if invoice.amount_paid == stp_invoice.total
puts "Id: #{invoice.id}, reference: #{invoice.reference}, stripe id: #{stp_invoice.id}, " \
"invoice total: #{invoice.amount_paid / 100.0}, stripe invoice total: #{stp_invoice.total / 100.0}, " \
"date: #{invoice.created_at}"
end
end
desc 'clean stripe secrets from VCR cassettes'
task clean_cassettes_secrets: :environment do
Dir['test/vcr_cassettes/*.yml'].each do |cassette_file|
cassette = File.read(cassette_file)
cassette = cassette.gsub(Rails.application.secrets.stripe_api_key, 'sk_test_testfaketestfaketestfake')
cassette = cassette.gsub(Rails.application.secrets.stripe_publishable_key, 'pk_test_faketestfaketestfaketest')
puts cassette
File.write(cassette_file, cassette)
end
end
end
end