diff options
Diffstat (limited to 'app')
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 |
