diff --git a/Gemfile b/Gemfile index 36b2b76..44d17b2 100644 --- a/Gemfile +++ b/Gemfile @@ -11,7 +11,7 @@ end gemspec -gem "rails", "~> 5.1" +gem "rails", "~> 8.0" group :development, :test do gem 'bootsnap', require: false @@ -28,6 +28,7 @@ group :development, :test do gem 'puma' gem 'paperclip', '~> 5.3' gem 'dunlop-ember', gitlab: 'benja-2/dunlop-ember', branch: 'master' + gem 'record_collection' #, github: 'bterkuile/record_collection', branch: 'master' #gem 'carrierwave' #gem 'fog-aws' diff --git a/app/services/dunlop/loggable.rb b/app/services/dunlop/loggable.rb index 934ae5f..a6dbb3c 100644 --- a/app/services/dunlop/loggable.rb +++ b/app/services/dunlop/loggable.rb @@ -6,7 +6,7 @@ module Dunlop::Loggable end def with_nested_logger_and_catch_failed(scope=nil, options={}) - scope ||= caller[0][/`.*'/][1..-2] + scope ||= caller[0][/'.*'/][1..-2] options[:exception_notifier] = true unless options.has_key?(:exception_notifier) backtrace = nil ::Dunlop::NestedLogger.scope('empty sandbox', benchmark: false) do diff --git a/app/services/dunlop/overdue_handling.rb b/app/services/dunlop/overdue_handling.rb index 618db30..0252223 100644 --- a/app/services/dunlop/overdue_handling.rb +++ b/app/services/dunlop/overdue_handling.rb @@ -1,124 +1,126 @@ -module Dunlop::OverdueHandling - @registry = {} - @final_states = %w[overdue completed rejected] +module Dunlop + module OverdueHandling + @registry = {} + @final_states = %w[overdue completed rejected] - def self.registry - @registry - end + def self.registry + @registry + end - def self.final_states - @final_states - end + def self.final_states + @final_states + end - def self.final_states=(states) - @final_states = states - end + def self.final_states=(states) + @final_states = states + end - def self.define(&block) - @registry = {} # empty the registry - definition_proxy = DefinitionProxy.new - definition_proxy.instance_eval(&block) - end + def self.define(&block) + @registry = {} # empty the registry + definition_proxy = DefinitionProxy.new + definition_proxy.instance_eval(&block) + end - def self.handle_overdue! - registry.each do |workflow_step_name, config| - base_scope = WorkflowInstance.all #where.not(state: final_states) - base_scope = base_scope.where(sti_type: config.scenarios.map{|s| "WorkflowInstance::#{s.to_s.classify}"}) if config.scenarios.any? - base_scope = base_scope.joins(workflow_step_name).where.not("#{workflow_step_name.to_s.pluralize}.state" => final_states) #.includes(workflow_step_name) - if config.from.is_nested? - base_scope = base_scope.joins(config.from.key) if config.from.key != workflow_step_name - end - base_scope = base_scope.where("#{config.date_target_class.table_name}.#{config.date_target_column} <= ?", Date.current - config.time) + def self.handle_overdue! + registry.each do |workflow_step_name, config| + base_scope = WorkflowInstance.all #where.not(state: final_states) + base_scope = base_scope.where(sti_type: config.scenarios.map{|s| "WorkflowInstance::#{s.to_s.classify}"}) if config.scenarios.any? + base_scope = base_scope.joins(workflow_step_name).where.not("#{workflow_step_name.to_s.pluralize}.state" => final_states) #.includes(workflow_step_name) + if config.from.is_nested? + base_scope = base_scope.joins(config.from.key) if config.from.key != workflow_step_name + end + base_scope = base_scope.where("#{config.date_target_class.table_name}.#{config.date_target_column} <= ?", Date.current - config.time) - base_scope.find_each do |workflow_instance| - next unless workflow_step = workflow_instance.public_send(workflow_step_name) - workflow_step.is_overdue! + base_scope.find_each do |workflow_instance| + next unless workflow_step = workflow_instance.public_send(workflow_step_name) + workflow_step.is_overdue! + end end end - end - class DefinitionProxy - def when_workflow_step(workflow_step, options = {}, &block) - raise "Workflow step #{workflow_step} does not exist" unless WorkflowInstance.possible_workflow_step_names.include?(workflow_step) - workflow_step_proxy = WorkflowStepProxy.new(workflow_step, options) - workflow_step_proxy.instance_eval(&block) if block - workflow_step_proxy.register_callbacks! - ::Dunlop::OverdueHandling.registry[workflow_step] = workflow_step_proxy + class DefinitionProxy + def when_workflow_step(workflow_step, options = {}, &block) + raise "Workflow step #{workflow_step} does not exist" unless WorkflowInstance.possible_workflow_step_names.include?(workflow_step) + workflow_step_proxy = WorkflowStepProxy.new(workflow_step, options) + workflow_step_proxy.instance_eval(&block) if block + workflow_step_proxy.register_callbacks! + ::Dunlop::OverdueHandling.registry[workflow_step] = workflow_step_proxy + end + + def the_final_states_are(states) + ::Dunlop::OverdueHandling.final_states = states + end end - def the_final_states_are(states) - ::Dunlop::OverdueHandling.final_states = states - end - end + class WorkflowStepProxy + attr_reader :workflow_step, :options, :overdue_target_class + def initialize(workflow_step, options) + @workflow_step, @options = workflow_step, options + @overdue_target_class = workflow_step.to_s.classify.constantize + end - class WorkflowStepProxy - attr_reader :workflow_step, :options, :overdue_target_class - def initialize(workflow_step, options) - @workflow_step, @options = workflow_step, options - @overdue_target_class = workflow_step.to_s.classify.constantize - end + def date_target_class + @date_target_class ||= from.is_nested? ? from.key.to_s.classify.constantize : WorkflowInstance + end - def date_target_class - @date_target_class ||= from.is_nested? ? from.key.to_s.classify.constantize : WorkflowInstance - end + def date_target_column + @date_target_column ||= from.field + end - def date_target_column - @date_target_column ||= from.field - end + def scenarios + options[:scenarios] || [] + end - def scenarios - options[:scenarios] || [] - end + def from + WorkflowStepBaseDate.new(workflow_step, options[:from]) + end - def from - WorkflowStepBaseDate.new(workflow_step, options[:from]) - end + def time + options[:is] + end - def time - options[:is] - end - - #TODO: find a simple way to do this!!! - def register_callbacks! - date_target_classes = [date_target_class] #TODO: only implement on specific scenarios if given as argument - date_column = date_target_column - workflow_step_name = workflow_step # make local scope for after_save definition - overdue_time = time - date_target_classes.each do |target_class| - target_class.after_save do |record| - if saved_changes[date_column] - target_record = record.workflow_instance.public_send(workflow_step_name) - if date = record.public_send(date_column) - if date <= Date.current - overdue_time - target_record.is_overdue! if target_record.pending? or target_record.processing? + #TODO: find a simple way to do this!!! + def register_callbacks! + date_target_classes = [date_target_class] #TODO: only implement on specific scenarios if given as argument + date_column = date_target_column + workflow_step_name = workflow_step # make local scope for after_save definition + overdue_time = time + date_target_classes.each do |target_class| + target_class.after_save do |record| + if saved_changes[date_column] + target_record = record.workflow_instance.public_send(workflow_step_name) + if date = record.public_send(date_column) + if date <= Date.current - overdue_time + target_record.is_overdue! if target_record.pending? or target_record.processing? + else + target_record.process! if target_record.overdue? + end else target_record.process! if target_record.overdue? end - else - target_record.process! if target_record.overdue? end end end end end - end - class WorkflowStepBaseDate - attr_reader :workflow_step, :config - def initialize(workflow_step, config) - @workflow_step, @config = workflow_step, config - end + class WorkflowStepBaseDate + attr_reader :workflow_step, :config + def initialize(workflow_step, config) + @workflow_step, @config = workflow_step, config + end - def is_nested? - config.is_a?(Hash) - end + def is_nested? + config.is_a?(Hash) + end - def key - is_nested? ? config.keys.first : config - end + def key + is_nested? ? config.keys.first : config + end - def field - is_nested? ? config.values.first : config + def field + is_nested? ? config.values.first : config + end end end end diff --git a/bin/rails b/bin/rails index e22bfcc..a97d4f2 100755 --- a/bin/rails +++ b/bin/rails @@ -3,6 +3,7 @@ ENGINE_ROOT = File.expand_path('../..', __FILE__) ENGINE_PATH = File.expand_path('../../lib/dunlop/engine', __FILE__) +APP_PATH = File.expand_path("../spec/dummy/config/application", __dir__) # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) diff --git a/dunlop-core.gemspec b/dunlop-core.gemspec index 0d59659..413d41a 100644 --- a/dunlop-core.gemspec +++ b/dunlop-core.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new do |s| s.add_dependency "rails", ">= 4.2.6" s.add_dependency 'slim-rails' - #s.add_dependency 'record_collection', '>= 0.10.4' + #s.add_dependency 'record_collection', '>= 0.10.4' # Only in Gemfile to make not requried s.add_dependency 'request_store' s.add_dependency 'ransack' s.add_dependency 'responders' @@ -31,6 +31,7 @@ Gem::Specification.new do |s| s.add_dependency 'facets' s.add_dependency 'memoist' s.add_dependency 'cancancan' + s.add_dependency 'csv' # assets #s.add_dependency 'momentjs-rails' diff --git a/lib/generators/dunlop/install/base/base_generator.rb b/lib/generators/dunlop/install/base/base_generator.rb index c164d85..3d41ba5 100644 --- a/lib/generators/dunlop/install/base/base_generator.rb +++ b/lib/generators/dunlop/install/base/base_generator.rb @@ -36,8 +36,8 @@ class Dunlop::Install::BaseGenerator < Rails::Generators::Base config.application_name = "#{Rails.application.class.name.deconstantize}" config.git_version = Rails.env - config.git_version = File.read('REVISION').strip if File.exists?('REVISION') - config.git_version = File.read('OFFLINE_REVISION').strip if File.exists?('OFFLINE_REVISION') + config.git_version = File.read('REVISION').strip if File.exist?('REVISION') + config.git_version = File.read('OFFLINE_REVISION').strip if File.exist?('OFFLINE_REVISION') RUBY end diff --git a/spec/dummy/app/assets/config/manifest.js b/spec/dummy/app/assets/config/manifest.js new file mode 100644 index 0000000..89c89e7 --- /dev/null +++ b/spec/dummy/app/assets/config/manifest.js @@ -0,0 +1,3 @@ + //= link_tree ../images + //= link_directory ../javascripts .js + //= link_directory ../stylesheets .css diff --git a/spec/dummy/app/models/owner_initialization.rb b/spec/dummy/app/models/owner_initialization.rb index 0ede1be..3d0297f 100644 --- a/spec/dummy/app/models/owner_initialization.rb +++ b/spec/dummy/app/models/owner_initialization.rb @@ -1,8 +1,8 @@ class OwnerInitialization < ApplicationRecord include WorkflowStepModel - serialize :window_from, DayTimeMinutes - serialize :window_to, DayTimeMinutes + serialize :window_from, coder: DayTimeMinutes + serialize :window_to, coder: DayTimeMinutes activate_dunlop! end diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb index 44c25a6..1c29cb1 100644 --- a/spec/dummy/config/application.rb +++ b/spec/dummy/config/application.rb @@ -22,8 +22,8 @@ module Dummy config.application_name = 'Dunlop' config.git_version = nil - config.git_version = File.read('REVISION').strip if File.exists?('REVISION') - config.git_version = File.read('OFFLINE_REVISION').strip if File.exists?('OFFLINE_REVISION') + config.git_version = File.read('REVISION').strip if File.exist?('REVISION') + config.git_version = File.read('OFFLINE_REVISION').strip if File.exist?('OFFLINE_REVISION') config.file_storage_path = Rails.root.join('files') # source file storage config.working_path = '/tmp' # source file processing directory diff --git a/spec/dummy/config/initializers/dunlop_overdue_config.rb b/spec/dummy/config/initializers/dunlop_overdue_config.rb index b6e4d49..60426d1 100644 --- a/spec/dummy/config/initializers/dunlop_overdue_config.rb +++ b/spec/dummy/config/initializers/dunlop_overdue_config.rb @@ -1,3 +1,5 @@ -Dunlop::OverdueHandling.define do - when_workflow_step :contractor_initialization, is: 2.days, from: {owner_initialization: :plan_date} +Rails.application.config.after_initialize do + Dunlop::OverdueHandling.define do + when_workflow_step :contractor_initialization, is: 2.days, from: {owner_initialization: :plan_date} + end end diff --git a/spec/dummy/config/initializers/dunlop_workflow_config.rb b/spec/dummy/config/initializers/dunlop_workflow_config.rb index 9e24c2a..09e403c 100644 --- a/spec/dummy/config/initializers/dunlop_workflow_config.rb +++ b/spec/dummy/config/initializers/dunlop_workflow_config.rb @@ -1,3 +1,5 @@ -Dunlop::Workflow.configure do |config| - config.max_number_of_records_in_display_badge = 72 +Rails.application.config.after_initialize do + Dunlop::Workflow.configure do |config| + config.max_number_of_records_in_display_badge = 72 + end end diff --git a/spec/dummy/config/initializers/dunlop_workflow_steps_in_batch_finished_config.rb b/spec/dummy/config/initializers/dunlop_workflow_steps_in_batch_finished_config.rb index 273a0d0..b1ad5ca 100644 --- a/spec/dummy/config/initializers/dunlop_workflow_steps_in_batch_finished_config.rb +++ b/spec/dummy/config/initializers/dunlop_workflow_steps_in_batch_finished_config.rb @@ -1,28 +1,30 @@ -Dunlop::WorkflowStepsInBatchFinished.define do - the_final_states_are %w[rejected completed] +Rails.application.config.after_initialize do + Dunlop::WorkflowStepsInBatchFinished.define do + the_final_states_are %w[rejected completed] - on_finishing_of :owner_initialization do - description "Send notification mail to Owner" do |workflow_instance_batch| - OwnerMailer.owner_initialization_finished(workflow_instance_batch, self).deliver_later + on_finishing_of :owner_initialization do + description "Send notification mail to Owner" do |workflow_instance_batch| + OwnerMailer.owner_initialization_finished(workflow_instance_batch, self).deliver_later + end end + + #on_finishing_of :contractor_service_window1_execution do + # description <<-DESCRIPTION + # Check ${attributes.owner_service_window2_preparation.migration_file_for_bvt_ready} + # for ${models.owner_service_window2_preparation} workflow steps in the batch + # DESCRIPTION + # action do |workflow_instance_batch| + # workflow_steps_in_batch_scope(:owner_service_window2_preparation).update_all migration_file_for_bvt_ready: true + # end + + # description "Send an email to Core Delivery informing them of batch completion" do |workflow_instance_batch| + # KpnCoreDeliveryMailer.contractor_service_window1_handled_for_batch(workflow_instance_batch.id).deliver_later + # end + + # description "Send an email to Schuuring informing them of batch completion" do |workflow_instance_batch| + # SchuuringMailer.workflow_instance_batch_workflow_step_finished(self.class.name, workflow_instance_batch.id).deliver_later + # end + #end + end - - #on_finishing_of :contractor_service_window1_execution do - # description <<-DESCRIPTION - # Check ${attributes.owner_service_window2_preparation.migration_file_for_bvt_ready} - # for ${models.owner_service_window2_preparation} workflow steps in the batch - # DESCRIPTION - # action do |workflow_instance_batch| - # workflow_steps_in_batch_scope(:owner_service_window2_preparation).update_all migration_file_for_bvt_ready: true - # end - - # description "Send an email to Core Delivery informing them of batch completion" do |workflow_instance_batch| - # KpnCoreDeliveryMailer.contractor_service_window1_handled_for_batch(workflow_instance_batch.id).deliver_later - # end - - # description "Send an email to Schuuring informing them of batch completion" do |workflow_instance_batch| - # SchuuringMailer.workflow_instance_batch_workflow_step_finished(self.class.name, workflow_instance_batch.id).deliver_later - # end - #end - end diff --git a/spec/factories/target_files.rb b/spec/factories/target_files.rb index 365535c..6eb871f 100644 --- a/spec/factories/target_files.rb +++ b/spec/factories/target_files.rb @@ -3,7 +3,7 @@ FactoryBot.define do original_file { Tempfile.new("target_file_factory") } trait :failed do after(:build) { |record| record.log_entries.build(body: 'ERROR - some reason to fail') } - state 'failed' + state { 'failed' } end end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 71114d9..ea56e9a 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -6,14 +6,14 @@ FactoryBot.define do factory :user do email - password 'password' - role_names %w[read-class-WorkflowInstance] + password { 'password' } + role_names { %w[read-class-WorkflowInstance] } end factory :admin, class: User do - email 'admin@example.com' - password 'password' - admin true + email { 'admin@example.com' } + password { 'password' } + admin { true } end end diff --git a/spec/factories/workflow_instance.rb b/spec/factories/workflow_instance.rb index b31aa67..28f89b0 100644 --- a/spec/factories/workflow_instance.rb +++ b/spec/factories/workflow_instance.rb @@ -1,29 +1,29 @@ FactoryBot.define do factory :workflow_instance do after(:build){|instance| instance.setup_workflow_steps } - state "unplanned" # default for Vula + state { "unplanned" } # default for Vula trait :uncategorized do - state 'uncategorized' + state { 'uncategorized' } end trait :unplanned do - state 'unplanned' + state { 'unplanned' } end trait :planned do - state 'planned' + state { 'planned' } end trait :active do - state 'active' + state { 'active' } after :build do |instance| instance.workflow_steps.first.state = 'processing' end end trait :overdue do - state 'overdue' + state { 'overdue' } after :build do |instance| instance.owner_initialization.plan_date = 1.year.ago instance.contractor_initialization.state = 'overdue' @@ -31,14 +31,14 @@ FactoryBot.define do end trait :all_completed do - state 'all_completed' + state { 'all_completed' } after :build do |instance| instance.workflow_steps.each{|workflow_step| workflow_step.state = 'completed' } end end trait :any_rejected do - state 'any_rejected' + state { 'any_rejected' } after :build do |instance| instance.workflow_steps.first.state = 'rejected' end diff --git a/spec/models/dunlop/execution_batch_spec.rb b/spec/models/execution_batch_spec.rb similarity index 98% rename from spec/models/dunlop/execution_batch_spec.rb rename to spec/models/execution_batch_spec.rb index d27be63..44441e1 100644 --- a/spec/models/dunlop/execution_batch_spec.rb +++ b/spec/models/execution_batch_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Dunlop::ExecutionBatch do +describe ::ExecutionBatch do let(:time) { '1981-03-09T13:33:04Z'.to_time } let(:model) { ExecutionBatch::MyBatch } before { Timecop.freeze time } diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index d1df211..9bd90ac 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -43,7 +43,7 @@ RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = 1 RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures - config.fixture_path = Dunlop::Engine.root.join("spec/fixtures") + config.fixture_paths = [Dunlop::Engine.root.join("spec/fixtures")] config.expect_with(:rspec) { |c| c.syntax = [:should, :expect] } diff --git a/spec/services/dunlop/file_zip_spec.rb b/spec/services/dunlop/file_zip_spec.rb index eee1a13..e84d6fc 100644 --- a/spec/services/dunlop/file_zip_spec.rb +++ b/spec/services/dunlop/file_zip_spec.rb @@ -20,10 +20,10 @@ RSpec.describe Dunlop::FileZip do context "mime-type: application/zip" do it "unzips the file to the provided filename" do - expect(File.exists?(destination_filename)).to be_falsey + expect(File.exist?(destination_filename)).to be_falsey subject.unzip(zipped_filename, destination_filename) - expect(File.exists?(destination_filename)).to be_truthy - expect(File.exists?(zipped_filename)).to be_truthy + expect(File.exist?(destination_filename)).to be_truthy + expect(File.exist?(zipped_filename)).to be_truthy expect(File.read(destination_filename)).to eq File.read(unzipped_filename) end @@ -34,10 +34,10 @@ RSpec.describe Dunlop::FileZip do context "mime-type: application/x-gzip" do it "unzips the file to the provided filename" do - expect(File.exists?(destination_filename)).to be_falsey + expect(File.exist?(destination_filename)).to be_falsey subject.unzip(gzipped_filename, destination_filename) - expect(File.exists?(destination_filename)).to be_truthy - expect(File.exists?(gzipped_filename)).to be_truthy + expect(File.exist?(destination_filename)).to be_truthy + expect(File.exist?(gzipped_filename)).to be_truthy expect(File.read(destination_filename)).to eq File.read(unzipped_filename) end @@ -46,10 +46,10 @@ RSpec.describe Dunlop::FileZip do context "mime-type: text/plain" do it "copies the file to the provided filename" do - expect(File.exists?(destination_filename)).to be_falsey + expect(File.exist?(destination_filename)).to be_falsey subject.unzip(unzipped_filename, destination_filename) - expect(File.exists?(destination_filename)).to be_truthy - expect(File.exists?(unzipped_filename)).to be_truthy + expect(File.exist?(destination_filename)).to be_truthy + expect(File.exist?(unzipped_filename)).to be_truthy expect(File.read(destination_filename)).to eq File.read(unzipped_filename) end @@ -69,10 +69,10 @@ RSpec.describe Dunlop::FileZip do end it "gzips the file to the provided filename" do - expect(File.exists?(gzipped_filename)).to be_falsey + expect(File.exist?(gzipped_filename)).to be_falsey subject.gzip(unzipped_filename, gzipped_filename) - expect(File.exists?(gzipped_filename)).to be_truthy - expect(File.exists?(unzipped_filename)).to be_truthy + expect(File.exist?(gzipped_filename)).to be_truthy + expect(File.exist?(unzipped_filename)).to be_truthy expect(File.size(unzipped_filename)).to eq 305 expect(File.size(gzipped_filename)).to eq 153