aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/application.js6
-rw-r--r--app/assets/stylesheets/components/_referential_overview.sass1
-rw-r--r--app/controllers/api/v1/netex_imports_controller.rb39
-rw-r--r--app/controllers/application_controller.rb3
-rw-r--r--app/controllers/chouette_controller.rb1
-rw-r--r--app/controllers/concerns/metadata_controller_support.rb26
-rw-r--r--app/controllers/concerns/paper_trail_support.rb11
-rw-r--r--app/controllers/journey_patterns_collections_controller.rb1
-rw-r--r--app/controllers/lines_controller.rb4
-rw-r--r--app/controllers/purchase_windows_controller.rb4
-rw-r--r--app/controllers/time_tables_controller.rb46
-rw-r--r--app/controllers/vehicle_journeys_collections_controller.rb4
-rw-r--r--app/controllers/vehicle_journeys_controller.rb2
-rw-r--r--app/decorators/route_decorator.rb3
-rw-r--r--app/helpers/application_helper.rb6
-rw-r--r--app/helpers/compliance_controls_helper.rb4
-rw-r--r--app/helpers/table_builder_helper.rb7
-rw-r--r--app/javascript/helpers/polyfills.js4
-rw-r--r--app/javascript/journey_patterns/actions/index.js18
-rw-r--r--app/javascript/packs/calendars/edit.js2
-rw-r--r--app/javascript/packs/exports/new.js2
-rw-r--r--app/javascript/packs/journey_patterns/index.js2
-rw-r--r--app/javascript/packs/referential_lines/show.js2
-rw-r--r--app/javascript/packs/referential_overview/overview.js2
-rw-r--r--app/javascript/packs/routes/edit.js27
-rw-r--r--app/javascript/packs/routes/show.js2
-rw-r--r--app/javascript/packs/stop_areas/new.js2
-rw-r--r--app/javascript/packs/time_tables/edit.js2
-rw-r--r--app/javascript/packs/vehicle_journeys/index.js2
-rw-r--r--app/javascript/routes/components/StopPoint.js6
-rw-r--r--app/javascript/time_tables/actions/index.js11
-rw-r--r--app/javascript/time_tables/components/ConfirmModal.js8
-rw-r--r--app/javascript/time_tables/components/ErrorModal.js8
-rw-r--r--app/javascript/time_tables/components/Metas.js8
-rw-r--r--app/javascript/time_tables/components/PeriodForm.js8
-rw-r--r--app/javascript/time_tables/components/PeriodManager.js8
-rw-r--r--app/javascript/time_tables/components/TagsSelect2.js6
-rw-r--r--app/javascript/time_tables/components/Timetable.js14
-rw-r--r--app/javascript/vehicle_journeys/actions/index.js32
-rw-r--r--app/javascript/vehicle_journeys/components/Filters.js4
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js2
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js2
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js2
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js2
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/fr.js9
-rw-r--r--app/javascript/vehicle_journeys/components/tools/select2s/language.js9
-rw-r--r--app/javascript/vehicle_journeys/reducers/vehicleJourneys.js15
-rw-r--r--app/models/api/v1/api_key.rb6
-rw-r--r--app/models/application_model.rb5
-rw-r--r--app/models/calendar.rb4
-rw-r--r--app/models/calendar/date_value.rb2
-rw-r--r--app/models/calendar/period.rb2
-rw-r--r--app/models/chouette/access_link.rb2
-rw-r--r--app/models/chouette/access_point.rb2
-rw-r--r--app/models/chouette/active_record.rb3
-rw-r--r--app/models/chouette/company.rb6
-rw-r--r--app/models/chouette/connection_link.rb2
-rw-r--r--app/models/chouette/group_of_line.rb2
-rw-r--r--app/models/chouette/journey_pattern.rb2
-rw-r--r--app/models/chouette/line.rb4
-rw-r--r--app/models/chouette/network.rb2
-rw-r--r--app/models/chouette/pt_link.rb2
-rw-r--r--app/models/chouette/purchase_window.rb2
-rw-r--r--app/models/chouette/route.rb15
-rw-r--r--app/models/chouette/routing_constraint_zone.rb2
-rw-r--r--app/models/chouette/stop_area.rb4
-rw-r--r--app/models/chouette/stop_point.rb2
-rw-r--r--app/models/chouette/time_table.rb2
-rw-r--r--app/models/chouette/timeband.rb2
-rw-r--r--app/models/chouette/vehicle_journey.rb5
-rw-r--r--app/models/clean_up.rb2
-rw-r--r--app/models/clean_up_result.rb2
-rw-r--r--app/models/compliance_check.rb2
-rw-r--r--app/models/compliance_check_block.rb2
-rw-r--r--app/models/compliance_check_message.rb2
-rw-r--r--app/models/compliance_check_resource.rb2
-rw-r--r--app/models/compliance_check_set.rb5
-rw-r--r--app/models/compliance_control.rb2
-rw-r--r--app/models/compliance_control_block.rb2
-rw-r--r--app/models/compliance_control_set.rb5
-rw-r--r--app/models/concerns/application_days_support.rb8
-rw-r--r--app/models/concerns/custom_fields_support.rb5
-rw-r--r--app/models/concerns/iev_interfaces/task.rb2
-rw-r--r--app/models/concerns/metadata_support.rb107
-rw-r--r--app/models/custom_field.rb2
-rw-r--r--app/models/export/message.rb2
-rw-r--r--app/models/export/resource.rb2
-rw-r--r--app/models/import/base.rb4
-rw-r--r--app/models/import/gtfs.rb302
-rw-r--r--app/models/import/message.rb2
-rw-r--r--app/models/import/netex.rb38
-rw-r--r--app/models/import/resource.rb2
-rw-r--r--app/models/import/workbench.rb21
-rw-r--r--app/models/line_referential.rb2
-rw-r--r--app/models/line_referential_membership.rb2
-rw-r--r--app/models/line_referential_sync.rb2
-rw-r--r--app/models/line_referential_sync_message.rb2
-rw-r--r--app/models/merge.rb18
-rw-r--r--app/models/organisation.rb2
-rw-r--r--app/models/public_version.rb4
-rw-r--r--app/models/referential.rb10
-rw-r--r--app/models/referential_cloning.rb2
-rw-r--r--app/models/referential_metadata.rb2
-rw-r--r--app/models/referential_suite.rb2
-rw-r--r--app/models/simple_interface.rb2
-rw-r--r--app/models/stop_area_referential.rb2
-rw-r--r--app/models/stop_area_referential_membership.rb2
-rw-r--r--app/models/stop_area_referential_sync.rb2
-rw-r--r--app/models/stop_area_referential_sync_message.rb2
-rw-r--r--app/models/user.rb4
-rw-r--r--app/models/workbench.rb2
-rw-r--r--app/models/workgroup.rb2
-rw-r--r--app/services/zip_service.rb45
-rw-r--r--app/views/autocomplete_purchase_windows/index.rabl13
-rw-r--r--app/views/dashboards/_dashboard.html.slim2
-rw-r--r--app/views/lines/_filters.html.slim4
-rw-r--r--app/views/lines/show.html.slim2
-rw-r--r--app/views/referential_lines/_filters.html.slim6
-rw-r--r--app/views/referential_vehicle_journeys/_filters.html.slim4
-rw-r--r--app/views/referentials/select_compliance_control_set.html.slim2
-rw-r--r--app/views/routes/show.html.slim2
-rw-r--r--app/views/shared/iev_interfaces/_messages.html.slim7
-rw-r--r--app/views/stop_areas/_filters.html.slim4
-rw-r--r--app/views/stop_areas/index.html.slim2
-rw-r--r--app/views/time_tables/index.html.slim6
-rw-r--r--app/views/vehicle_journeys/index.html.slim2
-rw-r--r--app/views/workbench_outputs/show.html.slim3
-rw-r--r--app/views/workbenches/show.html.slim5
-rw-r--r--app/workers/gtfs_import_worker.rb7
-rw-r--r--app/workers/workbench_import_worker/object_state_updater.rb27
130 files changed, 883 insertions, 318 deletions
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 6a79f7e8e..3eaade37f 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -25,3 +25,9 @@
//= require "i18n"
//= require "i18n/extended"
//= require "i18n/translations"
+
+$(document).ready(function() {
+ $('a[disabled=disabled]').click(function(event){
+ event.preventDefault(); // Prevent link from following its href
+ });
+});
diff --git a/app/assets/stylesheets/components/_referential_overview.sass b/app/assets/stylesheets/components/_referential_overview.sass
index 7a0cc98c5..cf440b22c 100644
--- a/app/assets/stylesheets/components/_referential_overview.sass
+++ b/app/assets/stylesheets/components/_referential_overview.sass
@@ -24,6 +24,7 @@
.time-travel
padding-top: 3px
padding-bottom: 4px
+ height: 43px
a.btn:first-child
margin-right: 1px
a.btn:last-child
diff --git a/app/controllers/api/v1/netex_imports_controller.rb b/app/controllers/api/v1/netex_imports_controller.rb
index 2654fa088..186ddc35c 100644
--- a/app/controllers/api/v1/netex_imports_controller.rb
+++ b/app/controllers/api/v1/netex_imports_controller.rb
@@ -25,56 +25,19 @@ module Api
def create_models
find_workbench
- create_referential
create_netex_import
end
def create_netex_import
attributes = netex_import_params.merge creator: "Webservice"
-
- attributes = attributes.merge referential_id: @new_referential.id
-
@netex_import = Import::Netex.new attributes
@netex_import.save!
-
- unless @netex_import.referential
- Rails.logger.info "Can't create referential for import #{@netex_import.id}: #{@new_referential.inspect} #{@new_referential.metadatas.inspect} #{@new_referential.errors.full_messages}"
- @netex_import.messages.create criticity: :error, message_key: "referential_creation"
- end
+ @netex_import.create_referential!
rescue ActiveRecord::RecordInvalid
render json: {errors: @netex_import.errors}, status: 406
finish_action!
end
- def create_referential
- @new_referential =
- Referential.new(
- name: netex_import_params['name'],
- organisation_id: @workbench.organisation_id,
- workbench_id: @workbench.id,
- metadatas: [metadata]
- )
- @new_referential.save
- end
-
- def metadata
- metadata = ReferentialMetadata.new
-
- if netex_import_params['file']
- netex_file = STIF::NetexFile.new(netex_import_params['file'].to_io)
- frame = netex_file.frames.first
-
- if frame
- metadata.periodes = frame.periods
-
- line_objectids = frame.line_refs.map { |ref| "STIF:CODIFLIGNE:Line:#{ref}" }
- metadata.line_ids = @workbench.lines.where(objectid: line_objectids).pluck(:id)
- end
- end
-
- metadata
- end
-
def netex_import_params
params
.require('netex_import')
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 9a83394e2..8b66e6097 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,5 +1,5 @@
class ApplicationController < ActionController::Base
- include PaperTrailSupport
+ include MetadataControllerSupport
include Pundit
include FeatureChecker
@@ -10,7 +10,6 @@ class ApplicationController < ActionController::Base
before_action :authenticate_user!
before_action :set_locale
-
# Load helpers in rails engine
helper LanguageEngine::Engine.helpers
diff --git a/app/controllers/chouette_controller.rb b/app/controllers/chouette_controller.rb
index 3e4f3af27..e6e7c0a8a 100644
--- a/app/controllers/chouette_controller.rb
+++ b/app/controllers/chouette_controller.rb
@@ -1,4 +1,3 @@
class ChouetteController < InheritedResources::Base
- include PaperTrailSupport
include ApplicationHelper
end
diff --git a/app/controllers/concerns/metadata_controller_support.rb b/app/controllers/concerns/metadata_controller_support.rb
new file mode 100644
index 000000000..db83e79ae
--- /dev/null
+++ b/app/controllers/concerns/metadata_controller_support.rb
@@ -0,0 +1,26 @@
+module MetadataControllerSupport
+ extend ActiveSupport::Concern
+
+ included do
+ after_action :set_creator_metadata, only: :create
+ after_action :set_modifier_metadata, only: :update
+ end
+
+ def user_for_metadata
+ current_user ? current_user.username : ''
+ end
+
+ def set_creator_metadata
+ if resource.valid?
+ resource.try(:set_metadata!, :creator_username, user_for_metadata)
+ resource.try(:set_metadata!, :modifier_username, user_for_metadata)
+ end
+ end
+
+ def set_modifier_metadata
+ _resource = @resources || [resource]
+ _resource.flatten.each do |r|
+ r.try :set_metadata!, :modifier_username, user_for_metadata
+ end
+ end
+end
diff --git a/app/controllers/concerns/paper_trail_support.rb b/app/controllers/concerns/paper_trail_support.rb
deleted file mode 100644
index 4b0b1a7c7..000000000
--- a/app/controllers/concerns/paper_trail_support.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-module PaperTrailSupport
- extend ActiveSupport::Concern
-
- included do
- before_action :set_paper_trail_whodunnit
-
- def user_for_paper_trail
- current_user ? current_user.name : ''
- end
- end
-end
diff --git a/app/controllers/journey_patterns_collections_controller.rb b/app/controllers/journey_patterns_collections_controller.rb
index da567779e..db92d48f3 100644
--- a/app/controllers/journey_patterns_collections_controller.rb
+++ b/app/controllers/journey_patterns_collections_controller.rb
@@ -74,6 +74,7 @@ class JourneyPatternsCollectionsController < ChouetteController
def update
state = JSON.parse request.raw_post
Chouette::JourneyPattern.state_update route, state
+ @resources = route.journey_patterns
errors = state.any? {|item| item['errors']}
respond_to do |format|
diff --git a/app/controllers/lines_controller.rb b/app/controllers/lines_controller.rb
index ae8c9ed0c..cd8091252 100644
--- a/app/controllers/lines_controller.rb
+++ b/app/controllers/lines_controller.rb
@@ -122,7 +122,7 @@ class LinesController < ChouetteController
end
def line_params
- params.require(:line).permit(
+ out = params.require(:line).permit(
:transport_mode,
:network_id,
:company_id,
@@ -148,6 +148,8 @@ class LinesController < ChouetteController
:secondary_company_ids => [],
footnotes_attributes: [:code, :label, :_destroy, :id]
)
+ out[:secondary_company_ids] = (out[:secondary_company_ids] || []).select(&:present?)
+ out
end
# Fake ransack filter
diff --git a/app/controllers/purchase_windows_controller.rb b/app/controllers/purchase_windows_controller.rb
index 293a7d8e4..cf73d0ed1 100644
--- a/app/controllers/purchase_windows_controller.rb
+++ b/app/controllers/purchase_windows_controller.rb
@@ -63,7 +63,9 @@ class PurchaseWindowsController < ChouetteController
def ransack_contains_date
date =[]
- if params[:q] && params[:q]['contains_date(1i)'].present?
+ if params[:q] && params[:q]['contains_date'].present?
+ params[:q]['contains_date'] = @date = params[:q]['contains_date'].to_date
+ elsif params[:q] && params[:q]['contains_date(1i)'].present?
['contains_date(1i)', 'contains_date(2i)', 'contains_date(3i)'].each do |key|
date << params[:q][key].to_i
params[:q].delete(key)
diff --git a/app/controllers/time_tables_controller.rb b/app/controllers/time_tables_controller.rb
index 0dcadad1e..2ac8532e0 100644
--- a/app/controllers/time_tables_controller.rb
+++ b/app/controllers/time_tables_controller.rb
@@ -128,12 +128,43 @@ class TimeTablesController < ChouetteController
scope = self.ransack_period_range(scope: scope, error_message: t('referentials.errors.validity_period'), query: :overlapping)
@q = scope.search(params[:q])
- if sort_column && sort_direction
- @time_tables ||= @q.result(:distinct => true).order("#{sort_column} #{sort_direction}")
- else
- @time_tables ||= @q.result(:distinct => true).order(:comment)
+ @time_tables ||= begin
+ time_tables = @q.result(:distinct => true)
+ if sort_column == "bounding_dates"
+ time_tables = @q.result(:distinct => false).paginate(page: params[:page], per_page: 10)
+ ids = time_tables.pluck(:id).uniq
+ query = """
+ WITH time_tables_dates AS(
+ SELECT time_tables.id, time_table_dates.date FROM time_tables
+ LEFT JOIN time_table_dates ON time_table_dates.time_table_id = time_tables.id
+ WHERE time_table_dates.in_out IS NULL OR time_table_dates.in_out = 't'
+ UNION
+ SELECT time_tables.id, time_table_periods.period_start FROM time_tables
+ LEFT JOIN time_table_periods ON time_table_periods.time_table_id = time_tables.id
+ )
+ SELECT time_tables.id, MIN(time_tables_dates.date) AS min_date FROM time_tables
+ INNER JOIN time_tables_dates ON time_tables_dates.id = time_tables.id
+ WHERE time_tables.id IN (#{ids.map(&:to_s).join(',')})
+ GROUP BY time_tables.id
+ ORDER BY min_date #{sort_direction}
+ """
+
+ ordered_ids = ActiveRecord::Base.connection.exec_query(query).map {|r| r["id"]}
+ order_by = ["CASE"]
+ ordered_ids.each_with_index do |id, index|
+ order_by << "WHEN id='#{id}' THEN #{index}"
+ end
+ order_by << "END"
+ time_tables = time_tables.order(order_by.join(" "))
+ elsif sort_column == "vehicle_journeys_count"
+ time_tables = time_tables.joins("LEFT JOIN time_tables_vehicle_journeys ON time_tables_vehicle_journeys.time_table_id = time_tables.id LEFT JOIN vehicle_journeys ON vehicle_journeys.id = time_tables_vehicle_journeys.vehicle_journey_id")\
+ .group("time_tables.id").select('time_tables.*, COUNT(vehicle_journeys.id) as vehicle_journeys_count').order("#{sort_column} #{sort_direction}")
+ else
+ time_tables = time_tables.order("#{sort_column} #{sort_direction}")
+ end
+ time_tables = time_tables.paginate(page: params[:page], per_page: 10)
+ time_tables
end
- @time_tables = @time_tables.paginate(page: params[:page], per_page: 10)
end
def select_time_tables
@@ -155,7 +186,10 @@ class TimeTablesController < ChouetteController
private
def sort_column
- referential.time_tables.column_names.include?(params[:sort]) ? params[:sort] : 'comment'
+ valid_cols = referential.time_tables.column_names
+ valid_cols << "bounding_dates"
+ valid_cols << "vehicle_journeys_count"
+ valid_cols.include?(params[:sort]) ? params[:sort] : 'comment'
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
diff --git a/app/controllers/vehicle_journeys_collections_controller.rb b/app/controllers/vehicle_journeys_collections_controller.rb
index 712bcc154..a117888ab 100644
--- a/app/controllers/vehicle_journeys_collections_controller.rb
+++ b/app/controllers/vehicle_journeys_collections_controller.rb
@@ -9,8 +9,8 @@ class VehicleJourneysCollectionsController < ChouetteController
alias_method :route, :parent
def update
- state = JSON.parse request.raw_post
- Chouette::VehicleJourney.state_update route, state
+ state = JSON.parse request.raw_post
+ @resources = Chouette::VehicleJourney.state_update route, state
errors = state.any? {|item| item['errors']}
respond_to do |format|
diff --git a/app/controllers/vehicle_journeys_controller.rb b/app/controllers/vehicle_journeys_controller.rb
index 821ea83ff..220f2d29e 100644
--- a/app/controllers/vehicle_journeys_controller.rb
+++ b/app/controllers/vehicle_journeys_controller.rb
@@ -154,7 +154,7 @@ class VehicleJourneysController < ChouetteController
private
def load_custom_fields
- @custom_fields = referential.workgroup&.custom_fields_definitions || {}
+ @custom_fields = Chouette::VehicleJourney.custom_fields_definitions(referential.workgroup)
@extra_headers = Rails.application.config.vehicle_journeys_extra_headers.dup.delete_if do |header|
header[:type] == :custom_field and not @custom_fields.has_key?(header[:name].to_s)
diff --git a/app/decorators/route_decorator.rb b/app/decorators/route_decorator.rb
index 4a173cbb9..646bc1620 100644
--- a/app/decorators/route_decorator.rb
+++ b/app/decorators/route_decorator.rb
@@ -74,10 +74,11 @@ class RouteDecorator < AF83::Decorator
instance_decorator.action_link(
secondary: :show,
policy: :create_opposite,
- if: ->{h.has_feature?(:create_opposite_routes) && object.opposite_route.nil?}
+ if: ->{h.has_feature?(:create_opposite_routes)}
) do |l|
l.content h.t('routes.create_opposite.title')
l.method :post
+ l.disabled { object.opposite_route.present? }
l.href do
h.duplicate_referential_line_route_path(
context[:referential],
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index a0c6796ea..702ca0ffc 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -14,7 +14,7 @@ module ApplicationHelper
def page_header_title(object)
# Unwrap from decorator, we want to know the object model name
object = object.object if object.try(:object)
-
+
if Referential === object
return object.full_name
end
@@ -36,8 +36,8 @@ module ApplicationHelper
display = policy(object).synchronize? if policy(object).respond_to?(:synchronize?) rescue false
if display
info = t('last_update', time: l(object.updated_at, format: :short))
- if object.try(:versions)
- author = object.versions.try(:last).try(:whodunnit) || t('default_whodunnit')
+ if object.has_metadata?
+ author = object.metadata.modifier_username || t('default_whodunnit')
info = "#{info} <br/> #{t('whodunnit', author: author)}"
end
out += content_tag :div, info.html_safe, class: 'small last-update'
diff --git a/app/helpers/compliance_controls_helper.rb b/app/helpers/compliance_controls_helper.rb
index 297ae3afa..abf909929 100644
--- a/app/helpers/compliance_controls_helper.rb
+++ b/app/helpers/compliance_controls_helper.rb
@@ -11,7 +11,7 @@ module ComplianceControlsHelper
def compliance_control_metadatas(compliance_control)
attributes = resource.class.dynamic_attributes
- attributes.push(*resource.control_attributes.keys) if resource.respond_to? :control_attributes
+ attributes.push(*resource.control_attributes.keys) if resource&.control_attributes&.keys
{}.tap do |hash|
attributes.each do |attribute|
@@ -19,4 +19,4 @@ module ComplianceControlsHelper
end
end
end
-end
+end
diff --git a/app/helpers/table_builder_helper.rb b/app/helpers/table_builder_helper.rb
index 63125b161..e2aa2e9ea 100644
--- a/app/helpers/table_builder_helper.rb
+++ b/app/helpers/table_builder_helper.rb
@@ -402,9 +402,10 @@ module TableBuilderHelper
content_tag(
:li,
link_to(
- link.href,
- method: link.method,
- data: link.data
+ link.disabled ? '#' : link.href,
+ method: link.disabled ? nil : link.method,
+ data: link.data,
+ disabled: link.disabled
) do
link.content
end,
diff --git a/app/javascript/helpers/polyfills.js b/app/javascript/helpers/polyfills.js
new file mode 100644
index 000000000..93e3e9846
--- /dev/null
+++ b/app/javascript/helpers/polyfills.js
@@ -0,0 +1,4 @@
+import 'promise-polyfill/src/polyfill'
+import 'es6-symbol/implement'
+import 'polyfill-array-includes'
+import 'whatwg-fetch'
diff --git a/app/javascript/journey_patterns/actions/index.js b/app/javascript/journey_patterns/actions/index.js
index ea54f4e05..a813f4b9e 100644
--- a/app/javascript/journey_patterns/actions/index.js
+++ b/app/javascript/journey_patterns/actions/index.js
@@ -1,10 +1,3 @@
-import Promise from 'promise-polyfill'
-
-// To add to window
-if (!window.Promise) {
- window.Promise = Promise;
-}
-
const actions = {
enterEditMode: () => ({
type: "ENTER_EDIT_MODE"
@@ -195,15 +188,19 @@ const actions = {
dispatch(actions.unavailableServer())
} else {
if(json.length != 0){
- let val
- for (val of json){
- for (let stop_point of val.route_short_description.stop_points){
+ let j = 0
+ while(j < json.length){
+ let val = json[j]
+ let i = 0
+ while(i < val.route_short_description.stop_points.length){
+ let stop_point = val.route_short_description.stop_points[i]
stop_point.checked = false
val.stop_area_short_descriptions.map((element) => {
if(element.stop_area_short_description.id === stop_point.id){
stop_point.checked = true
}
})
+ i ++
}
journeyPatterns.push(
_.assign({}, val, {
@@ -212,6 +209,7 @@ const actions = {
deletable: false
})
)
+ j ++
}
}
window.currentItemsLength = journeyPatterns.length
diff --git a/app/javascript/packs/calendars/edit.js b/app/javascript/packs/calendars/edit.js
index bd09657ec..0c46313b9 100644
--- a/app/javascript/packs/calendars/edit.js
+++ b/app/javascript/packs/calendars/edit.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
diff --git a/app/javascript/packs/exports/new.js b/app/javascript/packs/exports/new.js
index ffe702cdb..b113cc709 100644
--- a/app/javascript/packs/exports/new.js
+++ b/app/javascript/packs/exports/new.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import MasterSlave from "../../helpers/master_slave"
new MasterSlave("form")
diff --git a/app/javascript/packs/journey_patterns/index.js b/app/javascript/packs/journey_patterns/index.js
index 367a8830f..075eea13a 100644
--- a/app/javascript/packs/journey_patterns/index.js
+++ b/app/javascript/packs/journey_patterns/index.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
diff --git a/app/javascript/packs/referential_lines/show.js b/app/javascript/packs/referential_lines/show.js
index 99c5072ef..523f2040f 100644
--- a/app/javascript/packs/referential_lines/show.js
+++ b/app/javascript/packs/referential_lines/show.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import clone from '../../helpers/clone'
import RoutesMap from '../../helpers/routes_map'
diff --git a/app/javascript/packs/referential_overview/overview.js b/app/javascript/packs/referential_overview/overview.js
index 59c326e9a..03da12ef3 100644
--- a/app/javascript/packs/referential_overview/overview.js
+++ b/app/javascript/packs/referential_overview/overview.js
@@ -1 +1,3 @@
+import '../../helpers/polyfills'
+
import ReferentialOverview from '../../referential_overview'
diff --git a/app/javascript/packs/routes/edit.js b/app/javascript/packs/routes/edit.js
index fc7aa203d..0512b7aff 100644
--- a/app/javascript/packs/routes/edit.js
+++ b/app/javascript/packs/routes/edit.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import React from 'react'
import PropTypes from 'prop-types'
@@ -56,12 +58,25 @@ const getInitialState = () => {
}
var initialState = { stopPoints: getInitialState() }
-const loggerMiddleware = createLogger()
-let store = createStore(
- reducers,
- initialState,
- applyMiddleware(thunkMiddleware, promise, loggerMiddleware)
-)
+let store = null
+
+if(Object.assign){
+ const loggerMiddleware = createLogger()
+ store = createStore(
+ reducers,
+ initialState,
+ applyMiddleware(thunkMiddleware, promise, loggerMiddleware)
+ )
+}
+else{
+ // IE
+ store = createStore(
+ reducers,
+ initialState,
+ applyMiddleware(thunkMiddleware, promise)
+ )
+}
+
render(
<Provider store={store}>
diff --git a/app/javascript/packs/routes/show.js b/app/javascript/packs/routes/show.js
index c20de0800..e8e068ddd 100644
--- a/app/javascript/packs/routes/show.js
+++ b/app/javascript/packs/routes/show.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import clone from '../../helpers/clone'
import RoutesMap from '../../helpers/routes_map'
diff --git a/app/javascript/packs/stop_areas/new.js b/app/javascript/packs/stop_areas/new.js
index ffe702cdb..b113cc709 100644
--- a/app/javascript/packs/stop_areas/new.js
+++ b/app/javascript/packs/stop_areas/new.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import MasterSlave from "../../helpers/master_slave"
new MasterSlave("form")
diff --git a/app/javascript/packs/time_tables/edit.js b/app/javascript/packs/time_tables/edit.js
index cf058d501..873bdea50 100644
--- a/app/javascript/packs/time_tables/edit.js
+++ b/app/javascript/packs/time_tables/edit.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
diff --git a/app/javascript/packs/vehicle_journeys/index.js b/app/javascript/packs/vehicle_journeys/index.js
index 9cad3870e..0b4351d26 100644
--- a/app/javascript/packs/vehicle_journeys/index.js
+++ b/app/javascript/packs/vehicle_journeys/index.js
@@ -1,3 +1,5 @@
+import '../../helpers/polyfills'
+
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
diff --git a/app/javascript/routes/components/StopPoint.js b/app/javascript/routes/components/StopPoint.js
index 368ec8261..768d069c0 100644
--- a/app/javascript/routes/components/StopPoint.js
+++ b/app/javascript/routes/components/StopPoint.js
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import BSelect2 from './BSelect2'
import OlMap from './OlMap'
-import { defaultAttribute } from '../actions'
+import { defaultAttribute } from '../actions'
export default function StopPoint(props, {I18n}) {
return (
@@ -42,13 +42,13 @@ export default function StopPoint(props, {I18n}) {
<div
className={'btn btn-link' + (props.first ? ' disabled' : '')}
- onClick={props.onMoveUpClick}
+ onClick={props.first ? null : props.onMoveUpClick}
>
<span className='fa fa-arrow-up'></span>
</div>
<div
className={'btn btn-link' + (props.last ? ' disabled' : '')}
- onClick={props.onMoveDownClick}
+ onClick={props.last ? null : props.onMoveDownClick}
>
<span className='fa fa-arrow-down'></span>
</div>
diff --git a/app/javascript/time_tables/actions/index.js b/app/javascript/time_tables/actions/index.js
index 7c79dfe52..a5c454a18 100644
--- a/app/javascript/time_tables/actions/index.js
+++ b/app/javascript/time_tables/actions/index.js
@@ -191,10 +191,13 @@ const actions = {
isInPeriod: (periods, date) => {
date = new Date(date)
- for (let period of periods) {
+ let i = 0;
+ while(i < periods.length){
+ let period = periods[i]
let begin = new Date(period.period_start)
let end = new Date(period.period_end)
if (date >= begin && date <= end) return true
+ i++
}
return false
@@ -235,12 +238,14 @@ const actions = {
let error = ''
start = new Date(start)
end = new Date(end)
-
- for (let day of in_days) {
+ let i = 0;
+ while(i < in_days){
+ let day = in_days[i]
if (start <= new Date(day.date) && end >= new Date(day.date)) {
error = I18n.t('time_tables.edit.error_submit.dates_overlaps')
break
}
+ i ++
}
return error
},
diff --git a/app/javascript/time_tables/components/ConfirmModal.js b/app/javascript/time_tables/components/ConfirmModal.js
index 4e8583bc0..e4219348d 100644
--- a/app/javascript/time_tables/components/ConfirmModal.js
+++ b/app/javascript/time_tables/components/ConfirmModal.js
@@ -2,7 +2,7 @@ import React from 'react'
import PropTypes from 'prop-types'
-export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCancel, timetable, metas}, {I18n}) {
+export default function ConfirmModal({dispatch, modal, onModalAccept, onModalCancel, timetable, metas}) {
return (
<div className={'modal fade ' + ((modal.type == 'confirm') ? 'in' : '')} id='ConfirmModal'>
<div className='modal-container'>
@@ -45,8 +45,4 @@ ConfirmModal.propTypes = {
modal: PropTypes.object.isRequired,
onModalAccept: PropTypes.func.isRequired,
onModalCancel: PropTypes.func.isRequired
-}
-
-ConfirmModal.contextTypes = {
- I18n: PropTypes.object
-}
+} \ No newline at end of file
diff --git a/app/javascript/time_tables/components/ErrorModal.js b/app/javascript/time_tables/components/ErrorModal.js
index 8af12f1d1..a512d28fd 100644
--- a/app/javascript/time_tables/components/ErrorModal.js
+++ b/app/javascript/time_tables/components/ErrorModal.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import actions from '../actions'
-export default function ErrorModal({dispatch, modal, onModalClose}, {I18n}) {
+export default function ErrorModal({dispatch, modal, onModalClose}) {
return (
<div className={'modal fade ' + ((modal.type == 'error') ? 'in' : '')} id='ErrorModal'>
<div className='modal-container'>
@@ -37,8 +37,4 @@ export default function ErrorModal({dispatch, modal, onModalClose}, {I18n}) {
ErrorModal.propTypes = {
modal: PropTypes.object.isRequired,
onModalClose: PropTypes.func.isRequired
-}
-
-ErrorModal.contextTypes = {
- I18n: PropTypes.object
-}
+} \ No newline at end of file
diff --git a/app/javascript/time_tables/components/Metas.js b/app/javascript/time_tables/components/Metas.js
index 08a6e26fe..d9746a379 100644
--- a/app/javascript/time_tables/components/Metas.js
+++ b/app/javascript/time_tables/components/Metas.js
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import actions from '../actions'
import TagsSelect2 from './TagsSelect2'
-export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelect2Tags, onUnselect2Tags}, {I18n}) {
+export default function Metas({metas, onUpdateDayTypes, onUpdateComment, onUpdateColor, onSelect2Tags, onUnselect2Tags}) {
let colorList = ["", "#9B9B9B", "#FFA070", "#C67300", "#7F551B", "#41CCE3", "#09B09C", "#3655D7", "#6321A0", "#E796C6", "#DD2DAA"]
return (
<div className='form-horizontal'>
@@ -134,8 +134,4 @@ Metas.propTypes = {
onUpdateColor: PropTypes.func.isRequired,
onSelect2Tags: PropTypes.func.isRequired,
onUnselect2Tags: PropTypes.func.isRequired
-}
-
-Metas.contextTypes = {
- I18n: PropTypes.object
-}
+} \ No newline at end of file
diff --git a/app/javascript/time_tables/components/PeriodForm.js b/app/javascript/time_tables/components/PeriodForm.js
index d17a246f7..36ed6cfdf 100644
--- a/app/javascript/time_tables/components/PeriodForm.js
+++ b/app/javascript/time_tables/components/PeriodForm.js
@@ -33,7 +33,7 @@ const makeYearsOptions = (yearSelected) => {
return arr
}
-export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriodForm, onUpdatePeriodForm, onValidatePeriodForm}, {I18n}) {
+export default function PeriodForm({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriodForm, onUpdatePeriodForm, onValidatePeriodForm}) {
return (
<div className="container-fluid">
<div className="row">
@@ -143,8 +143,4 @@ PeriodForm.propTypes = {
onUpdatePeriodForm: PropTypes.func.isRequired,
onValidatePeriodForm: PropTypes.func.isRequired,
timetable: PropTypes.object.isRequired
-}
-
-PeriodForm.contextTypes = {
- I18n: PropTypes.object
-}
+} \ No newline at end of file
diff --git a/app/javascript/time_tables/components/PeriodManager.js b/app/javascript/time_tables/components/PeriodManager.js
index 6b817fe73..6871d0b9b 100644
--- a/app/javascript/time_tables/components/PeriodManager.js
+++ b/app/javascript/time_tables/components/PeriodManager.js
@@ -55,7 +55,7 @@ export default class PeriodManager extends Component {
type='button'
onClick={() => this.props.onOpenEditPeriodForm(this.props.value, this.props.index)}
>
- Modifier
+ {I18n.t('actions.edit')}
</button>
</li>
<li className='delete-action'>
@@ -64,7 +64,7 @@ export default class PeriodManager extends Component {
onClick={() => this.props.onDeletePeriod(this.props.index, this.props.metas.day_types)}
>
<span className='fa fa-trash'></span>
- Supprimer
+ {I18n.t('actions.destroy')}
</button>
</li>
</ul>
@@ -79,8 +79,4 @@ PeriodManager.propTypes = {
currentDate: PropTypes.object.isRequired,
onDeletePeriod: PropTypes.func.isRequired,
onOpenEditPeriodForm: PropTypes.func.isRequired
-}
-
-PeriodManager.contextTypes = {
- I18n: PropTypes.object
} \ No newline at end of file
diff --git a/app/javascript/time_tables/components/TagsSelect2.js b/app/javascript/time_tables/components/TagsSelect2.js
index 43cf59fdf..dd8d6e9c0 100644
--- a/app/javascript/time_tables/components/TagsSelect2.js
+++ b/app/javascript/time_tables/components/TagsSelect2.js
@@ -40,7 +40,7 @@ export default class TagsSelect2 extends Component {
allowClear: true,
theme: 'bootstrap',
width: '100%',
- placeholder: this.context.I18n.t('time_tables.edit.select2.tag.placeholder'),
+ placeholder: I18n.t('time_tables.edit.select2.tag.placeholder'),
ajax: {
url: origin + path + '/tags.json',
dataType: 'json',
@@ -74,8 +74,4 @@ export default class TagsSelect2 extends Component {
const formatRepo = (props) => {
if(props.name) return props.name
-}
-
-TagsSelect2.contextTypes = {
- I18n: PropTypes.object
} \ No newline at end of file
diff --git a/app/javascript/time_tables/components/Timetable.js b/app/javascript/time_tables/components/Timetable.js
index 991f31435..3779fa2d0 100644
--- a/app/javascript/time_tables/components/Timetable.js
+++ b/app/javascript/time_tables/components/Timetable.js
@@ -31,11 +31,11 @@ export default class Timetable extends Component {
<div className="table table-2entries mb-sm">
<div className="t2e-head w20">
<div className="th">
- <div className="strong">{this.context.I18n.t('time_tables.edit.synthesis')}</div>
+ <div className="strong">{I18n.t('time_tables.edit.synthesis')}</div>
</div>
- <div className="td"><span>{this.context.I18n.t('time_tables.edit.day_types')}</span></div>
- <div className="td"><span>{this.context.I18n.t('time_tables.edit.periods')}</span></div>
- <div className="td"><span>{this.context.I18n.t('time_tables.edit.exceptions')}</span></div>
+ <div className="td"><span>{I18n.t('time_tables.edit.day_types')}</span></div>
+ <div className="td"><span>{I18n.t('time_tables.edit.periods')}</span></div>
+ <div className="td"><span>{I18n.t('time_tables.edit.exceptions')}</span></div>
</div>
<div className="t2e-item-list w80">
<div>
@@ -109,8 +109,4 @@ Timetable.propTypes = {
onDeletePeriod: PropTypes.func.isRequired,
onExcludeDateFromPeriod: PropTypes.func.isRequired,
onIncludeDateInPeriod: PropTypes.func.isRequired
-}
-
-Timetable.contextTypes = {
- I18n: PropTypes.object
-}
+} \ No newline at end of file
diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js
index e00e9b1b0..d51012cdb 100644
--- a/app/javascript/vehicle_journeys/actions/index.js
+++ b/app/javascript/vehicle_journeys/actions/index.js
@@ -1,9 +1,3 @@
-import Promise from 'promise-polyfill'
-
-// To add to window
-if (!window.Promise) {
- window.Promise = Promise;
-}
import { batchActions } from '../batch'
const actions = {
@@ -113,14 +107,9 @@ const actions = {
type : 'EDIT_PURCHASE_WINDOWS_VEHICLEJOURNEY_MODAL',
vehicleJourneys
}),
- selectPurchaseWindowsModal: (selectedWindow) =>({
+ selectPurchaseWindowsModal: (selectedItem) =>({
type: 'SELECT_PURCHASE_WINDOW_MODAL',
- selectedItem:{
- id: selectedWindow.id,
- name: selectedWindow.name,
- color: selectedWindow.color,
- objectid: selectedWindow.objectid
- }
+ selectedItem
}),
addSelectedPurchaseWindow: () => ({
type: 'ADD_SELECTED_PURCHASE_WINDOW'
@@ -344,16 +333,23 @@ const actions = {
if(hasError == true) {
dispatch(actions.unavailableServer())
} else {
- let val
- for (val of json.vehicle_journeys){
+ let i = 0
+ while(i < json.vehicle_journeys.length){
+ let val = json.vehicle_journeys[i]
+ i++
var timeTables = []
var purchaseWindows = []
- let tt
- for (tt of val.time_tables){
+ let k = 0
+ while(k < val.time_tables.length){
+ let tt = val.time_tables[k]
+ k++
timeTables.push(tt)
}
if(val.purchase_windows){
- for (tt of val.purchase_windows){
+ k = 0
+ while(k < val.purchase_windows.length){
+ let tt = val.purchase_windows[k]
+ k++
purchaseWindows.push(tt)
}
}
diff --git a/app/javascript/vehicle_journeys/components/Filters.js b/app/javascript/vehicle_journeys/components/Filters.js
index ae3ab3476..93fe015a8 100644
--- a/app/javascript/vehicle_journeys/components/Filters.js
+++ b/app/javascript/vehicle_journeys/components/Filters.js
@@ -145,12 +145,12 @@ export default function Filters({filters, pagination, missions, onFilter, onRese
<span
className='btn btn-link'
onClick={(e) => onResetFilters(e, pagination)}>
- Effacer
+ {I18n.t('actions.erase')}
</span>
<span
className='btn btn-default'
onClick={(e) => onFilter(e, pagination)}>
- Filtrer
+ {I18n.t('actions.filter')}
</span>
</div>
</div>
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js
index b7e9691c1..60ad439b8 100644
--- a/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/CompanySelect2.js
@@ -31,7 +31,7 @@ export default class BSelect4 extends Component {
theme: 'bootstrap',
width: '100%',
placeholder: I18n.t('vehicle_journeys.vehicle_journeys_matrix.affect_company'),
- language: require('./fr'),
+ language: require('./language'),
ajax: {
url: origin + path + '/companies.json' + '?line_id=' + line,
dataType: 'json',
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js
index 96b34125d..cec39ab4e 100644
--- a/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/MissionSelect2.js
@@ -75,7 +75,7 @@ export default class BSelect4 extends Component {
escapeMarkup: function (markup) { return markup; },
templateResult: formatRepo,
placeholder: I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.journey_pattern'),
- language: require('./fr'),
+ language: require('./language'),
allowClear: false,
escapeMarkup: function (markup) { return markup; },
}
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js
index 9a345b464..d5aad20d0 100644
--- a/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/TimetableSelect2.js
@@ -27,7 +27,7 @@ export default class BSelect4 extends Component {
theme: 'bootstrap',
width: '100%',
placeholder: I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.timetable'),
- language: require('./fr'),
+ language: require('./language'),
ajax: {
url: origin + path + this.props.chunkURL,
dataType: 'json',
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js b/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js
index f5881cef7..50a941b6d 100644
--- a/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/VJSelect2.js
@@ -27,7 +27,7 @@ export default class BSelect4b extends Component {
theme: 'bootstrap',
placeholder: I18n.t('vehicle_journeys.vehicle_journeys_matrix.filters.id'),
width: '100%',
- language: require('./fr'),
+ language: require('./language'),
ajax: {
url: origin + path + '/vehicle_journeys.json',
dataType: 'json',
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/fr.js b/app/javascript/vehicle_journeys/components/tools/select2s/fr.js
deleted file mode 100644
index 20154d412..000000000
--- a/app/javascript/vehicle_journeys/components/tools/select2s/fr.js
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = {
- errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},
- inputTooLong:function(e){var t=e.input.length-e.maximum,n="Supprimez "+t+" caractère";return t!==1&&(n+="s"),n},
- inputTooShort:function(e){var t=e.minimum-e.input.length,n="Saisissez "+t+" caractère";return t!==1&&(n+="s"),n},
- loadingMore:function(){return"Chargement de résultats supplémentaires…"},
- maximumSelected:function(e){var t="Vous pouvez seulement sélectionner "+e.maximum+" élément";return e.maximum!==1&&(t+="s"),t},
- noResults:function(){return"Aucun résultat trouvé"},
- searching:function(){return"Recherche en cours…"}
-}
diff --git a/app/javascript/vehicle_journeys/components/tools/select2s/language.js b/app/javascript/vehicle_journeys/components/tools/select2s/language.js
new file mode 100644
index 000000000..9d587f96e
--- /dev/null
+++ b/app/javascript/vehicle_journeys/components/tools/select2s/language.js
@@ -0,0 +1,9 @@
+module.exports = {
+ errorLoading: () => I18n.t('select2.error_loading'),
+ inputTooLong: (e) => I18n.t('select2.input_too_short', { count: e.input.length - e.maximum}),
+ inputTooShort: (e) => I18n.t('select2.input_too_long', { count: e.minimum - e.input.length }),
+ loadingMore: () => I18n.t('select2.loading_more'),
+ maximumSelected: (e) => I18n.t('select2.maximum_selected', {count: e.maximum}),
+ noResults: () => I18n.t('select2.no_results'),
+ searching: () => I18n.t('select2.searching')
+}
diff --git a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
index 6524f8d6f..b02c19a69 100644
--- a/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
+++ b/app/javascript/vehicle_journeys/reducers/vehicleJourneys.js
@@ -9,32 +9,35 @@ const vehicleJourney= (state = {}, action, keep) => {
return _.assign({}, state, {selected: false})
case 'ADD_VEHICLEJOURNEY':
let pristineVjasList = []
- let prevSp = action.stopPointsList[0]
+ let prevSp
let current_time = {
hour: 0,
minute: 0
}
let computeSchedule = false
- let userTZOffet = 0
+ let initTZOffet = 0
if(action.data["start_time.hour"] && action.data["start_time.hour"].value && action.data["start_time.hour"].value.length > 0 && action.data["start_time.minute"] && action.selectedJourneyPattern.full_schedule && action.selectedJourneyPattern.costs){
computeSchedule = true
- userTZOffet = action.data["tz_offset"] && parseInt(action.data["tz_offset"].value) || 0
- current_time.hour = parseInt(action.data["start_time.hour"].value) + parseInt(userTZOffet / 60)
+ initTZOffet = - action.stopPointsList[0].time_zone_offset / 60 || 0
+ current_time.hour = parseInt(action.data["start_time.hour"].value) + parseInt(initTZOffet / 60)
current_time.minute = 0
if(action.data["start_time.minute"].value){
- current_time.minute = parseInt(action.data["start_time.minute"].value) + (userTZOffet - 60 * parseInt(userTZOffet / 60))
+ current_time.minute = parseInt(action.data["start_time.minute"].value) + (initTZOffet - 60 * parseInt(initTZOffet / 60))
}
}
_.each(action.stopPointsList, (sp) =>{
let inJourney = false
let newVjas
if(computeSchedule){
- if(action.selectedJourneyPattern.costs[prevSp.stop_area_id + "-" + sp.stop_area_id]){
+ if(prevSp && action.selectedJourneyPattern.costs[prevSp.stop_area_id + "-" + sp.stop_area_id]){
let delta = parseInt(action.selectedJourneyPattern.costs[prevSp.stop_area_id + "-" + sp.stop_area_id].time)
current_time = actions.addMinutesToTime(current_time, delta)
prevSp = sp
inJourney = true
}
+ if(!prevSp){
+ prevSp = sp
+ }
let offsetHours = sp.time_zone_offset / 3600
let offsetminutes = sp.time_zone_offset/60 - 60*offsetHours
newVjas = {
diff --git a/app/models/api/v1/api_key.rb b/app/models/api/v1/api_key.rb
index 09c6f77ac..e6ceb977a 100644
--- a/app/models/api/v1/api_key.rb
+++ b/app/models/api/v1/api_key.rb
@@ -1,7 +1,8 @@
module Api
module V1
- class ApiKey < ::ActiveRecord::Base
- has_paper_trail
+ class ApiKey < ::ApplicationModel
+ has_metadata
+
before_create :generate_access_token
belongs_to :referential, :class_name => '::Referential'
belongs_to :organisation, :class_name => '::Organisation'
@@ -47,4 +48,3 @@ module Api
end
end
end
-
diff --git a/app/models/application_model.rb b/app/models/application_model.rb
new file mode 100644
index 000000000..1a2a5099d
--- /dev/null
+++ b/app/models/application_model.rb
@@ -0,0 +1,5 @@
+class ApplicationModel < ::ActiveRecord::Base
+ include MetadataSupport
+
+ self.abstract_class = true
+end
diff --git a/app/models/calendar.rb b/app/models/calendar.rb
index 32eedf9ea..39e2b2cff 100644
--- a/app/models/calendar.rb
+++ b/app/models/calendar.rb
@@ -2,13 +2,13 @@ require 'range_ext'
require_relative 'calendar/date_value'
require_relative 'calendar/period'
-class Calendar < ActiveRecord::Base
+class Calendar < ApplicationModel
include DateSupport
include PeriodSupport
include ApplicationDaysSupport
include TimetableSupport
- has_paper_trail class_name: 'PublicVersion'
+ has_metadata
belongs_to :organisation
belongs_to :workgroup
diff --git a/app/models/calendar/date_value.rb b/app/models/calendar/date_value.rb
index a4a405d43..f50b4237c 100644
--- a/app/models/calendar/date_value.rb
+++ b/app/models/calendar/date_value.rb
@@ -1,4 +1,4 @@
-class Calendar < ActiveRecord::Base
+class Calendar < ApplicationModel
class DateValue
include ActiveAttr::Model
diff --git a/app/models/calendar/period.rb b/app/models/calendar/period.rb
index 8b3e4109b..07926e818 100644
--- a/app/models/calendar/period.rb
+++ b/app/models/calendar/period.rb
@@ -1,4 +1,4 @@
-class Calendar < ActiveRecord::Base
+class Calendar < ApplicationModel
class Period
include ActiveAttr::Model
diff --git a/app/models/chouette/access_link.rb b/app/models/chouette/access_link.rb
index 6b08443be..7ab8ca715 100644
--- a/app/models/chouette/access_link.rb
+++ b/app/models/chouette/access_link.rb
@@ -1,6 +1,6 @@
module Chouette
class AccessLink < Chouette::TridentActiveRecord
- has_paper_trail
+ has_metadata
include ObjectidSupport
attr_accessor :access_link_type, :link_orientation_type, :link_key
diff --git a/app/models/chouette/access_point.rb b/app/models/chouette/access_point.rb
index ac6580015..884460881 100644
--- a/app/models/chouette/access_point.rb
+++ b/app/models/chouette/access_point.rb
@@ -4,7 +4,7 @@ require 'geo_ruby'
module Chouette
class AccessPoint < Chouette::ActiveRecord
- has_paper_trail
+ has_metadata
include Geokit::Mappable
include ProjectionFields
diff --git a/app/models/chouette/active_record.rb b/app/models/chouette/active_record.rb
index c2aab9d50..27f5426b3 100644
--- a/app/models/chouette/active_record.rb
+++ b/app/models/chouette/active_record.rb
@@ -1,7 +1,8 @@
#require "active_record"
require 'deep_cloneable'
module Chouette
- class ActiveRecord < ::ActiveRecord::Base
+ class ActiveRecord < ::ApplicationModel
+
self.abstract_class = true
before_save :nil_if_blank, :set_data_source_ref
diff --git a/app/models/chouette/company.rb b/app/models/chouette/company.rb
index 8d6dbee92..9d5737a6c 100644
--- a/app/models/chouette/company.rb
+++ b/app/models/chouette/company.rb
@@ -1,15 +1,15 @@
module Chouette
class Company < Chouette::ActiveRecord
+ has_metadata
+
include CompanyRestrictions
include LineReferentialSupport
include ObjectidSupport
include CustomFieldsSupport
- has_paper_trail class_name: 'PublicVersion'
-
has_many :lines
- validates_format_of :registration_number, :with => %r{\A[0-9A-Za-z_-]+\Z}, :allow_nil => true, :allow_blank => true
+ # validates_format_of :registration_number, :with => %r{\A[0-9A-Za-z_-]+\Z}, :allow_nil => true, :allow_blank => true
validates_presence_of :name
validates_format_of :url, :with => %r{\Ahttps?:\/\/([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?\Z}, :allow_nil => true, :allow_blank => true
diff --git a/app/models/chouette/connection_link.rb b/app/models/chouette/connection_link.rb
index c53d6f5f1..fb93e5f90 100644
--- a/app/models/chouette/connection_link.rb
+++ b/app/models/chouette/connection_link.rb
@@ -1,6 +1,6 @@
module Chouette
class ConnectionLink < Chouette::TridentActiveRecord
- has_paper_trail
+ has_metadata
include ObjectidSupport
include ConnectionLinkRestrictions
diff --git a/app/models/chouette/group_of_line.rb b/app/models/chouette/group_of_line.rb
index 3b6a7cea7..a30c34ce7 100644
--- a/app/models/chouette/group_of_line.rb
+++ b/app/models/chouette/group_of_line.rb
@@ -1,6 +1,6 @@
module Chouette
class GroupOfLine < Chouette::ActiveRecord
- has_paper_trail
+ has_metadata
include ObjectidSupport
include GroupOfLineRestrictions
include LineReferentialSupport
diff --git a/app/models/chouette/journey_pattern.rb b/app/models/chouette/journey_pattern.rb
index 5a5132200..830a6a808 100644
--- a/app/models/chouette/journey_pattern.rb
+++ b/app/models/chouette/journey_pattern.rb
@@ -1,6 +1,6 @@
module Chouette
class JourneyPattern < Chouette::TridentActiveRecord
- has_paper_trail
+ has_metadata
include ChecksumSupport
include JourneyPatternRestrictions
include ObjectidSupport
diff --git a/app/models/chouette/line.rb b/app/models/chouette/line.rb
index c8a02da1f..4b5d1a68d 100644
--- a/app/models/chouette/line.rb
+++ b/app/models/chouette/line.rb
@@ -1,6 +1,6 @@
module Chouette
class Line < Chouette::ActiveRecord
- has_paper_trail class_name: 'PublicVersion'
+ has_metadata
include LineRestrictions
include LineReferentialSupport
include ObjectidSupport
@@ -29,7 +29,7 @@ module Chouette
# validates_presence_of :network
# validates_presence_of :company
- validates_format_of :registration_number, :with => %r{\A[\d\w_\-]+\Z}, :allow_nil => true, :allow_blank => true
+ # validates_format_of :registration_number, :with => %r{\A[\d\w_\-]+\Z}, :allow_nil => true, :allow_blank => true
validates_format_of :stable_id, :with => %r{\A[\d\w_\-]+\Z}, :allow_nil => true, :allow_blank => true
validates_format_of :url, :with => %r{\Ahttps?:\/\/([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?\Z}, :allow_nil => true, :allow_blank => true
validates_format_of :color, :with => %r{\A[0-9a-fA-F]{6}\Z}, :allow_nil => true, :allow_blank => true
diff --git a/app/models/chouette/network.rb b/app/models/chouette/network.rb
index 942fc5d67..4802d7592 100644
--- a/app/models/chouette/network.rb
+++ b/app/models/chouette/network.rb
@@ -1,6 +1,6 @@
module Chouette
class Network < Chouette::ActiveRecord
- has_paper_trail class_name: 'PublicVersion'
+ has_metadata
include NetworkRestrictions
include LineReferentialSupport
include ObjectidSupport
diff --git a/app/models/chouette/pt_link.rb b/app/models/chouette/pt_link.rb
index 399539d44..680632a14 100644
--- a/app/models/chouette/pt_link.rb
+++ b/app/models/chouette/pt_link.rb
@@ -2,7 +2,7 @@ require 'geokit'
module Chouette
class PtLink < Chouette::ActiveRecord
- has_paper_trail
+ has_metadata
include Geokit::Mappable
def geometry
diff --git a/app/models/chouette/purchase_window.rb b/app/models/chouette/purchase_window.rb
index 4c8014780..e10b106ec 100644
--- a/app/models/chouette/purchase_window.rb
+++ b/app/models/chouette/purchase_window.rb
@@ -11,7 +11,7 @@ module Chouette
enumerize :color, in: %w(#9B9B9B #FFA070 #C67300 #7F551B #41CCE3 #09B09C #3655D7 #6321A0 #E796C6 #DD2DAA)
- has_paper_trail
+ has_metadata
belongs_to :referential
has_and_belongs_to_many :vehicle_journeys, :class_name => 'Chouette::VehicleJourney'
diff --git a/app/models/chouette/route.rb b/app/models/chouette/route.rb
index 65947c392..14bfa47b6 100644
--- a/app/models/chouette/route.rb
+++ b/app/models/chouette/route.rb
@@ -1,15 +1,24 @@
module Chouette
class Route < Chouette::TridentActiveRecord
- has_paper_trail
+ has_metadata
+
include RouteRestrictions
include ChecksumSupport
include ObjectidSupport
extend Enumerize
+ if Rails.env.development?
+ after_commit do
+ positions = stop_points.pluck(:position)
+ if positions.size != positions.uniq.size
+ raise "DUPLICATED stop_points positions: #{positions}"
+ end
+ end
+ end
+
enumerize :direction, in: %i(straight_forward backward clockwise counter_clockwise north north_west west south_west south south_east east north_east)
enumerize :wayback, in: %i(outbound inbound), default: :outbound
-
def self.nullable_attributes
[:published_name, :comment, :number, :name, :direction, :wayback]
end
@@ -69,7 +78,7 @@ module Chouette
validates_presence_of :line
validates :wayback, inclusion: { in: self.wayback.values }
after_save :calculate_costs!, if: ->() { TomTom.enabled? }
-
+
def duplicate opposite=false
overrides = {
'opposite_route_id' => nil,
diff --git a/app/models/chouette/routing_constraint_zone.rb b/app/models/chouette/routing_constraint_zone.rb
index 58703598e..886eadc6c 100644
--- a/app/models/chouette/routing_constraint_zone.rb
+++ b/app/models/chouette/routing_constraint_zone.rb
@@ -1,6 +1,6 @@
module Chouette
class RoutingConstraintZone < Chouette::TridentActiveRecord
- has_paper_trail
+ has_metadata
include ChecksumSupport
include ObjectidSupport
diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb
index c263fa987..4ddc7403b 100644
--- a/app/models/chouette/stop_area.rb
+++ b/app/models/chouette/stop_area.rb
@@ -2,7 +2,7 @@ require 'geokit'
require 'geo_ruby'
module Chouette
class StopArea < Chouette::ActiveRecord
- has_paper_trail class_name: 'PublicVersion'
+ has_metadata
include ProjectionFields
include StopAreaRestrictions
include StopAreaReferentialSupport
@@ -33,7 +33,7 @@ module Chouette
after_update :journey_patterns_control_route_sections,
if: Proc.new { |stop_area| ['boarding_position', 'quay'].include? stop_area.stop_area_type }
- validates_format_of :registration_number, :with => %r{\A[\d\w_\-]+\Z}, :allow_blank => true
+ # validates_format_of :registration_number, :with => %r{\A[\d\w_:\-]+\Z}, :allow_blank => true
validates_presence_of :name
validates_presence_of :kind
validates_presence_of :latitude, :if => :longitude
diff --git a/app/models/chouette/stop_point.rb b/app/models/chouette/stop_point.rb
index da2da998a..1df1a664a 100644
--- a/app/models/chouette/stop_point.rb
+++ b/app/models/chouette/stop_point.rb
@@ -1,6 +1,6 @@
module Chouette
class StopPoint < Chouette::TridentActiveRecord
- has_paper_trail
+ has_metadata
def self.policy_class
RoutePolicy
end
diff --git a/app/models/chouette/time_table.rb b/app/models/chouette/time_table.rb
index 506e498b8..b59c95665 100644
--- a/app/models/chouette/time_table.rb
+++ b/app/models/chouette/time_table.rb
@@ -1,6 +1,6 @@
module Chouette
class TimeTable < Chouette::TridentActiveRecord
- has_paper_trail
+ has_metadata
include ChecksumSupport
include TimeTableRestrictions
include ObjectidSupport
diff --git a/app/models/chouette/timeband.rb b/app/models/chouette/timeband.rb
index 5a4e17b98..38260b755 100644
--- a/app/models/chouette/timeband.rb
+++ b/app/models/chouette/timeband.rb
@@ -9,7 +9,7 @@ module Chouette
class Timeband < Chouette::TridentActiveRecord
include ObjectidSupport
- has_paper_trail
+ has_metadata
validates :start_time, :end_time, presence: true
validates_with Chouette::TimebandValidator
diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb
index be05d4053..c269d478e 100644
--- a/app/models/chouette/vehicle_journey.rb
+++ b/app/models/chouette/vehicle_journey.rb
@@ -1,7 +1,7 @@
# coding: utf-8
module Chouette
class VehicleJourney < Chouette::TridentActiveRecord
- has_paper_trail
+ has_metadata
include ChecksumSupport
include CustomFieldsSupport
include VehicleJourneyRestrictions
@@ -244,11 +244,13 @@ module Chouette
end
def self.state_update route, state
+ objects = []
transaction do
state.each do |item|
item.delete('errors')
vj = find_by(objectid: item['objectid']) || state_create_instance(route, item)
next if item['deletable'] && vj.persisted? && vj.destroy
+ objects << vj
if vj.state_update_vjas?(item['vehicle_journey_at_stops'])
vj.update_vjas_from_state(item['vehicle_journey_at_stops'])
@@ -276,6 +278,7 @@ module Chouette
item['vehicle_journey_at_stops'].map {|vjas| vjas.delete('new_record') }
end
state.delete_if {|item| item['deletable']}
+ objects
end
def self.state_create_instance route, item
diff --git a/app/models/clean_up.rb b/app/models/clean_up.rb
index 7aab7f32e..ec47489e9 100644
--- a/app/models/clean_up.rb
+++ b/app/models/clean_up.rb
@@ -1,4 +1,4 @@
-class CleanUp < ActiveRecord::Base
+class CleanUp < ApplicationModel
extend Enumerize
include AASM
belongs_to :referential
diff --git a/app/models/clean_up_result.rb b/app/models/clean_up_result.rb
index 24d262deb..dff4f5acd 100644
--- a/app/models/clean_up_result.rb
+++ b/app/models/clean_up_result.rb
@@ -1,3 +1,3 @@
-class CleanUpResult < ActiveRecord::Base
+class CleanUpResult < ApplicationModel
belongs_to :clean_up
end
diff --git a/app/models/compliance_check.rb b/app/models/compliance_check.rb
index 9d817e146..4ef6170e9 100644
--- a/app/models/compliance_check.rb
+++ b/app/models/compliance_check.rb
@@ -1,4 +1,4 @@
-class ComplianceCheck < ActiveRecord::Base
+class ComplianceCheck < ApplicationModel
include ComplianceItemSupport
self.inheritance_column = nil
diff --git a/app/models/compliance_check_block.rb b/app/models/compliance_check_block.rb
index 059547e1b..e4f4c1c37 100644
--- a/app/models/compliance_check_block.rb
+++ b/app/models/compliance_check_block.rb
@@ -1,4 +1,4 @@
-class ComplianceCheckBlock < ActiveRecord::Base
+class ComplianceCheckBlock < ApplicationModel
include StifTransportModeEnumerations
include StifTransportSubmodeEnumerations
diff --git a/app/models/compliance_check_message.rb b/app/models/compliance_check_message.rb
index 738bd4a4b..a4b1062f6 100644
--- a/app/models/compliance_check_message.rb
+++ b/app/models/compliance_check_message.rb
@@ -1,4 +1,4 @@
-class ComplianceCheckMessage < ActiveRecord::Base
+class ComplianceCheckMessage < ApplicationModel
extend Enumerize
belongs_to :compliance_check_set
diff --git a/app/models/compliance_check_resource.rb b/app/models/compliance_check_resource.rb
index 777254aaf..d2f782e2b 100644
--- a/app/models/compliance_check_resource.rb
+++ b/app/models/compliance_check_resource.rb
@@ -1,4 +1,4 @@
-class ComplianceCheckResource < ActiveRecord::Base
+class ComplianceCheckResource < ApplicationModel
extend Enumerize
belongs_to :compliance_check_set
diff --git a/app/models/compliance_check_set.rb b/app/models/compliance_check_set.rb
index 49d324c53..8b1dbdd68 100644
--- a/app/models/compliance_check_set.rb
+++ b/app/models/compliance_check_set.rb
@@ -1,6 +1,7 @@
-class ComplianceCheckSet < ActiveRecord::Base
+class ComplianceCheckSet < ApplicationModel
extend Enumerize
- has_paper_trail class_name: 'PublicVersion'
+
+ has_metadata
belongs_to :referential
belongs_to :compliance_control_set
diff --git a/app/models/compliance_control.rb b/app/models/compliance_control.rb
index 1cc06f927..672fb128c 100644
--- a/app/models/compliance_control.rb
+++ b/app/models/compliance_control.rb
@@ -1,4 +1,4 @@
-class ComplianceControl < ActiveRecord::Base
+class ComplianceControl < ApplicationModel
include ComplianceItemSupport
class << self
diff --git a/app/models/compliance_control_block.rb b/app/models/compliance_control_block.rb
index bc5d6fd4a..6a3c8a34e 100644
--- a/app/models/compliance_control_block.rb
+++ b/app/models/compliance_control_block.rb
@@ -1,4 +1,4 @@
-class ComplianceControlBlock < ActiveRecord::Base
+class ComplianceControlBlock < ApplicationModel
include StifTransportModeEnumerations
include StifTransportSubmodeEnumerations
diff --git a/app/models/compliance_control_set.rb b/app/models/compliance_control_set.rb
index c0ea692f2..4f0f86d08 100644
--- a/app/models/compliance_control_set.rb
+++ b/app/models/compliance_control_set.rb
@@ -1,5 +1,6 @@
-class ComplianceControlSet < ActiveRecord::Base
- has_paper_trail class_name: 'PublicVersion'
+class ComplianceControlSet < ApplicationModel
+ has_metadata
+
belongs_to :organisation
has_many :compliance_control_blocks, dependent: :destroy
has_many :compliance_controls, dependent: :destroy
diff --git a/app/models/concerns/application_days_support.rb b/app/models/concerns/application_days_support.rb
index 2d00b5847..6086d9580 100644
--- a/app/models/concerns/application_days_support.rb
+++ b/app/models/concerns/application_days_support.rb
@@ -10,8 +10,10 @@ module ApplicationDaysSupport
SUNDAY = 256
EVERYDAY = MONDAY | TUESDAY | WEDNESDAY | THURSDAY | FRIDAY | SATURDAY | SUNDAY
+ ALL_DAYS = %w(monday tuesday wednesday thursday friday saturday sunday).freeze
+
def display_day_types
- %w(monday tuesday wednesday thursday friday saturday sunday).select{ |d| self.send(d) }.map{ |d| self.human_attribute_name(d).first(2)}.join(', ')
+ ALL_DAYS.select{ |d| self.send(d) }.map{ |d| self.human_attribute_name(d).first(2)}.join(', ')
end
def day_by_mask(flag)
@@ -39,6 +41,10 @@ module ApplicationDaysSupport
def self.day_by_mask(int_day_types,flag)
int_day_types & flag == flag
end
+
+ def self.all_days
+ ALL_DAYS
+ end
end
def valid_days
diff --git a/app/models/concerns/custom_fields_support.rb b/app/models/concerns/custom_fields_support.rb
index 017f496a8..46fc8e73d 100644
--- a/app/models/concerns/custom_fields_support.rb
+++ b/app/models/concerns/custom_fields_support.rb
@@ -11,6 +11,10 @@ module CustomFieldsSupport
fields
end
+ def self.custom_fields_definitions workgroup=:all
+ Hash[*custom_fields(workgroup).map{|cf| [cf.code, cf]}.flatten]
+ end
+
def method_missing method_name, *args
if method_name =~ /custom_field_*/ && method_name.to_sym != :custom_field_values && !@custom_fields_initialized
initialize_custom_fields
@@ -33,6 +37,7 @@ module CustomFieldsSupport
end
def initialize_custom_fields
+ return unless self.attributes.has_key?("custom_field_values")
self.custom_field_values ||= {}
custom_fields(:all).values.each &:initialize_custom_field
custom_fields(:all).each do |k, v|
diff --git a/app/models/concerns/iev_interfaces/task.rb b/app/models/concerns/iev_interfaces/task.rb
index bc78ff28c..f052b3a8f 100644
--- a/app/models/concerns/iev_interfaces/task.rb
+++ b/app/models/concerns/iev_interfaces/task.rb
@@ -25,7 +25,7 @@ module IevInterfaces::Task
scope :blocked, -> { where('created_at < ? AND status = ?', 4.hours.ago, 'running') }
- before_create :initialize_fields
+ before_save :initialize_fields, on: :create
after_save :notify_parent
end
diff --git a/app/models/concerns/metadata_support.rb b/app/models/concerns/metadata_support.rb
new file mode 100644
index 000000000..c4bedbcda
--- /dev/null
+++ b/app/models/concerns/metadata_support.rb
@@ -0,0 +1,107 @@
+module MetadataSupport
+ extend ActiveSupport::Concern
+
+ included do
+ class << self
+ def has_metadata?
+ !!@has_metadata
+ end
+
+ def has_metadata opts={}
+ @has_metadata = true
+
+ define_method :metadata do
+ attr_name = opts[:attr_name] || :metadata
+ @wrapped_metadata ||= begin
+ wrapped = MetadataSupport::MetadataWrapper.new self.read_attribute(attr_name)
+ wrapped.attribute_name = attr_name
+ wrapped.owner = self
+ wrapped
+ end
+ end
+
+ define_method :metadata= do |val|
+ @wrapped_metadata = nil
+ super val
+ end
+
+ define_method :set_metadata! do |name, value|
+ self.metadata.send "#{name}=", value
+ self.save!
+ end
+ end
+ end
+ end
+
+ def has_metadata?
+ self.class.has_metadata?
+ end
+
+ def merge_metadata_from source
+ return unless source.has_metadata?
+ source_metadata = source.metadata
+ res = {}
+ self.metadata.each do |k, v|
+ unless self.metadata.is_timestamp_attr?(k)
+ ts = self.metadata.timestamp_attr(k)
+ if source_metadata[ts] && source_metadata[ts] > self.metadata[ts]
+ res[k] = source_metadata[k]
+ else
+ res[k] = v
+ end
+ end
+ end
+ self.metadata = res
+ self
+ end
+
+ class MetadataWrapper < OpenStruct
+ attr_accessor :attribute_name, :owner
+
+ def is_timestamp_attr? name
+ name =~ /_updated_at$/
+ end
+
+ def timestamp_attr name
+ "#{name}_updated_at".to_sym
+ end
+
+ def method_missing(mid, *args)
+ out = super(mid, *args)
+ owner.send :write_attribute, attribute_name, @table
+ out = out&.to_time if args.length == 0 && is_timestamp_attr?(mid)
+ out
+ end
+
+ def each
+ @table.each do |k,v|
+ yield k, v
+ end
+ end
+
+ def new_ostruct_member name
+ unless is_timestamp_attr?(name)
+ timestamp_attr_name = timestamp_attr(name)
+ end
+
+ name = name.to_sym
+ unless respond_to?(name)
+ if timestamp_attr_name
+ define_singleton_method(timestamp_attr_name) { @table[timestamp_attr_name]&.to_time }
+ define_singleton_method(name) { @table[name] }
+ else
+ # we are defining an accessor for a timestamp
+ define_singleton_method(name) { @table[name]&.to_time }
+ end
+
+ define_singleton_method("#{name}=") do |x|
+ modifiable[timestamp_attr_name] = Time.now if timestamp_attr_name
+ modifiable[name] = x
+ owner.send :write_attribute, attribute_name, @table
+ end
+ modifiable[timestamp_attr_name] = Time.now if timestamp_attr_name
+ end
+ name
+ end
+ end
+end
diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb
index 8347d84f9..22118a15a 100644
--- a/app/models/custom_field.rb
+++ b/app/models/custom_field.rb
@@ -1,4 +1,4 @@
-class CustomField < ActiveRecord::Base
+class CustomField < ApplicationModel
extend Enumerize
belongs_to :workgroup
diff --git a/app/models/export/message.rb b/app/models/export/message.rb
index b64b524ac..223429900 100644
--- a/app/models/export/message.rb
+++ b/app/models/export/message.rb
@@ -1,4 +1,4 @@
-class Export::Message < ActiveRecord::Base
+class Export::Message < ApplicationModel
self.table_name = :export_messages
include IevInterfaces::Message
diff --git a/app/models/export/resource.rb b/app/models/export/resource.rb
index 98f103be4..2a63c14a8 100644
--- a/app/models/export/resource.rb
+++ b/app/models/export/resource.rb
@@ -1,4 +1,4 @@
-class Export::Resource < ActiveRecord::Base
+class Export::Resource < ApplicationModel
self.table_name = :export_resources
include IevInterfaces::Resource
diff --git a/app/models/import/base.rb b/app/models/import/base.rb
index 62494c92e..f98e359d4 100644
--- a/app/models/import/base.rb
+++ b/app/models/import/base.rb
@@ -1,4 +1,4 @@
-class Import::Base < ActiveRecord::Base
+class Import::Base < ApplicationModel
self.table_name = "imports"
validates :file, presence: true
@@ -41,7 +41,7 @@ class Import::Base < ActiveRecord::Base
def initialize_fields
super
- self.token_download = SecureRandom.urlsafe_base64
+ self.token_download ||= SecureRandom.urlsafe_base64
end
end
diff --git a/app/models/import/gtfs.rb b/app/models/import/gtfs.rb
index 03cf49e60..70f448132 100644
--- a/app/models/import/gtfs.rb
+++ b/app/models/import/gtfs.rb
@@ -1,36 +1,296 @@
-require 'net/http'
class Import::Gtfs < Import::Base
- before_destroy :destroy_non_ready_referential
+ after_commit :launch_worker, :on => :create
- after_commit :launch_java_import, on: :create
- before_save def abort_unless_referential
- self.status = 'aborted' unless referential
+ def launch_worker
+ GtfsImportWorker.perform_async id
end
- def launch_java_import
- return if self.class.finished_statuses.include?(status)
- threaded_call_boiv_iev
+ def import
+ update status: 'running', started_at: Time.now
+
+ import_without_status
+ update status: 'successful', ended_at: Time.now
+ rescue Exception => e
+ update status: 'failed', ended_at: Time.now
+ Rails.logger.error "Error in GTFS import: #{e} #{e.backtrace.join('\n')}"
+ ensure
+ notify_parent
+ referential&.update ready: true
+ end
+
+ def self.accept_file?(file)
+ Zip::File.open(file) do |zip_file|
+ zip_file.glob('agency.txt').size == 1
+ end
+ rescue Exception => e
+ Rails.logger.debug "Error in testing GTFS file: #{e}"
+ return false
+ end
+
+ def create_referential
+ self.referential ||= Referential.create!(
+ name: "GTFS Import",
+ organisation_id: workbench.organisation_id,
+ workbench_id: workbench.id,
+ metadatas: [referential_metadata]
+ )
+ end
+
+ def referential_metadata
+ registration_numbers = source.routes.map(&:id)
+ line_ids = line_referential.lines.where(registration_number: registration_numbers).pluck(:id)
+
+ start_dates, end_dates = source.calendars.map { |c| [c.start_date, c.end_date ] }.transpose
+ excluded_dates = source.calendar_dates.select { |d| d.exception_type == "2" }.map(&:date)
+
+ min_date = Date.parse (start_dates + [excluded_dates.min]).compact.min
+ max_date = Date.parse (end_dates + [excluded_dates.max]).compact.max
+
+ ReferentialMetadata.new line_ids: line_ids, periodes: [min_date..max_date]
+ end
+
+ attr_accessor :local_file
+ def local_file
+ @local_file ||= download_local_file
end
- private
+ attr_accessor :download_host
+ def download_host
+ @download_host ||= Rails.application.config.rails_host.gsub("http://","")
+ end
- def destroy_non_ready_referential
- if referential && !referential.ready
- referential.destroy
+ def local_temp_directory
+ Rails.application.config.try(:import_temporary_directory) ||
+ Rails.root.join('tmp', 'imports')
+ end
+
+ def local_temp_file(&block)
+ Tempfile.open("chouette-import", local_temp_directory) do |file|
+ file.binmode
+ yield file
end
end
- def threaded_call_boiv_iev
- Thread.new(&method(:call_boiv_iev))
+ def download_path
+ Rails.application.routes.url_helpers.download_workbench_import_path(workbench, id, token: token_download)
end
- def call_boiv_iev
- Rails.logger.error("Begin IEV call for import")
- Net::HTTP.get(URI("#{Rails.configuration.iev_url}/boiv_iev/referentials/importer/new?id=#{id}"))
- Rails.logger.error("End IEV call for import")
- rescue Exception => e
- logger.error "IEV server error : #{e.message}"
- logger.error e.backtrace.inspect
+ def download_local_file
+ local_temp_file do |file|
+ begin
+ Net::HTTP.start(download_host) do |http|
+ http.request_get(download_path) do |response|
+ response.read_body do |segment|
+ file.write segment
+ end
+ end
+ end
+ ensure
+ file.close
+ end
+
+ file.path
+ end
+ end
+
+ def source
+ @source ||= ::GTFS::Source.build local_file
+ end
+
+ delegate :line_referential, :stop_area_referential, to: :workbench
+
+ def prepare_referential
+ import_agencies
+ import_stops
+ import_routes
+
+ create_referential
+ referential.switch
+ end
+
+ def import_without_status
+ prepare_referential
+
+ import_calendars
+ import_trips
+ import_stop_times
+ end
+
+ def import_agencies
+ Chouette::Company.transaction do
+ source.agencies.each do |agency|
+ company = line_referential.companies.find_or_initialize_by(registration_number: agency.id)
+ company.attributes = { name: agency.name }
+
+ save_model company
+ end
+ end
+ end
+
+ def import_stops
+ Chouette::StopArea.transaction do
+ source.stops.each do |stop|
+ stop_area = stop_area_referential.stop_areas.find_or_initialize_by(registration_number: stop.id)
+
+ stop_area.name = stop.name
+ stop_area.area_type = stop.location_type == "1" ? "zdlp" : "zdep"
+ stop_area.parent = stop_area_referential.stop_areas.find_by!(registration_number: stop.parent_station) if stop.parent_station.present?
+ stop_area.latitude, stop_area.longitude = stop.lat, stop.lon
+ stop_area.kind = "commercial"
+
+ # TODO correct default timezone
+
+ save_model stop_area
+ end
+ end
+ end
+
+ def import_routes
+ Chouette::Line.transaction do
+ source.routes.each do |route|
+ line = line_referential.lines.find_or_initialize_by(registration_number: route.id)
+ line.name = route.long_name.presence || route.short_name
+ line.number = route.short_name
+ line.published_name = route.long_name
+
+ line.company = line_referential.companies.find_by(registration_number: route.agency_id) if route.agency_id.present?
+
+ # TODO transport mode
+
+ line.comment = route.desc
+
+ # TODO colors
+
+ line.url = route.url
+
+ save_model line
+ end
+ end
+ end
+
+ def vehicle_journey_by_trip_id
+ @vehicle_journey_by_trip_id ||= {}
+ end
+
+ def import_trips
+ source.trips.each_slice(100) do |slice|
+ slice.each do |trip|
+ Chouette::Route.transaction do
+ line = line_referential.lines.find_by registration_number: trip.route_id
+
+ route = referential.routes.build line: line
+ route.wayback = (trip.direction_id == "0" ? :outbound : :inbound)
+ # TODO better name ?
+ name = route.published_name = trip.short_name.presence || trip.headsign.presence || route.wayback.to_s.capitalize
+ route.name = name
+ save_model route
+
+ journey_pattern = route.journey_patterns.build name: name
+ save_model journey_pattern
+
+ vehicle_journey = journey_pattern.vehicle_journeys.build route: route
+ vehicle_journey.published_journey_name = trip.headsign.presence || trip.id
+ save_model vehicle_journey
+
+ time_table = referential.time_tables.find_by(id: time_tables_by_service_id[trip.service_id]) if time_tables_by_service_id[trip.service_id]
+ if time_table
+ vehicle_journey.time_tables << time_table
+ else
+ messages.create! criticity: "warning", message_key: "gtfs.trips.unkown_service_id", message_attributes: {service_id: trip.service_id}
+ end
+
+ vehicle_journey_by_trip_id[trip.id] = vehicle_journey.id
+ end
+ end
+ end
+ end
+
+ def import_stop_times
+ source.stop_times.group_by(&:trip_id).each_slice(50) do |slice|
+ slice.each do |trip_id, stop_times|
+ Chouette::VehicleJourneyAtStop.transaction do
+ vehicle_journey = referential.vehicle_journeys.find vehicle_journey_by_trip_id[trip_id]
+ journey_pattern = vehicle_journey.journey_pattern
+ route = journey_pattern.route
+
+ stop_times.sort_by! { |s| s.stop_sequence.to_i }
+
+ stop_times.each do |stop_time|
+ stop_area = stop_area_referential.stop_areas.find_by(registration_number: stop_time.stop_id)
+
+ stop_point = route.stop_points.build stop_area: stop_area
+ save_model stop_point
+
+ journey_pattern.stop_points << stop_point
+
+ # JourneyPattern#vjas_add creates automaticaly VehicleJourneyAtStop
+ vehicle_journey_at_stop = journey_pattern.vehicle_journey_at_stops.find_by(stop_point_id: stop_point.id)
+
+ departure_time = GTFS::Time.parse(stop_time.departure_time)
+ arrival_time = GTFS::Time.parse(stop_time.arrival_time)
+
+ vehicle_journey_at_stop.departure_time = departure_time.time
+ vehicle_journey_at_stop.arrival_time = arrival_time.time
+ vehicle_journey_at_stop.departure_day_offset = departure_time.day_offset
+ vehicle_journey_at_stop.arrival_day_offset = arrival_time.day_offset
+
+ # TODO offset
+
+ save_model vehicle_journey_at_stop
+ end
+ end
+ end
+ end
+ end
+
+ def time_tables_by_service_id
+ @time_tables_by_service_id ||= {}
+ end
+
+ def import_calendars
+ source.calendars.each_slice(500) do |slice|
+ Chouette::TimeTable.transaction do
+ slice.each do |calendar|
+ time_table = referential.time_tables.build comment: "Calendar #{calendar.service_id}"
+ Chouette::TimeTable.all_days.each do |day|
+ time_table.send("#{day}=", calendar.send(day))
+ end
+ time_table.periods.build period_start: calendar.start_date, period_end: calendar.end_date
+
+ save_model time_table
+
+ time_tables_by_service_id[calendar.service_id] = time_table.id
+ end
+ end
+ end
+ end
+
+ def import_calendar_dates
+ source.calendar_dates.each_slice(500) do |slice|
+ Chouette::TimeTable.transaction do
+ slice.each do |calendar_date|
+ time_table = referential.time_tables.find time_tables_by_service_id[calendar_date.service_id]
+ date = time_table.dates.build date: Date.parse(calendar_date.date), in_out: calendar_date.exception_type == "1"
+
+ save_model date
+ end
+ end
+ end
+ end
+
+ def save_model(model)
+ unless model.save
+ Rails.logger.info "Can't save #{model.class.name} : #{model.errors.inspect}"
+ raise ActiveRecord::RecordNotSaved.new("Invalid #{model.class.name} : #{model.errors.inspect}")
+ end
+ Rails.logger.debug "Created #{model.inspect}"
+ end
+
+ def notify_parent
+ return unless parent.present?
+ return if notified_parent_at
+ parent.child_change
+ update_column :notified_parent_at, Time.now
end
end
diff --git a/app/models/import/message.rb b/app/models/import/message.rb
index c1900a718..30b76ec5c 100644
--- a/app/models/import/message.rb
+++ b/app/models/import/message.rb
@@ -1,4 +1,4 @@
-class Import::Message < ActiveRecord::Base
+class Import::Message < ApplicationModel
self.table_name = :import_messages
include IevInterfaces::Message
diff --git a/app/models/import/netex.rb b/app/models/import/netex.rb
index 2b0982229..93604c5f9 100644
--- a/app/models/import/netex.rb
+++ b/app/models/import/netex.rb
@@ -10,6 +10,26 @@ class Import::Netex < Import::Base
validates_presence_of :parent
+ def create_referential!
+ self.referential =
+ Referential.new(
+ name: self.name,
+ organisation_id: workbench.organisation_id,
+ workbench_id: workbench.id,
+ metadatas: [referential_metadata]
+ )
+ self.referential.save
+ unless self.referential.valid?
+ Rails.logger.info "Can't create referential for import #{self.id}: #{referential.inspect} #{referential.metadatas.inspect} #{referential.errors.messages}"
+ if referential.metadatas.all?{|m| m.line_ids.empty?}
+ parent.messages.create criticity: :error, message_key: "referential_creation_missing_lines", message_attributes: {referential_name: referential.name}
+ else
+ parent.messages.create criticity: :error, message_key: "referential_creation", message_attributes: {referential_name: referential.name}
+ end
+ end
+ save!
+ end
+
private
def iev_callback_url
@@ -21,4 +41,22 @@ class Import::Netex < Import::Base
referential.destroy
end
end
+
+ def referential_metadata
+ metadata = ReferentialMetadata.new
+
+ if self.file
+ netex_file = STIF::NetexFile.new(self.file.path)
+ frame = netex_file.frames.first
+
+ if frame
+ metadata.periodes = frame.periods
+
+ line_objectids = frame.line_refs.map { |ref| "STIF:CODIFLIGNE:Line:#{ref}" }
+ metadata.line_ids = workbench.lines.where(objectid: line_objectids).pluck(:id)
+ end
+ end
+
+ metadata
+ end
end
diff --git a/app/models/import/resource.rb b/app/models/import/resource.rb
index 5bd011039..1951daacd 100644
--- a/app/models/import/resource.rb
+++ b/app/models/import/resource.rb
@@ -1,4 +1,4 @@
-class Import::Resource < ActiveRecord::Base
+class Import::Resource < ApplicationModel
self.table_name = :import_resources
include IevInterfaces::Resource
diff --git a/app/models/import/workbench.rb b/app/models/import/workbench.rb
index f6e15cb89..124b9b0d8 100644
--- a/app/models/import/workbench.rb
+++ b/app/models/import/workbench.rb
@@ -2,6 +2,25 @@ class Import::Workbench < Import::Base
after_commit :launch_worker, :on => :create
def launch_worker
- WorkbenchImportWorker.perform_async(id)
+ unless Import::Gtfs.accept_file?(file.path)
+ WorkbenchImportWorker.perform_async(id)
+ else
+ import_gtfs
+ end
+ end
+
+ def import_gtfs
+ update_column :status, 'running'
+ update_column :started_at, Time.now
+
+ Import::Gtfs.create! parent_id: self.id, workbench: workbench, file: File.new(file.path), name: "Import GTFS", creator: "Web service"
+
+ update_column :status, 'successful'
+ update_column :ended_at, Time.now
+ rescue Exception => e
+ Rails.logger.error "Error while processing GTFS file: #{e}"
+
+ update_column :status, 'failed'
+ update_column :ended_at, Time.now
end
end
diff --git a/app/models/line_referential.rb b/app/models/line_referential.rb
index 89700c06f..08193c960 100644
--- a/app/models/line_referential.rb
+++ b/app/models/line_referential.rb
@@ -1,4 +1,4 @@
-class LineReferential < ActiveRecord::Base
+class LineReferential < ApplicationModel
include ObjectidFormatterSupport
extend StifTransportModeEnumerations
diff --git a/app/models/line_referential_membership.rb b/app/models/line_referential_membership.rb
index dcada25bf..8371bdc32 100644
--- a/app/models/line_referential_membership.rb
+++ b/app/models/line_referential_membership.rb
@@ -1,4 +1,4 @@
-class LineReferentialMembership < ActiveRecord::Base
+class LineReferentialMembership < ApplicationModel
belongs_to :organisation
belongs_to :line_referential
diff --git a/app/models/line_referential_sync.rb b/app/models/line_referential_sync.rb
index 75c1e48a2..39e3846f0 100644
--- a/app/models/line_referential_sync.rb
+++ b/app/models/line_referential_sync.rb
@@ -1,4 +1,4 @@
-class LineReferentialSync < ActiveRecord::Base
+class LineReferentialSync < ApplicationModel
include AASM
belongs_to :line_referential
has_many :line_referential_sync_messages, :dependent => :destroy
diff --git a/app/models/line_referential_sync_message.rb b/app/models/line_referential_sync_message.rb
index 3b6cf3367..00a2b58a3 100644
--- a/app/models/line_referential_sync_message.rb
+++ b/app/models/line_referential_sync_message.rb
@@ -1,4 +1,4 @@
-class LineReferentialSyncMessage < ActiveRecord::Base
+class LineReferentialSyncMessage < ApplicationModel
belongs_to :line_referential_sync
enum criticity: [:info, :warning, :error]
diff --git a/app/models/merge.rb b/app/models/merge.rb
index e72c794fe..6e2a7036a 100644
--- a/app/models/merge.rb
+++ b/app/models/merge.rb
@@ -1,4 +1,4 @@
-class Merge < ActiveRecord::Base
+class Merge < ApplicationModel
extend Enumerize
belongs_to :workbench
@@ -138,7 +138,9 @@ class Merge < ActiveRecord::Base
new.switch do
referential_routes.each do |route|
existing_route = new.routes.find_by line_id: route.line_id, checksum: route.checksum
- unless existing_route
+ if existing_route
+ existing_route.merge_metadata_from route
+ else
objectid = Chouette::Route.where(objectid: route.objectid).exists? ? nil : route.objectid
attributes = route.attributes.merge(
id: nil,
@@ -196,7 +198,9 @@ class Merge < ActiveRecord::Base
existing_journey_pattern = new.journey_patterns.find_by route_id: existing_associated_route.id, checksum: journey_pattern.checksum
- unless existing_journey_pattern
+ if existing_journey_pattern
+ existing_journey_pattern.merge_metadata_from journey_pattern
+ else
objectid = Chouette::JourneyPattern.where(objectid: journey_pattern.objectid).exists? ? nil : journey_pattern.objectid
attributes = journey_pattern.attributes.merge(
id: nil,
@@ -241,7 +245,9 @@ class Merge < ActiveRecord::Base
existing_vehicle_journey = new.vehicle_journeys.find_by journey_pattern_id: existing_associated_journey_pattern.id, checksum: vehicle_journey.checksum
- unless existing_vehicle_journey
+ if existing_vehicle_journey
+ existing_vehicle_journey.merge_metadata_from vehicle_journey
+ else
objectid = Chouette::VehicleJourney.where(objectid: vehicle_journey.objectid).exists? ? nil : vehicle_journey.objectid
attributes = vehicle_journey.attributes.merge(
id: nil,
@@ -338,7 +344,9 @@ class Merge < ActiveRecord::Base
existing_time_table = line.time_tables.find_by checksum: candidate_time_table.checksum
- unless existing_time_table
+ if existing_time_table
+ existing_time_table.merge_metadata_from candidate_time_table
+ else
objectid = Chouette::TimeTable.where(objectid: time_table.objectid).exists? ? nil : time_table.objectid
candidate_time_table.objectid = objectid
diff --git a/app/models/organisation.rb b/app/models/organisation.rb
index 5bef67941..5742c81e8 100644
--- a/app/models/organisation.rb
+++ b/app/models/organisation.rb
@@ -1,5 +1,5 @@
# coding: utf-8
-class Organisation < ActiveRecord::Base
+class Organisation < ApplicationModel
include DataFormatEnumerations
has_many :users, :dependent => :destroy
diff --git a/app/models/public_version.rb b/app/models/public_version.rb
deleted file mode 100644
index 4dbf6ce27..000000000
--- a/app/models/public_version.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-class PublicVersion < PaperTrail::Version
- # custom behaviour, e.g:
- self.table_name = :'public.versions'
-end
diff --git a/app/models/referential.rb b/app/models/referential.rb
index 0e48be43f..1794126a2 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -1,5 +1,5 @@
# coding: utf-8
-class Referential < ActiveRecord::Base
+class Referential < ApplicationModel
include DataFormatEnumerations
include ObjectidFormatterSupport
@@ -168,6 +168,10 @@ class Referential < ActiveRecord::Base
Chouette::TimeTable.all
end
+ def time_table_dates
+ Chouette::TimeTableDate.all
+ end
+
def timebands
Chouette::Timeband.all
end
@@ -184,6 +188,10 @@ class Referential < ActiveRecord::Base
Chouette::VehicleJourneyFrequency.all
end
+ def vehicle_journey_at_stops
+ Chouette::VehicleJourneyAtStop.all
+ end
+
def routing_constraint_zones
Chouette::RoutingConstraintZone.all
end
diff --git a/app/models/referential_cloning.rb b/app/models/referential_cloning.rb
index d4b74bd52..f2c81009a 100644
--- a/app/models/referential_cloning.rb
+++ b/app/models/referential_cloning.rb
@@ -1,4 +1,4 @@
-class ReferentialCloning < ActiveRecord::Base
+class ReferentialCloning < ApplicationModel
include AASM
belongs_to :source_referential, class_name: 'Referential'
belongs_to :target_referential, class_name: 'Referential'
diff --git a/app/models/referential_metadata.rb b/app/models/referential_metadata.rb
index 017eb1449..7a8a01774 100644
--- a/app/models/referential_metadata.rb
+++ b/app/models/referential_metadata.rb
@@ -1,7 +1,7 @@
require 'activeattr_ext.rb'
require 'range_ext'
-class ReferentialMetadata < ActiveRecord::Base
+class ReferentialMetadata < ApplicationModel
belongs_to :referential, touch: true
belongs_to :referential_source, class_name: 'Referential'
has_array_of :lines, class_name: 'Chouette::Line'
diff --git a/app/models/referential_suite.rb b/app/models/referential_suite.rb
index 4f825628c..f4a72f22c 100644
--- a/app/models/referential_suite.rb
+++ b/app/models/referential_suite.rb
@@ -1,4 +1,4 @@
-class ReferentialSuite < ActiveRecord::Base
+class ReferentialSuite < ApplicationModel
belongs_to :new, class_name: 'Referential'
validate def validate_consistent_new
return true if new_id.nil? || new.nil?
diff --git a/app/models/simple_interface.rb b/app/models/simple_interface.rb
index 43c740b57..7b04a07df 100644
--- a/app/models/simple_interface.rb
+++ b/app/models/simple_interface.rb
@@ -1,4 +1,4 @@
-class SimpleInterface < ActiveRecord::Base
+class SimpleInterface < ApplicationModel
attr_accessor :configuration, :interfaces_group
class << self
diff --git a/app/models/stop_area_referential.rb b/app/models/stop_area_referential.rb
index 4706cdd77..6c339547c 100644
--- a/app/models/stop_area_referential.rb
+++ b/app/models/stop_area_referential.rb
@@ -1,4 +1,4 @@
-class StopAreaReferential < ActiveRecord::Base
+class StopAreaReferential < ApplicationModel
validates :registration_number_format, format: { with: /\AX*\z/ }
include ObjectidFormatterSupport
diff --git a/app/models/stop_area_referential_membership.rb b/app/models/stop_area_referential_membership.rb
index fbed1c004..d507bc50e 100644
--- a/app/models/stop_area_referential_membership.rb
+++ b/app/models/stop_area_referential_membership.rb
@@ -1,4 +1,4 @@
-class StopAreaReferentialMembership < ActiveRecord::Base
+class StopAreaReferentialMembership < ApplicationModel
belongs_to :organisation
belongs_to :stop_area_referential
diff --git a/app/models/stop_area_referential_sync.rb b/app/models/stop_area_referential_sync.rb
index e6cf2ecbc..8b48d35e6 100644
--- a/app/models/stop_area_referential_sync.rb
+++ b/app/models/stop_area_referential_sync.rb
@@ -1,4 +1,4 @@
-class StopAreaReferentialSync < ActiveRecord::Base
+class StopAreaReferentialSync < ApplicationModel
include AASM
belongs_to :stop_area_referential
has_many :stop_area_referential_sync_messages, :dependent => :destroy
diff --git a/app/models/stop_area_referential_sync_message.rb b/app/models/stop_area_referential_sync_message.rb
index cd2e62405..642ccfc38 100644
--- a/app/models/stop_area_referential_sync_message.rb
+++ b/app/models/stop_area_referential_sync_message.rb
@@ -1,4 +1,4 @@
-class StopAreaReferentialSyncMessage < ActiveRecord::Base
+class StopAreaReferentialSyncMessage < ApplicationModel
belongs_to :stop_area_referential_sync
enum criticity: [:info, :warning, :error]
diff --git a/app/models/user.rb b/app/models/user.rb
index eca7ede0c..ba166b06f 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,4 +1,4 @@
-class User < ActiveRecord::Base
+class User < ApplicationModel
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable, :database_authenticatable
@@ -9,7 +9,7 @@ class User < ActiveRecord::Base
:recoverable, :rememberable, :trackable, :async, authentication_type
# FIXME https://github.com/nbudin/devise_cas_authenticatable/issues/53
- # Work around :validatable, when database_authenticatable is diabled.
+ # Work around :validatable, when database_authenticatable is disabled.
attr_accessor :password unless authentication_type == :database_authenticatable
# Setup accessible (or protected) attributes for your model
diff --git a/app/models/workbench.rb b/app/models/workbench.rb
index b5f4673bb..ef0b2eaa4 100644
--- a/app/models/workbench.rb
+++ b/app/models/workbench.rb
@@ -1,4 +1,4 @@
-class Workbench < ActiveRecord::Base
+class Workbench < ApplicationModel
DEFAULT_WORKBENCH_NAME = "Gestion de l'offre"
include ObjectidFormatterSupport
diff --git a/app/models/workgroup.rb b/app/models/workgroup.rb
index 7e3e857ec..3e8409634 100644
--- a/app/models/workgroup.rb
+++ b/app/models/workgroup.rb
@@ -1,4 +1,4 @@
-class Workgroup < ActiveRecord::Base
+class Workgroup < ApplicationModel
belongs_to :line_referential
belongs_to :stop_area_referential
diff --git a/app/services/zip_service.rb b/app/services/zip_service.rb
index 7166e6448..2402721fb 100644
--- a/app/services/zip_service.rb
+++ b/app/services/zip_service.rb
@@ -1,8 +1,8 @@
class ZipService
- class Subdir < Struct.new(:name, :stream, :spurious, :foreign_lines)
+ class Subdir < Struct.new(:name, :stream, :spurious, :foreign_lines, :missing_calendar, :wrong_calendar)
def ok?
- foreign_lines.empty? && spurious.empty?
+ foreign_lines.empty? && spurious.empty? && !missing_calendar && !wrong_calendar
end
end
@@ -38,8 +38,21 @@ class ZipService
add_to_current_output entry
end
+ def validate entry
+ if is_calendar_file?(entry.name)
+ @current_calendar_is_missing = false
+ if wrong_calendar_data?(entry)
+ @current_calendar_is_wrong = true
+ return false
+ end
+ end
+ return false if is_spurious?(entry.name)
+ return false if is_foreign_line?(entry.name)
+ true
+ end
+
def add_to_current_output entry
- return if is_spurious!(entry.name) || is_foreign_line!(entry.name)
+ return unless validate(entry)
current_output.put_next_entry entry.name
write_to_current_output entry.get_input_stream
@@ -48,7 +61,7 @@ class ZipService
def write_to_current_output input_stream
# the condition below is true for directory entries
return if Zip::NullInputStream == input_stream
- current_output.write input_stream.read
+ current_output.write input_stream.read
end
def finish_current_output
@@ -58,7 +71,9 @@ class ZipService
# Second part of the solution, yield the closed stream
current_output.close_buffer,
current_spurious.to_a,
- foreign_lines)
+ foreign_lines,
+ @current_calendar_is_missing,
+ @current_calendar_is_wrong)
end
end
@@ -68,6 +83,8 @@ class ZipService
@current_output = Zip::OutputStream.new(StringIO.new(''), true, nil)
@current_spurious = Set.new
@foreign_lines = []
+ @current_calendar_is_missing = true
+ @current_calendar_is_wrong = false
end
def entry_key entry
@@ -75,7 +92,7 @@ class ZipService
entry.name.split('/').first
end
- def is_spurious! entry_name
+ def is_spurious? entry_name
segments = entry_name.split('/', 3)
return false if segments.size < 3
@@ -83,11 +100,25 @@ class ZipService
return true
end
- def is_foreign_line! entry_name
+ def is_foreign_line? entry_name
STIF::NetexFile::Frame.get_short_id(entry_name).tap do | line_object_id |
return nil unless line_object_id
return nil if line_object_id.in? allowed_lines
foreign_lines << line_object_id
end
end
+
+ def is_calendar_file? entry_name
+ entry_name =~ /calendriers.xml$/
+ end
+
+ def wrong_calendar_data? entry
+ content = entry.get_input_stream.read
+ period = STIF::NetexFile::Frame.parse_calendars content.to_s
+ return true unless period
+ return true unless period.first
+ return true unless period.end
+ return true unless period.first <= period.end
+ false
+ end
end
diff --git a/app/views/autocomplete_purchase_windows/index.rabl b/app/views/autocomplete_purchase_windows/index.rabl
index 1d0287602..bdc513c31 100644
--- a/app/views/autocomplete_purchase_windows/index.rabl
+++ b/app/views/autocomplete_purchase_windows/index.rabl
@@ -2,11 +2,12 @@ collection @purchase_windows, :object_root => false
node do |window|
{
- :id => window.id,
- :name => window.name,
- :objectid => window.objectid,
- :color => window.color,
- :short_id => window.get_objectid.short_id,
- :text => "<strong><span class='fa fa-circle' style='color:" + (window.color ? window.color : '#4b4b4b') + "'></span> " + window.name + " - " + window.get_objectid.short_id + "</strong>"
+ id: window.id,
+ name: window.name,
+ objectid: window.objectid,
+ color: window.color,
+ short_id: window.get_objectid.short_id,
+ bounding_dates: window.bounding_dates,
+ text: "<strong><span class='fa fa-circle' style='color:" + (window.color ? window.color : '#4b4b4b') + "'></span> " + window.name + " - " + window.get_objectid.short_id + "</strong>"
}
end
diff --git a/app/views/dashboards/_dashboard.html.slim b/app/views/dashboards/_dashboard.html.slim
index e1be3df4a..466695b5a 100644
--- a/app/views/dashboards/_dashboard.html.slim
+++ b/app/views/dashboards/_dashboard.html.slim
@@ -6,7 +6,7 @@
h3.panel-title.with_actions
div
= link_to t('dashboards.workbench.title', organisation: workbench.organisation.name), workbench_path(workbench)
- span.badge.ml-xs = workbench.referentials.count if workbench.referentials.present?
+ span.badge.ml-xs = workbench.all_referentials.uniq.count if workbench.all_referentials.present?
div
= link_to '', workbench_path(workbench), class: ' fa fa-chevron-right pull-right', title: t('workbenches.index.offers.see')
diff --git a/app/views/lines/_filters.html.slim b/app/views/lines/_filters.html.slim
index da0539bd0..f745d10a4 100644
--- a/app/views/lines/_filters.html.slim
+++ b/app/views/lines/_filters.html.slim
@@ -44,5 +44,5 @@
.actions
- = link_to 'Effacer', @workbench, class: 'btn btn-link'
- = f.submit 'Filtrer', class: 'btn btn-default'
+ = link_to t('actions.erase'), @workbench, class: 'btn btn-link'
+ = f.submit t('actions.filter'), class: 'btn btn-default'
diff --git a/app/views/lines/show.html.slim b/app/views/lines/show.html.slim
index 96bb5bb0d..9e1ae6d6f 100644
--- a/app/views/lines/show.html.slim
+++ b/app/views/lines/show.html.slim
@@ -6,7 +6,7 @@
.row
.col-lg-6.col-md-6.col-sm-12.col-xs-12
= definition_list t('metadatas'),
- { t('id_codif') => @line.get_objectid.short_id,
+ { t('objectid') => @line.get_objectid.short_id,
@line.human_attribute_name(:deactivated) => (@line.deactivated? ? t('false') : t('true')),
@line.human_attribute_name(:network_id) => (@line.network.nil? ? t('lines.index.unset') : @line.network.name),
@line.human_attribute_name(:company_id) => (@line.company.nil? ? t('lines.index.unset') : @line.company.name),
diff --git a/app/views/referential_lines/_filters.html.slim b/app/views/referential_lines/_filters.html.slim
index 501f61c16..15db0e33e 100644
--- a/app/views/referential_lines/_filters.html.slim
+++ b/app/views/referential_lines/_filters.html.slim
@@ -1,7 +1,7 @@
= search_form_for @q, url: referential_line_path(@referential, @line), class: 'form form-filter' do |f|
.ffg-row
.input-group.search_bar class=filter_item_class(params[:q], :name_or_objectid_cont)
- = f.search_field :name_or_objectid_cont, class: 'form-control', placeholder: "Indiquez un nom d'itinéraire ou un ID..."
+ = f.search_field :name_or_objectid_cont, class: 'form-control', placeholder: t('.name_or_objectid_cont')
span.input-group-btn
button.btn.btn-default#search-btn type='submit'
span.fa.fa-search
@@ -12,5 +12,5 @@
= f.input :wayback_eq_any, class: 'form-control', collection: Chouette::Route.wayback.values, as: :check_boxes, label: false, required: false, wrapper_html: { class: 'checkbox_list'}, label_method: lambda{|l| ("<span>" + t("enumerize.route.wayback.#{l}") + "</span>").html_safe}
.actions
- = link_to 'Effacer', referential_line_path(@referential, @line), class: 'btn btn-link'
- = f.submit 'Filtrer', class: 'btn btn-default'
+ = link_to t('actions.erase'), referential_line_path(@referential, @line), class: 'btn btn-link'
+ = f.submit t('actions.filter'), class: 'btn btn-default'
diff --git a/app/views/referential_vehicle_journeys/_filters.html.slim b/app/views/referential_vehicle_journeys/_filters.html.slim
index f1fbdb5d8..f9fa4fcf7 100644
--- a/app/views/referential_vehicle_journeys/_filters.html.slim
+++ b/app/views/referential_vehicle_journeys/_filters.html.slim
@@ -68,5 +68,5 @@
.actions
- = link_to 'Effacer', referential_vehicle_journeys_path(@referential), class: 'btn btn-link'
- = f.submit 'Filtrer', class: 'btn btn-default'
+ = link_to t('actions.erase'), referential_vehicle_journeys_path(@referential), class: 'btn btn-link'
+ = f.submit t('actions.filter'), class: 'btn btn-default'
diff --git a/app/views/referentials/select_compliance_control_set.html.slim b/app/views/referentials/select_compliance_control_set.html.slim
index 3550bb202..7be82364d 100644
--- a/app/views/referentials/select_compliance_control_set.html.slim
+++ b/app/views/referentials/select_compliance_control_set.html.slim
@@ -8,7 +8,7 @@
.row
.col-lg-12
.form-group
- = label_tag 'name', nil, class: 'string required col-sm-4 col-xs-5 control-label'
+ = label_tag ComplianceControlSet.ts, nil, class: 'string required col-sm-4 col-xs-5 control-label'
.col-sm-8.col-xs-7
= select_tag :compliance_control_set, options_from_collection_for_select(@compliance_control_sets, "id", "name"), class: 'select optional form-control'
.separator
diff --git a/app/views/routes/show.html.slim b/app/views/routes/show.html.slim
index d2e750fb0..d4571c173 100644
--- a/app/views/routes/show.html.slim
+++ b/app/views/routes/show.html.slim
@@ -34,7 +34,7 @@
end \
), \
TableBuilderHelper::Column.new( \
- key: :deleted_at, \
+ name: Chouette::Line.tmf('activated'), \
attribute: Proc.new { |s| line_status(s.try(:stop_area).deleted_at) } \
), \
TableBuilderHelper::Column.new( \
diff --git a/app/views/shared/iev_interfaces/_messages.html.slim b/app/views/shared/iev_interfaces/_messages.html.slim
index 14157a88d..4e2c4d849 100644
--- a/app/views/shared/iev_interfaces/_messages.html.slim
+++ b/app/views/shared/iev_interfaces/_messages.html.slim
@@ -1,14 +1,15 @@
- if messages.any?
ul.list-unstyled.import_message-list
- messages.order(:created_at).each do | message |
+ - width = message.resource_attributes.present? ? 6 : 12
li
.row class=bootstrap_class_for_message_criticity(message.criticity)
- if message.message_attributes && message.message_attributes["line"]
.col-md-1= "L. #{message.message_attributes["line"]}"
- .col-md-5= export_message_content message
+ div class="col-md-#{width-1}"= export_message_content message
- else
- .col-md-6= export_message_content message
+ div class="col-md-#{width}"= export_message_content message
.col-md-6
- - if message.resource_attributes
+ - if message.resource_attributes.present?
pre
= JSON.pretty_generate message.resource_attributes || {}
diff --git a/app/views/stop_areas/_filters.html.slim b/app/views/stop_areas/_filters.html.slim
index a32638567..c698eaaa5 100644
--- a/app/views/stop_areas/_filters.html.slim
+++ b/app/views/stop_areas/_filters.html.slim
@@ -41,5 +41,5 @@
input_html: { checked: @status.try(:[], :deactivated) }
.actions
- = link_to 'Effacer', @workbench, class: 'btn btn-link'
- = f.submit 'Filtrer', class: 'btn btn-default'
+ = link_to t('actions.erase'), @workbench, class: 'btn btn-link'
+ = f.submit t('actions.filter'), class: 'btn btn-default'
diff --git a/app/views/stop_areas/index.html.slim b/app/views/stop_areas/index.html.slim
index 587efbdaa..fbdb54e02 100644
--- a/app/views/stop_areas/index.html.slim
+++ b/app/views/stop_areas/index.html.slim
@@ -32,7 +32,7 @@
attribute: 'registration_number' \
), \
TableBuilderHelper::Column.new( \
- name: t('activerecord.attributes.stop_area.state'), \
+ name: Chouette::StopArea.tmf('state'), \
attribute: Proc.new { |s| stop_area_status(s) } \
), \
TableBuilderHelper::Column.new( \
diff --git a/app/views/time_tables/index.html.slim b/app/views/time_tables/index.html.slim
index 6913712a0..58bf66a9d 100644
--- a/app/views/time_tables/index.html.slim
+++ b/app/views/time_tables/index.html.slim
@@ -28,14 +28,14 @@
end \
), \
TableBuilderHelper::Column.new( \
+ key: :bounding_dates, \
name: "Période englobante", \
- attribute: Proc.new { |tt| tt.bounding_dates.empty? ? '-' : t('bounding_dates', debut: l(tt.bounding_dates.min), end: l(tt.bounding_dates.max)) }, \
- sortable: false \
+ attribute: Proc.new { |tt| tt.object.bounding_dates.empty? ? '-' : t('bounding_dates', debut: l(tt.object.bounding_dates.min), end: l(tt.object.bounding_dates.max)) }, \
), \
TableBuilderHelper::Column.new( \
+ key: :vehicle_journeys_count, \
name: "Nombre de courses associées", \
attribute: Proc.new{ |tt| tt.vehicle_journeys.count }, \
- sortable: false \
), \
TableBuilderHelper::Column.new( \
name: "Journées d'application", \
diff --git a/app/views/vehicle_journeys/index.html.slim b/app/views/vehicle_journeys/index.html.slim
index c92fb7bae..7fcee545f 100644
--- a/app/views/vehicle_journeys/index.html.slim
+++ b/app/views/vehicle_journeys/index.html.slim
@@ -7,7 +7,7 @@
- if has_feature? :purchase_windows
= link_to I18n.t("purchase_windows.index.title"), [@referential, :purchase_windows], class: 'btn btn-primary sticky-action', target: :blank
- if @route.opposite_route.present?
- = link_to(t('routes.actions.opposite_route_timetable'), [@referential, @route.line, @route.opposite_route, :vehicle_journeys], class: 'btn btn-primary sticky-action')
+ = link_to(t('routes.actions.reversed_vehicle_journey'), [@referential, @route.line, @route.opposite_route, :vehicle_journeys], class: 'btn btn-primary sticky-action')
.page_content
diff --git a/app/views/workbench_outputs/show.html.slim b/app/views/workbench_outputs/show.html.slim
index a9e106dbb..b310119e6 100644
--- a/app/views/workbench_outputs/show.html.slim
+++ b/app/views/workbench_outputs/show.html.slim
@@ -6,7 +6,8 @@
.row.mb-sm
.col-lg-12.text-right
= link_to t('.see_current_output'), referential_path(@workbench.output.current), class: 'btn btn-primary' if @workbench.output&.current
- = link_to t('merges.actions.create'), new_workbench_merge_path(@workbench), class: 'btn btn-primary'
+ - if policy(Merge).create?
+ = link_to t('merges.actions.create'), new_workbench_merge_path(@workbench), class: 'btn btn-primary'
.page_content
.container-fluid
diff --git a/app/views/workbenches/show.html.slim b/app/views/workbenches/show.html.slim
index 8312338d0..7dd1583fa 100644
--- a/app/views/workbenches/show.html.slim
+++ b/app/views/workbenches/show.html.slim
@@ -32,7 +32,8 @@
end \
), \
TableBuilderHelper::Column.new( \
- key: :status, \
+ key: :archived_at, \
+ name: Referential.tmf('status'), \
attribute: Proc.new {|w| w.referential_read_only? ? ("<div class='td-block'><span class='fa fa-archive'></span><span>#{t('activerecord.attributes.referential.archived_at')}</span></div>").html_safe : ("<div class='td-block'><span class='sb sb-lg sb-preparing'></span><span>#{t('activerecord.attributes.referential.archived_at_null')}</span></div>").html_safe} \
), \
TableBuilderHelper::Column.new( \
@@ -45,7 +46,7 @@
), \
TableBuilderHelper::Column.new( \
key: :lines, \
- name: t('activerecord.attributes.referential.number_of_lines'), \
+ name: Referential.tmf('number_of_lines'), \
attribute: Proc.new {|w| w.lines.count} \
), \
TableBuilderHelper::Column.new( \
diff --git a/app/workers/gtfs_import_worker.rb b/app/workers/gtfs_import_worker.rb
new file mode 100644
index 000000000..02f5053b0
--- /dev/null
+++ b/app/workers/gtfs_import_worker.rb
@@ -0,0 +1,7 @@
+class GtfsImportWorker
+ include Sidekiq::Worker
+
+ def perform(import_id)
+ Import::Gtfs.find(import_id).import
+ end
+end
diff --git a/app/workers/workbench_import_worker/object_state_updater.rb b/app/workers/workbench_import_worker/object_state_updater.rb
index 67bdc0654..1edc6b9a1 100644
--- a/app/workers/workbench_import_worker/object_state_updater.rb
+++ b/app/workers/workbench_import_worker/object_state_updater.rb
@@ -6,9 +6,10 @@ class WorkbenchImportWorker
workbench_import.update( total_steps: count )
update_spurious entry
update_foreign_lines entry
+ update_missing_calendar entry
+ update_wrong_calendar entry
end
-
private
def update_foreign_lines entry
@@ -19,7 +20,7 @@ class WorkbenchImportWorker
message_attributes: {
'source_filename' => workbench_import.file.file.file,
'foreign_lines' => entry.foreign_lines.join(', ')
- })
+ })
end
def update_spurious entry
@@ -30,7 +31,27 @@ class WorkbenchImportWorker
message_attributes: {
'source_filename' => workbench_import.file.file.file,
'spurious_dirs' => entry.spurious.join(', ')
- })
+ })
+ end
+
+ def update_missing_calendar entry
+ return unless entry.missing_calendar
+ workbench_import.messages.create(
+ criticity: :error,
+ message_key: 'missing_calendar_in_zip_file',
+ message_attributes: {
+ 'source_filename' => entry.name
+ })
+ end
+
+ def update_wrong_calendar entry
+ return unless entry.wrong_calendar
+ workbench_import.messages.create(
+ criticity: :error,
+ message_key: 'wrong_calendar_in_zip_file',
+ message_attributes: {
+ 'source_filename' => entry.name
+ })
end
end
end