aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/controllers/compliance_control_sets_controller.rb40
-rw-r--r--app/controllers/statuses_controller.rb20
-rw-r--r--app/decorators/compliance_control_set_decorator.rb2
-rw-r--r--app/models/compliance_check_set.rb14
-rw-r--r--app/models/concerns/min_max_values_validation.rb1
-rw-r--r--app/models/import.rb10
-rw-r--r--app/models/referential.rb1
-rw-r--r--app/models/vehicle_journey_control/delta.rb1
-rw-r--r--app/models/vehicle_journey_control/waiting_time.rb1
-rw-r--r--app/services/parent_import_notifier.rb15
-rw-r--r--app/services/parent_notifier.rb19
-rw-r--r--app/views/vehicle_journeys/show.rabl4
-rw-r--r--config/locales/vehicle_journeys.fr.yml2
-rw-r--r--config/routes.rb2
-rw-r--r--config/schedule.rb6
-rw-r--r--lib/tasks/compliance_check_sets.rb11
-rw-r--r--lib/tasks/imports.rake7
-rw-r--r--spec/controllers/statuses_controller_spec.rb50
-rw-r--r--spec/controllers/vehicle_journeys_controller_spec.rb24
-rw-r--r--spec/factories/compliance_controls/vehicle_journey_control_factories.rb2
-rw-r--r--spec/models/compliance_check_spec.rb32
-rw-r--r--spec/models/import_spec.rb52
-rw-r--r--spec/services/parent_notifier_spec.rb (renamed from spec/services/parent_import_notifier_spec.rb)16
23 files changed, 301 insertions, 31 deletions
diff --git a/app/controllers/compliance_control_sets_controller.rb b/app/controllers/compliance_control_sets_controller.rb
index ae1d01feb..8f9251155 100644
--- a/app/controllers/compliance_control_sets_controller.rb
+++ b/app/controllers/compliance_control_sets_controller.rb
@@ -7,10 +7,8 @@ class ComplianceControlSetsController < ChouetteController
def index
index! do |format|
- scope = self.ransack_period_range(scope: @compliance_control_sets, error_message: t('imports.filters.error_period_filter'), query: :where_updated_at_between)
- @q_for_form = scope.ransack(params[:q])
format.html {
- @compliance_control_sets = decorate_compliance_control_sets(@q_for_form.result.paginate(page: params[:page], per_page: 30))
+ @compliance_control_sets = decorate_compliance_control_sets(@compliance_control_sets)
}
end
end
@@ -37,6 +35,14 @@ class ComplianceControlSetsController < ChouetteController
private
+ def collection
+ scope = self.ransack_period_range(scope: ComplianceControlSet.all, error_message: t('imports.filters.error_period_filter'), query: :where_updated_at_between)
+ @q_for_form = scope.ransack(params[:q])
+ compliance_control_sets = @q_for_form.result
+ compliance_control_sets = joins_with_associated_objects(compliance_control_sets).order(sort_column + ' ' + sort_direction) if sort_column && sort_direction
+ @compliance_control_sets = compliance_control_sets.paginate(page: params[:page], per_page: 30)
+ end
+
def decorate_compliance_control_sets(compliance_control_sets)
ComplianceControlSetDecorator.decorate(compliance_control_sets)
end
@@ -58,4 +64,32 @@ class ComplianceControlSetsController < ChouetteController
@direct_compliance_controls = compliance_controls.delete nil
@blocks_to_compliance_controls_map = compliance_controls
end
+
+ def sort_column
+ case params[:sort]
+ when 'name' then 'lower(compliance_control_sets.name)'
+ when 'owner_jdc' then 'lower(organisations.name)'
+ when 'control_numbers' then 'COUNT(compliance_controls.id)'
+ else
+ ComplianceControlSet.column_names.include?(params[:sort]) ? params[:sort] : 'lower(compliance_control_sets.name)'
+ end
+ end
+
+ def joins_with_associated_objects(collection)
+
+ # dont know if this is the right way to do it but since we need to join table deoending of the params
+ # it was to avoid loading associated objects if we don't need them
+ case params[:sort]
+ when 'owner_jdc'
+ collection.joins("LEFT JOIN organisations ON compliance_control_sets.organisation_id = organisations.id")
+ when 'control_numbers'
+ collection.joins("LEFT JOIN compliance_controls ON compliance_controls.compliance_control_set_id = compliance_control_sets.id").group(:id)
+ else
+ collection
+ end
+ end
+
+ def sort_direction
+ %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
+ end
end
diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb
new file mode 100644
index 000000000..e38a92982
--- /dev/null
+++ b/app/controllers/statuses_controller.rb
@@ -0,0 +1,20 @@
+class StatusesController < ChouetteController
+ respond_to :json
+
+ def index
+
+ status = {
+ referentials_blocked: Referential.blocked.count,
+ imports_blocked: Import.blocked.count,
+ compliance_check_sets_blocked: ComplianceCheckSet.blocked.count
+ }
+ status[:status] = global_status status
+ render json: status.to_json
+ end
+
+ private
+
+ def global_status status
+ status.values.all?(&:zero?) ? 'ok' : 'ko'
+ end
+end
diff --git a/app/decorators/compliance_control_set_decorator.rb b/app/decorators/compliance_control_set_decorator.rb
index 387822c67..b16a06886 100644
--- a/app/decorators/compliance_control_set_decorator.rb
+++ b/app/decorators/compliance_control_set_decorator.rb
@@ -6,6 +6,8 @@ class ComplianceControlSetDecorator < AF83::Decorator
end
with_instance_decorator do |instance_decorator|
+ instance_decorator.show_action_link
+
instance_decorator.edit_action_link do |l|
l.content t('compliance_control_sets.actions.edit')
end
diff --git a/app/models/compliance_check_set.rb b/app/models/compliance_check_set.rb
index f4c44d26d..289fc134f 100644
--- a/app/models/compliance_check_set.rb
+++ b/app/models/compliance_check_set.rb
@@ -19,6 +19,20 @@ class ComplianceCheckSet < ActiveRecord::Base
where('created_at BETWEEN :begin AND :end', begin: period_range.begin, end: period_range.end)
end
+ scope :blocked, -> { where('created_at < ? AND status = ?', 4.hours.ago, 'running') }
+
+ def self.finished_statuses
+ %w(successful failed warning aborted canceled)
+ end
+
+ def self.abort_old
+ where(
+ 'created_at < ? AND status NOT IN (?)',
+ 4.hours.ago,
+ finished_statuses
+ ).update_all(status: 'aborted')
+ end
+
def notify_parent
if parent
# parent.child_change
diff --git a/app/models/concerns/min_max_values_validation.rb b/app/models/concerns/min_max_values_validation.rb
index 9b2e0d548..eff779d81 100644
--- a/app/models/concerns/min_max_values_validation.rb
+++ b/app/models/concerns/min_max_values_validation.rb
@@ -2,6 +2,7 @@ module MinMaxValuesValidation
extend ActiveSupport::Concern
included do
+ validates_presence_of :minimum, :maximum
validate :min_max_values_validation
end
diff --git a/app/models/import.rb b/app/models/import.rb
index 049a65f40..29aadcd56 100644
--- a/app/models/import.rb
+++ b/app/models/import.rb
@@ -13,6 +13,8 @@ class Import < ActiveRecord::Base
where('started_at BETWEEN :begin AND :end', begin: period_range.begin, end: period_range.end)
end
+ scope :blocked, -> { where('created_at < ? AND status = ?', 4.hours.ago, 'running') }
+
extend Enumerize
enumerize :status, in: %w(new pending successful warning failed running aborted canceled), scope: true, default: :new
@@ -42,6 +44,14 @@ class Import < ActiveRecord::Base
%w(successful failed warning aborted canceled)
end
+ def self.abort_old
+ where(
+ 'created_at < ? AND status NOT IN (?)',
+ 4.hours.ago,
+ finished_statuses
+ ).update_all(status: 'aborted')
+ end
+
def notify_parent
parent.child_change
update(notified_parent_at: DateTime.now)
diff --git a/app/models/referential.rb b/app/models/referential.rb
index f64db4ebf..509e0412f 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -62,6 +62,7 @@ class Referential < ActiveRecord::Base
scope :order_by_validity_period, ->(dir) { joins(:metadatas).order("unnest(periodes) #{dir}") }
scope :order_by_lines, ->(dir) { joins(:metadatas).group("referentials.id").order("sum(array_length(referential_metadata.line_ids,1)) #{dir}") }
scope :not_in_referential_suite, -> { where referential_suite_id: nil }
+ scope :blocked, -> { where('ready = ? AND created_at < ?', false, 4.hours.ago) }
def save_with_table_lock_timeout(options = {})
save_without_table_lock_timeout(options)
diff --git a/app/models/vehicle_journey_control/delta.rb b/app/models/vehicle_journey_control/delta.rb
index f061b9fdd..737b7d78c 100644
--- a/app/models/vehicle_journey_control/delta.rb
+++ b/app/models/vehicle_journey_control/delta.rb
@@ -4,6 +4,7 @@ module VehicleJourneyControl
store_accessor :control_attributes, :maximum
validates_numericality_of :maximum, allow_nil: true, greater_than_or_equal_to: 0
+ validates_presence_of :maximum
def self.default_code; "3-VehicleJourney-3" end
end
diff --git a/app/models/vehicle_journey_control/waiting_time.rb b/app/models/vehicle_journey_control/waiting_time.rb
index f2666cb72..89a18a5d9 100644
--- a/app/models/vehicle_journey_control/waiting_time.rb
+++ b/app/models/vehicle_journey_control/waiting_time.rb
@@ -3,6 +3,7 @@ module VehicleJourneyControl
store_accessor :control_attributes, :maximum
validates_numericality_of :maximum, allow_nil: true, greater_than_or_equal_to: 0
+ validates_presence_of :maximum
def self.default_code; "3-VehicleJourney-1" end
end
diff --git a/app/services/parent_import_notifier.rb b/app/services/parent_import_notifier.rb
deleted file mode 100644
index 47e6755e4..000000000
--- a/app/services/parent_import_notifier.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class ParentImportNotifier
- def self.notify_when_finished(imports = nil)
- imports ||= imports_pending_notification
- imports.each(&:notify_parent)
- end
-
- def self.imports_pending_notification
- Import
- .where(
- notified_parent_at: nil,
- status: Import.finished_statuses
- )
- .where.not(parent: nil)
- end
-end
diff --git a/app/services/parent_notifier.rb b/app/services/parent_notifier.rb
new file mode 100644
index 000000000..653c98aff
--- /dev/null
+++ b/app/services/parent_notifier.rb
@@ -0,0 +1,19 @@
+class ParentNotifier
+ def initialize(klass)
+ @klass = klass
+ end
+
+ def notify_when_finished(collection = nil)
+ collection ||= objects_pending_notification
+ collection.each(&:notify_parent)
+ end
+
+ def objects_pending_notification
+ @klass
+ .where(
+ notified_parent_at: nil,
+ status: @klass.finished_statuses
+ )
+ .where.not(parent: nil)
+ end
+end
diff --git a/app/views/vehicle_journeys/show.rabl b/app/views/vehicle_journeys/show.rabl
index dca0866b3..546c851a4 100644
--- a/app/views/vehicle_journeys/show.rabl
+++ b/app/views/vehicle_journeys/show.rabl
@@ -39,10 +39,8 @@ child :footnotes, :object_root => false do |footnotes|
end
child(:vehicle_journey_at_stops_matrix, :object_root => false) do |vehicle_stops|
+ attributes :id, :connecting_service_id, :boarding_alighting_possibility
node do |vehicle_stop|
- [:id, :connecting_service_id, :boarding_alighting_possibility].map do |att|
- node(att) { vehicle_stop.send(att) ? vehicle_stop.send(att) : nil }
- end
node(:dummy) { vehicle_stop.dummy }
node(:area_kind) { vehicle_stop.stop_point.stop_area.kind }
diff --git a/config/locales/vehicle_journeys.fr.yml b/config/locales/vehicle_journeys.fr.yml
index 6bf167234..1034a3fba 100644
--- a/config/locales/vehicle_journeys.fr.yml
+++ b/config/locales/vehicle_journeys.fr.yml
@@ -124,7 +124,7 @@ fr:
published_journey_name: "Nom public"
purchase_window: "Disponibilité commerciale"
regular_fs: "Service régulier"
- route: "Séquence d'arrêt"
+ route: "Itinéraire"
status_value: "Etat de trafic"
time_slot: "Fréquence"
time_table_ids: "Liste des calendriers"
diff --git a/config/routes.rb b/config/routes.rb
index 2715ca428..0b657b028 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -256,4 +256,6 @@ ChouetteIhm::Application.routes.draw do
match '/422', to: 'errors#server_error', via: :all, as: 'unprocessable_entity'
match '/500', to: 'errors#server_error', via: :all, as: 'server_error'
+ match '/status', to: 'statuses#index', via: :get
+
end
diff --git a/config/schedule.rb b/config/schedule.rb
index 08488c255..0d2a24f31 100644
--- a/config/schedule.rb
+++ b/config/schedule.rb
@@ -40,9 +40,15 @@ every :day, :at => '4:00 am' do
end
every 5.minutes do
+ rake "import:netex_abort_old"
rake "import:notify_parent"
end
+every 5.minutes do
+ rake "compliance_check_sets:abort_old"
+ rake "compliance_check_sets:notify_parent"
+end
+
every 1.minute do
command "/bin/echo HeartBeat"
end
diff --git a/lib/tasks/compliance_check_sets.rb b/lib/tasks/compliance_check_sets.rb
new file mode 100644
index 000000000..c53c7f9ed
--- /dev/null
+++ b/lib/tasks/compliance_check_sets.rb
@@ -0,0 +1,11 @@
+namespace :compliance_check_sets do
+ desc "Notify parent check sets when children finish"
+ task notify_parent: :environment do
+ ParentNotifier.new(ComplianceCheckSet).notify_when_finished
+ end
+
+ desc "Mark old unfinished check sets as 'aborted'"
+ task abort_old: :environment do
+ ComplianceCheckSet.abort_old
+ end
+end
diff --git a/lib/tasks/imports.rake b/lib/tasks/imports.rake
index 6bc84acc8..02e32fd3d 100644
--- a/lib/tasks/imports.rake
+++ b/lib/tasks/imports.rake
@@ -1,6 +1,11 @@
namespace :import do
desc "Notify parent imports when children finish"
task notify_parent: :environment do
- ParentImportNotifier.notify_when_finished
+ ParentNotifier.new(Import).notify_when_finished
+ end
+
+ desc "Mark old unfinished Netex imports as 'aborted'"
+ task netex_abort_old: :environment do
+ NetexImport.abort_old
end
end
diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb
new file mode 100644
index 000000000..8a6db8e28
--- /dev/null
+++ b/spec/controllers/statuses_controller_spec.rb
@@ -0,0 +1,50 @@
+RSpec.describe StatusesController, :type => :controller do
+
+ describe "GET index" do
+ login_user
+ render_views
+
+
+ let(:request){ get :index}
+ let(:parsed_response){ JSON.parse response.body }
+ it "should be ok" do
+ request
+ expect(response).to have_http_status 200
+ expect(parsed_response["status"]).to eq "ok"
+ end
+ context "without blocked object" do
+ before do
+ create :referential
+ create :import
+ create :compliance_check_set
+ request
+ end
+
+ it "should be ok" do
+ expect(response).to have_http_status 200
+ expect(parsed_response["status"]).to eq "ok"
+ expect(parsed_response["referentials_blocked"]).to eq 0
+ expect(parsed_response["imports_blocked"]).to eq 0
+ expect(parsed_response["imports_blocked"]).to eq 0
+ end
+ end
+
+ context "with a blocked object" do
+ before do
+ create :referential, created_at: 5.hours.ago, ready: false
+ create :import
+ create :compliance_check_set
+ request
+ end
+
+ it "should be ko" do
+ expect(Referential.blocked.count).to eq 1
+ expect(response).to have_http_status 200
+ expect(parsed_response["status"]).to eq "ko"
+ expect(parsed_response["referentials_blocked"]).to eq 1
+ expect(parsed_response["imports_blocked"]).to eq 0
+ expect(parsed_response["imports_blocked"]).to eq 0
+ end
+ end
+ end
+end
diff --git a/spec/controllers/vehicle_journeys_controller_spec.rb b/spec/controllers/vehicle_journeys_controller_spec.rb
index 416450c21..300684532 100644
--- a/spec/controllers/vehicle_journeys_controller_spec.rb
+++ b/spec/controllers/vehicle_journeys_controller_spec.rb
@@ -26,4 +26,28 @@ RSpec.describe VehicleJourneysController, :type => :controller do
end
end
+ describe "GET index" do
+ login_user
+ render_views
+
+ context "in JSON" do
+ let(:vehicle_journey){ create :vehicle_journey }
+ let(:route){ vehicle_journey.route }
+ let(:line){ route.line }
+ let!(:request){ get :index, referential_id: referential.id, line_id: line.id, route_id: route.id, format: :json}
+ let(:parsed_response){ JSON.parse response.body }
+ it "should have all the attributes" do
+ expect(response).to have_http_status 200
+ vehicle_journey = parsed_response["vehicle_journeys"].first
+ vehicle_journey_at_stops_matrix = vehicle_journey["vehicle_journey_at_stops"]
+ vehicle_journey_at_stops_matrix.each do |received_vjas|
+ expect(received_vjas).to have_key("id")
+ vjas = Chouette::VehicleJourneyAtStop.find received_vjas["id"]
+ [:connecting_service_id, :boarding_alighting_possibility].each do |att|
+ expect(received_vjas[att]).to eq vjas.send(att)
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/factories/compliance_controls/vehicle_journey_control_factories.rb b/spec/factories/compliance_controls/vehicle_journey_control_factories.rb
index e8f68cbdf..86a335aba 100644
--- a/spec/factories/compliance_controls/vehicle_journey_control_factories.rb
+++ b/spec/factories/compliance_controls/vehicle_journey_control_factories.rb
@@ -1,10 +1,12 @@
FactoryGirl.define do
factory :vehicle_journey_control_wating_time, class: 'VehicleJourneyControl::WaitingTime' do
+ maximum 10
association :compliance_control_set
end
factory :vehicle_journey_control_delta, class: 'VehicleJourneyControl::Delta' do
+ maximum 10
association :compliance_control_set
end
diff --git a/spec/models/compliance_check_spec.rb b/spec/models/compliance_check_spec.rb
index f83d78c29..ffa59245c 100644
--- a/spec/models/compliance_check_spec.rb
+++ b/spec/models/compliance_check_spec.rb
@@ -15,4 +15,36 @@ RSpec.describe ComplianceCheck, type: :model do
it { should validate_presence_of :name }
it { should validate_presence_of :code }
it { should validate_presence_of :origin_code }
+
+ describe ".abort_old" do
+ it "changes check sets older than 4 hours to aborted" do
+ Timecop.freeze(Time.now) do
+ old_check_set = create(
+ :compliance_check_set,
+ status: 'pending',
+ created_at: 4.hours.ago - 1.minute
+ )
+ current_check_set = create(:compliance_check_set, status: 'pending')
+
+ ComplianceCheckSet.abort_old
+
+ expect(current_check_set.reload.status).to eq('pending')
+ expect(old_check_set.reload.status).to eq('aborted')
+ end
+ end
+
+ it "doesn't work on check sets with a `finished_status`" do
+ Timecop.freeze(Time.now) do
+ check_set = create(
+ :compliance_check_set,
+ status: 'successful',
+ created_at: 4.hours.ago - 1.minute
+ )
+
+ ComplianceCheckSet.abort_old
+
+ expect(check_set.reload.status).to eq('successful')
+ end
+ end
+ end
end
diff --git a/spec/models/import_spec.rb b/spec/models/import_spec.rb
index ffb2360c2..8b85f151b 100644
--- a/spec/models/import_spec.rb
+++ b/spec/models/import_spec.rb
@@ -29,6 +29,58 @@ RSpec.describe Import, type: :model do
)
end
+ describe ".abort_old" do
+ it "changes imports older than 4 hours to aborted" do
+ Timecop.freeze(Time.now) do
+ old_import = create(
+ :workbench_import,
+ status: 'pending',
+ created_at: 4.hours.ago - 1.minute
+ )
+ current_import = create(:workbench_import, status: 'pending')
+
+ Import.abort_old
+
+ expect(current_import.reload.status).to eq('pending')
+ expect(old_import.reload.status).to eq('aborted')
+ end
+ end
+
+ it "doesn't work on imports with a `finished_status`" do
+ Timecop.freeze(Time.now) do
+ import = create(
+ :workbench_import,
+ status: 'successful',
+ created_at: 4.hours.ago - 1.minute
+ )
+
+ Import.abort_old
+
+ expect(import.reload.status).to eq('successful')
+ end
+ end
+
+ it "only works on the caller type" do
+ Timecop.freeze(Time.now) do
+ workbench_import = create(
+ :workbench_import,
+ status: 'pending',
+ created_at: 4.hours.ago - 1.minute
+ )
+ netex_import = create(
+ :netex_import,
+ status: 'pending',
+ created_at: 4.hours.ago - 1.minute
+ )
+
+ NetexImport.abort_old
+
+ expect(workbench_import.reload.status).to eq('pending')
+ expect(netex_import.reload.status).to eq('aborted')
+ end
+ end
+ end
+
describe "#destroy" do
it "must destroy all child imports" do
netex_import = create(:netex_import)
diff --git a/spec/services/parent_import_notifier_spec.rb b/spec/services/parent_notifier_spec.rb
index 3ab505f88..ecf508fcd 100644
--- a/spec/services/parent_import_notifier_spec.rb
+++ b/spec/services/parent_notifier_spec.rb
@@ -1,4 +1,4 @@
-RSpec.describe ParentImportNotifier do
+RSpec.describe ParentNotifier do
let(:workbench_import) { create(:workbench_import) }
describe ".notify_when_finished" do
@@ -20,7 +20,7 @@ RSpec.describe ParentImportNotifier do
expect(netex_import).to receive(:notify_parent)
end
- ParentImportNotifier.notify_when_finished(netex_imports)
+ ParentNotifier.new(Import).notify_when_finished(netex_imports)
end
it "doesn't call #notify_parent if its `notified_parent_at` is set" do
@@ -33,11 +33,11 @@ RSpec.describe ParentImportNotifier do
expect(netex_import).not_to receive(:notify_parent)
- ParentImportNotifier.notify_when_finished
+ ParentNotifier.new(Import).notify_when_finished
end
end
- describe ".imports_pending_notification" do
+ describe ".objects_pending_notification" do
it "includes imports with a parent and `notified_parent_at` unset" do
netex_import = create(
:netex_import,
@@ -47,7 +47,7 @@ RSpec.describe ParentImportNotifier do
)
expect(
- ParentImportNotifier.imports_pending_notification
+ ParentNotifier.new(Import).objects_pending_notification
).to eq([netex_import])
end
@@ -55,7 +55,7 @@ RSpec.describe ParentImportNotifier do
create(:import, parent: nil)
expect(
- ParentImportNotifier.imports_pending_notification
+ ParentNotifier.new(Import).objects_pending_notification
).to be_empty
end
@@ -70,7 +70,7 @@ RSpec.describe ParentImportNotifier do
end
expect(
- ParentImportNotifier.imports_pending_notification
+ ParentNotifier.new(Import).objects_pending_notification
).to be_empty
end
@@ -83,7 +83,7 @@ RSpec.describe ParentImportNotifier do
)
expect(
- ParentImportNotifier.imports_pending_notification
+ ParentNotifier.new(Import).objects_pending_notification
).to be_empty
end
end