diff --git a/.rubocop.yml b/.rubocop.yml index e4a51bf6c..b696b41ef 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -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: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cae73cce..b32f37223 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,7 +54,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 +96,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 +290,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 +306,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 +321,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 +450,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` diff --git a/README.md b/README.md index 47a4e17f9..b575911c0 100644 --- a/README.md +++ b/README.md @@ -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 @@ -392,7 +392,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] ``` diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 18fbba2ed..2cc5c875c 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -123,7 +123,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) diff --git a/doc/elastic_upgrade.md b/doc/elastic_upgrade.md index ed5d687a2..bed715d7e 100644 --- a/doc/elastic_upgrade.md +++ b/doc/elastic_upgrade.md @@ -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 ``` diff --git a/doc/sso_with_github.md b/doc/sso_with_github.md index 0ba007fe7..f955b4052 100644 --- a/doc/sso_with_github.md +++ b/doc/sso_with_github.md @@ -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 ``` diff --git a/docker/README.md b/docker/README.md index d39441d03..af68cefa2 100644 --- a/docker/README.md +++ b/docker/README.md @@ -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 diff --git a/lib/tasks/fablab.rake b/lib/tasks/fablab.rake deleted file mode 100644 index 4247c1e5e..000000000 --- a/lib/tasks/fablab.rake +++ /dev/null @@ -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 diff --git a/lib/tasks/fablab/auth.rake b/lib/tasks/fablab/auth.rake new file mode 100644 index 000000000..ff27dd7c2 --- /dev/null +++ b/lib/tasks/fablab/auth.rake @@ -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 diff --git a/lib/tasks/fablab/es.rake b/lib/tasks/fablab/es.rake new file mode 100644 index 000000000..c0a8f1ddc --- /dev/null +++ b/lib/tasks/fablab/es.rake @@ -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 diff --git a/lib/tasks/fablab/fix.rake b/lib/tasks/fablab/fix.rake index d1c3d5070..d1119c3be 100644 --- a/lib/tasks/fablab/fix.rake +++ b/lib/tasks/fablab/fix.rake @@ -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 - 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 - 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 + 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 + 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 + rescue ActiveRecord::RecordNotFound + failed_ids.push recurrent_event_id 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 diff --git a/lib/tasks/fablab/maintenance.rake b/lib/tasks/fablab/maintenance.rake new file mode 100644 index 000000000..ae09b4dd3 --- /dev/null +++ b/lib/tasks/fablab/maintenance.rake @@ -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 diff --git a/lib/tasks/fablab/openlab.rake b/lib/tasks/fablab/openlab.rake index a1e78bf79..053042430 100644 --- a/lib/tasks/fablab/openlab.rake +++ b/lib/tasks/fablab/openlab.rake @@ -1,3 +1,6 @@ +# frozen_string_literal: true + +# OpenLab Projects tasks namespace :fablab do namespace :openlab do desc 'bulk and export projects to openlab' diff --git a/lib/tasks/fablab/stripe.rake b/lib/tasks/fablab/stripe.rake new file mode 100644 index 000000000..85e7e3e21 --- /dev/null +++ b/lib/tasks/fablab/stripe.rake @@ -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