diff options
39 files changed, 355 insertions, 205 deletions
@@ -100,6 +100,7 @@ gem 'simple_form', '~> 3.1.0' gem 'font-awesome-sass', '~> 4.7' gem 'will_paginate-bootstrap' gem 'gretel' +gem 'country_select' # Format Output gem 'json' diff --git a/Gemfile.lock b/Gemfile.lock index 9c59016e6..ade052d8a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -146,6 +146,14 @@ GEM coffee-script-source (1.12.2) concurrent-ruby (1.0.5) connection_pool (2.2.1) + countries (2.1.3) + i18n_data (~> 0.8.0) + money (~> 6.9) + sixarm_ruby_unaccent (~> 1.1) + unicode_utils (~> 1.4) + country_select (3.1.1) + countries (~> 2.0) + sort_alphabetical (~> 1.0) crack (0.4.3) safe_yaml (~> 1.0.0) cucumber (2.4.0) @@ -269,6 +277,7 @@ GEM parser (>= 2.2.3.0) rainbow (~> 2.2) terminal-table (>= 1.5.1) + i18n_data (0.8.0) inherited_resources (1.7.1) actionpack (>= 3.2, < 5.1) has_scope (~> 0.6) @@ -305,6 +314,8 @@ GEM mimemagic (0.3.2) mini_portile2 (2.3.0) minitest (5.10.3) + money (6.10.1) + i18n (>= 0.6.4, < 1.0) multi_json (1.12.1) multi_test (0.1.2) multi_xml (0.6.0) @@ -487,6 +498,7 @@ GEM rack (~> 1.5) rack-protection (~> 1.4) tilt (>= 1.3, < 3) + sixarm_ruby_unaccent (1.2.0) slim (3.0.7) temple (~> 0.7.6) tilt (>= 1.3.3, < 2.1) @@ -495,6 +507,8 @@ GEM railties (>= 3.1) slim (~> 3.0) slop (3.6.0) + sort_alphabetical (1.1.0) + unicode_utils (>= 1.2.2) spring (2.0.1) activesupport (>= 4.2) spring-commands-rspec (1.0.4) @@ -537,6 +551,7 @@ GEM execjs (>= 0.3.0) json (>= 1.8.0) unicode-display_width (1.3.0) + unicode_utils (1.4.0) warden (1.2.7) rack (>= 1.0) webmock (3.0.1) @@ -584,6 +599,7 @@ DEPENDENCIES cocoon codifligne! coffee-rails (~> 4.0.0) + country_select cucumber-rails daemons database_cleaner diff --git a/app/assets/javascripts/select2.coffee b/app/assets/javascripts/select2.coffee index 2e3884d7f..4cf5f42d0 100644 --- a/app/assets/javascripts/select2.coffee +++ b/app/assets/javascripts/select2.coffee @@ -9,24 +9,27 @@ bind_select2 = (el, cfg = {}) -> target.select2 $.extend({}, default_cfg, cfg) bind_select2_ajax = (el, cfg = {}) -> - target = $(el) + _this = $(el) cfg = ajax: data: (params) -> - q: - "#{target.data('term')}": params.term - url: target.data('url'), + if _this.data('term') + { q: "#{_this.data('term')}": params.term } + else + { q: params.term } + url: _this.data('url'), dataType: 'json', delay: 125, processResults: (data, params) -> results: data - minimumInputLength: 1 - placeholder: target.data('select2ed-placeholder') templateResult: (item) -> item.text templateSelection: (item) -> item.text escapeMarkup: (markup) -> markup + initSelection : (item, callback) -> + if _this.data('initvalue') + callback(_this.data('initvalue')) bind_select2(el, cfg) @@ -40,7 +43,5 @@ bind_select2_ajax = (el, cfg = {}) -> $('select.form-control.tags').each -> bind_select2(this, {tags: true}) - - $ -> select_2() diff --git a/app/assets/stylesheets/modules/import_messages.sass b/app/assets/stylesheets/modules/import_messages.sass index e5666cbcd..6a088dc06 100644 --- a/app/assets/stylesheets/modules/import_messages.sass +++ b/app/assets/stylesheets/modules/import_messages.sass @@ -2,4 +2,42 @@ .status_icon padding-right: 20px h1 - padding-bottom: 20px + padding-bottom: 20px + + +.import_message-list + padding-bottom: 20px + + .import_messages-head + display: block + font-size: 1.8rem + font-weight: 700 + border-bottom: 2px solid #4b4b4b + padding: 5px 15px 6px 15px + + dl + dd, dt + display: inline-block + letter-spacing: normal + word-spacing: normal + text-rendering: auto + vertical-align: top + padding: 5px 15px 6px 15px + + dt + position: relative + width: 7% + font-weight: 700 + + &:before + content: "" + display: block + position: absolute + z-index: 1 + top: 0 + left: 0 + width: 250% + border-bottom: 1px solid rgba(164, 164, 164, 0.5) + + dd + width: 93%
\ No newline at end of file diff --git a/app/controllers/stop_areas_controller.rb b/app/controllers/stop_areas_controller.rb index b478d38fa..178a2413f 100644 --- a/app/controllers/stop_areas_controller.rb +++ b/app/controllers/stop_areas_controller.rb @@ -1,7 +1,7 @@ class StopAreasController < ChouetteController include ApplicationHelper include Activatable - + defaults :resource_class => Chouette::StopArea belongs_to :stop_area_referential @@ -14,10 +14,12 @@ class StopAreasController < ChouetteController respond_to :html, :kml, :xml, :json respond_to :js, :only => :index - # def complete - # @stop_areas = line.stop_areas - # render :layout => false - # end + def autocomplete + scope = stop_area_referential.stop_areas.where(deleted_at: nil) + args = [].tap{|arg| 4.times{arg << "%#{params[:q]}%"}} + @stop_areas = scope.where("unaccent(name) ILIKE unaccent(?) OR unaccent(city_name) ILIKE unaccent(?) OR registration_number ILIKE ? OR objectid ILIKE ?", *args).limit(50) + @stop_areas + end def select_parent @stop_area = stop_area diff --git a/app/helpers/common_helper.rb b/app/helpers/common_helper.rb deleted file mode 100644 index b515f681b..000000000 --- a/app/helpers/common_helper.rb +++ /dev/null @@ -1,8 +0,0 @@ - -module CommonHelper - def string_keys_to_symbols enumerable_pairs - enumerable_pairs.inject({}){ | hashy, (k, v) | - hashy.merge k.to_sym => v - } - end -end diff --git a/app/javascript/vehicle_journeys/actions/index.js b/app/javascript/vehicle_journeys/actions/index.js index 202c09440..40c8006f1 100644 --- a/app/javascript/vehicle_journeys/actions/index.js +++ b/app/javascript/vehicle_journeys/actions/index.js @@ -188,26 +188,18 @@ const actions = { resetValidation: (target) => { $(target).parent().removeClass('has-error').children('.help-block').remove() }, - validateFields : (...fields) => { - const test = [] - - Object.keys(fields).map(function(key) { - test.push(fields[key].validity.valid) + validateFields : (fields) => { + let valid = true + Object.keys(fields).forEach((key) => { + let field = fields[key] + if(field.validity && !field.validity.valid){ + valid = false + $(field).parent().addClass('has-error').children('.help-block').remove() + $(field).parent().append("<span class='small help-block'>" + field.validationMessage + "</span>") + } }) - if(test.indexOf(false) >= 0) { - // Form is invalid - test.map(function(item, i) { - if(item == false) { - const k = Object.keys(fields)[i] - $(fields[k]).parent().addClass('has-error').children('.help-block').remove() - $(fields[k]).parent().append("<span class='small help-block'>" + fields[k].validationMessage + "</span>") - } - }) - return false - } else { - // Form is valid - return true - } + + return valid }, toggleArrivals : () => ({ type: 'TOGGLE_ARRIVALS', @@ -349,35 +341,35 @@ const actions = { color: tt.color }) } - for (tt of val.purchase_windows){ - purchaseWindows.push({ - objectid: tt.objectid, - name: tt.name, - id: tt.id, - color: tt.color - }) + if(val.purchase_windows){ + for (tt of val.purchase_windows){ + purchaseWindows.push({ + objectid: tt.objectid, + name: tt.name, + id: tt.id, + color: tt.color + }) + } } let vjasWithDelta = val.vehicle_journey_at_stops.map((vjas, i) => { actions.fillEmptyFields(vjas) return actions.getDelta(vjas) }) - vehicleJourneys.push({ - journey_pattern: val.journey_pattern, - published_journey_name: val.published_journey_name, - objectid: val.objectid, - short_id: val.short_id, - footnotes: val.footnotes, - time_tables: timeTables, - purchase_windows: purchaseWindows, - vehicle_journey_at_stops: vjasWithDelta, - deletable: false, - selected: false, - published_journey_name: val.published_journey_name || 'non renseigné', - published_journey_identifier: val.published_journey_identifier || 'non renseigné', - company: val.company || 'non renseigné', - transport_mode: val.route.line.transport_mode || 'undefined', - transport_submode: val.route.line.transport_submode || 'undefined' - }) + + vehicleJourneys.push( + _.assign({}, val, { + time_tables: timeTables, + purchase_windows: purchaseWindows, + vehicle_journey_at_stops: vjasWithDelta, + deletable: false, + selected: false, + published_journey_name: val.published_journey_name || 'non renseigné', + published_journey_identifier: val.published_journey_identifier || 'non renseigné', + company: val.company || {name: 'non renseigné'}, + transport_mode: val.route.line.transport_mode || 'undefined', + transport_submode: val.route.line.transport_submode || 'undefined' + }) + ) } window.currentItemsLength = vehicleJourneys.length dispatch(actions.receiveVehicleJourneys(vehicleJourneys)) diff --git a/app/javascript/vehicle_journeys/components/VehicleJourney.js b/app/javascript/vehicle_journeys/components/VehicleJourney.js index 1e62444ef..5f6281487 100644 --- a/app/javascript/vehicle_journeys/components/VehicleJourney.js +++ b/app/javascript/vehicle_journeys/components/VehicleJourney.js @@ -64,10 +64,11 @@ export default class VehicleJourney extends Component { <div className='th' onClick={(e) => - ($(e.target).parents("a").length == 0) && this.props.editMode && this.props.onSelectVehicleJourney(this.props.index) + ($(e.target).parents("a").length == 0) && this.props.onSelectVehicleJourney(this.props.index) } > <div className='strong mb-xs'>{this.props.value.short_id || '-'}</div> + <div>{this.props.value.published_journey_name && this.props.value.published_journey_name != "non renseigné" ? this.props.value.published_journey_name : '-'}</div> <div>{this.props.value.journey_pattern.short_id || '-'}</div> <div> {time_tables.slice(0,3).map((tt, i)=> diff --git a/app/javascript/vehicle_journeys/components/VehicleJourneys.js b/app/javascript/vehicle_journeys/components/VehicleJourneys.js index e16d03f90..dc480d6b4 100644 --- a/app/javascript/vehicle_journeys/components/VehicleJourneys.js +++ b/app/javascript/vehicle_journeys/components/VehicleJourneys.js @@ -115,6 +115,7 @@ export default class VehicleJourneys extends Component { <div className='t2e-head w20'> <div className='th'> <div className='strong mb-xs'>ID course</div> + <div>Nom course</div> <div>ID mission</div> <div>Calendriers</div> { this.hasFeature('purchase_windows') && <div>Calendriers Commerciaux</div> } diff --git a/app/javascript/vehicle_journeys/components/tools/CreateModal.js b/app/javascript/vehicle_journeys/components/tools/CreateModal.js index 33873219c..cd593cdff 100644 --- a/app/javascript/vehicle_journeys/components/tools/CreateModal.js +++ b/app/javascript/vehicle_journeys/components/tools/CreateModal.js @@ -61,7 +61,7 @@ export default class CreateModal extends Component { <div className='form-group'> <label className='control-label'>Nom du transporteur</label> <CompanySelect2 - company = {undefined} + company = {this.props.modal.modalProps.vehicleJourney && this.props.modal.modalProps.vehicleJourney.company || undefined} onSelect2Company = {(e) => this.props.onSelect2Company(e)} /> </div> @@ -130,4 +130,4 @@ CreateModal.propTypes = { onAddVehicleJourney: PropTypes.func.isRequired, onSelect2JourneyPattern: PropTypes.func.isRequired, disabled: PropTypes.bool.isRequired -}
\ No newline at end of file +} diff --git a/app/javascript/vehicle_journeys/reducers/modal.js b/app/javascript/vehicle_journeys/reducers/modal.js index 862e27e1b..eae3314e8 100644 --- a/app/javascript/vehicle_journeys/reducers/modal.js +++ b/app/javascript/vehicle_journeys/reducers/modal.js @@ -1,6 +1,6 @@ import _ from 'lodash' -let vehicleJourneysModal, newModalProps +let vehicleJourneysModal, newModalProps, vehicleJourney export default function modal(state = {}, action) { switch (action.type) { @@ -74,10 +74,12 @@ export default function modal(state = {}, action) { confirmModal: {} } case 'SELECT_CP_EDIT_MODAL': - newModalProps = _.assign({}, state.modalProps, {selectedCompany : action.selectedItem}) + vehicleJourney = _.assign({}, state.modalProps.vehicleJourney, {company: action.selectedItem}) + newModalProps = _.assign({}, state.modalProps, {vehicleJourney}) return _.assign({}, state, {modalProps: newModalProps}) case 'UNSELECT_CP_EDIT_MODAL': - newModalProps = _.assign({}, state.modalProps, {selectedCompany : undefined}) + vehicleJourney = _.assign({}, state.modalProps.vehicleJourney, {company: undefined}) + newModalProps = _.assign({}, state.modalProps, {vehicleJourney}) return _.assign({}, state, {modalProps: newModalProps}) case 'SELECT_TT_CALENDAR_MODAL': newModalProps = _.assign({}, state.modalProps, {selectedTimetable : action.selectedItem}) diff --git a/app/models/chouette/area_type.rb b/app/models/chouette/area_type.rb index 33cbfbb48..43d96b391 100644 --- a/app/models/chouette/area_type.rb +++ b/app/models/chouette/area_type.rb @@ -1,4 +1,5 @@ class Chouette::AreaType + include Comparable ALL = %i(zdep zder zdlp zdlr lda gdl).freeze @@ -30,6 +31,10 @@ class Chouette::AreaType @code = code end + def <=>(other) + all.index(code) <=> all.index(other.code) + end + def label I18n.translate code, scope: 'area_types.label' end diff --git a/app/models/chouette/stop_area.rb b/app/models/chouette/stop_area.rb index 2f8d7c096..4f1359ff8 100644 --- a/app/models/chouette/stop_area.rb +++ b/app/models/chouette/stop_area.rb @@ -40,12 +40,20 @@ module Chouette validates_format_of :url, :with => %r{\Ahttps?:\/\/([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?\Z}, :allow_nil => true, :allow_blank => true validates_numericality_of :waiting_time, greater_than_or_equal_to: 0, only_integer: true, if: :waiting_time + validate :parent_area_type_must_be_greater def self.nullable_attributes [:registration_number, :street_name, :country_code, :fare_code, :nearest_topic_name, :comment, :long_lat_type, :zip_code, :city_name, :url, :time_zone] end + def parent_area_type_must_be_greater + return unless self.parent + if Chouette::AreaType.find(self.area_type) >= Chouette::AreaType.find(self.parent.area_type) + errors.add(:parent_id, I18n.t('stop_areas.errors.parent_area_type', area_type: self.parent.area_type)) + end + end + after_update :clean_invalid_access_links before_save :coordinates_to_lat_lng @@ -74,6 +82,10 @@ module Chouette end end + def full_name + "#{name} #{zip_code} #{city_name} - #{user_objectid}" + end + def user_objectid if objectid =~ /^.*:([0-9A-Za-z_-]+):STIF$/ $1 diff --git a/app/models/compliance_control.rb b/app/models/compliance_control.rb index 3fcf26f5d..2bde5b95a 100644 --- a/app/models/compliance_control.rb +++ b/app/models/compliance_control.rb @@ -6,7 +6,7 @@ class ComplianceControl < ActiveRecord::Base def prerequisite; I18n.t('compliance_controls.metas.no_prerequisite'); end def predicate; I18n.t("compliance_controls.#{self.name.underscore}.description") end def dynamic_attributes - stored_attributes[:control_attributes] + stored_attributes[:control_attributes] || [] end def policy_class diff --git a/app/models/import.rb b/app/models/import.rb index 19e835986..049a65f40 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -19,7 +19,6 @@ class Import < ActiveRecord::Base validates :name, presence: true validates :file, presence: true validates_presence_of :workbench, :creator - validates_format_of :file, with: %r{\.zip\z}i, message: I18n.t('activerecord.errors.models.import.attributes.file.wrong_file_extension') before_create :initialize_fields diff --git a/app/models/vehicle_journey_control/waiting_time.rb b/app/models/vehicle_journey_control/waiting_time.rb index 252135f04..f2666cb72 100644 --- a/app/models/vehicle_journey_control/waiting_time.rb +++ b/app/models/vehicle_journey_control/waiting_time.rb @@ -2,7 +2,7 @@ module VehicleJourneyControl class WaitingTime < ComplianceControl store_accessor :control_attributes, :maximum - validates :maximum, numericality: true, allow_nil: true + validates_numericality_of :maximum, allow_nil: true, greater_than_or_equal_to: 0 def self.default_code; "3-VehicleJourney-1" end end diff --git a/app/uploaders/import_uploader.rb b/app/uploaders/import_uploader.rb index 2740393ca..60e17ca0f 100644 --- a/app/uploaders/import_uploader.rb +++ b/app/uploaders/import_uploader.rb @@ -36,9 +36,9 @@ class ImportUploader < CarrierWave::Uploader::Base # Add a white list of extensions which are allowed to be uploaded. # For images you might use something like this: - # def extension_whitelist - # %w(jpg jpeg gif png) - # end + def extension_whitelist + %w(zip) + end # Override the filename of the uploaded files: # Avoid using model.id or version_name here, see uploader/store.rb for details. diff --git a/app/views/autocomplete_stop_areas/index.rabl b/app/views/autocomplete_stop_areas/index.rabl index 5a9f76a47..d20051ad5 100644 --- a/app/views/autocomplete_stop_areas/index.rabl +++ b/app/views/autocomplete_stop_areas/index.rabl @@ -14,7 +14,8 @@ node do |stop_area| :longitude => stop_area.longitude, :latitude => stop_area.latitude, :area_type => stop_area.area_type, - :comment => stop_area.comment + :comment => stop_area.comment, + :text => stop_area.full_name } end diff --git a/app/views/imports/_import_messages.html.slim b/app/views/imports/_import_messages.html.slim index 9ab9226f7..a10dce065 100644 --- a/app/views/imports/_import_messages.html.slim +++ b/app/views/imports/_import_messages.html.slim @@ -1,10 +1,11 @@ - - if import_messages.any? - dl#import_messages - - import_messages.each do | import_message | - dt.import_message - = import_message.criticity - dd.import_message - = t( ['import_messages', - 'compliance_check_messages', - import_message.message_key].join('.'), string_keys_to_symbols(import_message.message_attributes)) + .import_message-list + .import_messages-head Messages + dl + - import_messages.each do | import_message | + dt.criticity + = import_message.criticity + dd + = t( ['import_messages', + 'compliance_check_messages', + import_message.message_key].join('.'), import_message.message_attributes.symbolize_keys) diff --git a/app/views/imports/show.html.slim b/app/views/imports/show.html.slim index 90c638d78..cf137867b 100644 --- a/app/views/imports/show.html.slim +++ b/app/views/imports/show.html.slim @@ -11,9 +11,6 @@ - page_header_content_for @import -.error_messages - = render 'import_messages', import_messages: @import.messages - .page_content .container-fluid .row @@ -22,46 +19,52 @@ .row .col-lg-12 - = table_builder_2 @import.children, - [ \ - TableBuilderHelper::Column.new( \ - name: 'Nom du jeu de données', \ - attribute: 'name', \ - sortable: false, \ - link_to: lambda do |import| \ - referential_path(import.referential) if import.referential.present? \ - end \ - ), \ - TableBuilderHelper::Column.new( \ - key: :status, \ - attribute: Proc.new { |n| import_status(n.status) }, \ - sortable: false, \ - link_to: lambda do |import| \ - workbench_import_import_resources_path(import.workbench_id, import) \ - end \ - ), \ - TableBuilderHelper::Column.new( \ - name: 'Contrôle STIF', \ - attribute: '', \ - sortable: false, \ - ), \ - TableBuilderHelper::Column.new( \ - name: 'Contrôle organisation', \ - attribute: '', \ - sortable: false, \ - ) \ - ], - links: [], - cls: 'table', - overhead: [ \ - {}, \ - { \ - title: "#{@import.children_succeedeed} jeu de données validé sur #{@import.children.count} présent(s) dans l'archive", \ - width: 1, \ - cls: "#{@import.import_status_css_class} full-border" \ - }, { \ - title: 'Bilan des jeux de contrôles d\'import <span title="Lorem ipsum..." class="fa fa-lg fa-info-circle text-info"></span>', \ - width: 2, \ - cls: 'overheaded-default colspan="2"' \ - } \ - ] + .error_messages + = render 'import_messages', import_messages: @import.messages + + - if @import.children.any? + .row + .col-lg-12 + = table_builder_2 @import.children, + [ \ + TableBuilderHelper::Column.new( \ + name: 'Nom du jeu de données', \ + attribute: 'name', \ + sortable: false, \ + link_to: lambda do |import| \ + referential_path(import.referential) if import.referential.present? \ + end \ + ), \ + TableBuilderHelper::Column.new( \ + key: :status, \ + attribute: Proc.new { |n| import_status(n.status) }, \ + sortable: false, \ + link_to: lambda do |import| \ + workbench_import_import_resources_path(import.workbench_id, import) \ + end \ + ), \ + TableBuilderHelper::Column.new( \ + name: 'Contrôle STIF', \ + attribute: '', \ + sortable: false, \ + ), \ + TableBuilderHelper::Column.new( \ + name: 'Contrôle organisation', \ + attribute: '', \ + sortable: false, \ + ) \ + ], + links: [], + cls: 'table', + overhead: [ \ + {}, \ + { \ + title: "#{@import.children_succeedeed} jeu de données validé sur #{@import.children.count} présent(s) dans l'archive", \ + width: 1, \ + cls: "#{@import.import_status_css_class} full-border" \ + }, { \ + title: 'Bilan des jeux de contrôles d\'import <span title="Lorem ipsum..." class="fa fa-lg fa-info-circle text-info"></span>', \ + width: 2, \ + cls: 'overheaded-default colspan="2"' \ + } \ + ] diff --git a/app/views/stop_areas/_form.html.slim b/app/views/stop_areas/_form.html.slim index e44680499..af8b9d889 100644 --- a/app/views/stop_areas/_form.html.slim +++ b/app/views/stop_areas/_form.html.slim @@ -6,6 +6,9 @@ /= @map.to_html = f.input :id, as: :hidden = f.input :name, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.name")} + + = f.input :parent_id, as: :select, :collection => [f.object.parent_id], input_html: { data: { select2_ajax: 'true', url: autocomplete_stop_area_referential_stop_areas_path(@stop_area_referential), initvalue: {id: f.object.parent_id, text: f.object.parent.try(:full_name)}}} + = f.input :area_type, as: :select, :input_html => {:disabled => !@stop_area.new_record?}, :collection => Chouette::AreaType.options, :include_blank => false .location_info @@ -19,9 +22,9 @@ = f.input :coordinates, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.coordinates")}, required: true = f.input :street_name - /= f.input :country_code, required: format_restriction_for_locales(@referential) == '.hub' = f.input :zip_code, :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.zip_code")} = f.input :city_name, required: format_restriction_for_locales(@referential) == '.hub', :input_html => {:title => t("formtastic.titles#{format_restriction_for_locales(@referential)}.stop_area.city_name")} + = f.input :country_code, as: :country, priority: ['FR', 'GB', 'DE', 'ES'], :include_blank => true .stop_areas.stop_area.general_info h3 = t("stop_areas.stop_area.general") diff --git a/app/views/stop_areas/autocomplete.rabl b/app/views/stop_areas/autocomplete.rabl new file mode 100644 index 000000000..3208289b5 --- /dev/null +++ b/app/views/stop_areas/autocomplete.rabl @@ -0,0 +1,24 @@ +collection @stop_areas + +node do |stop_area| + { + :id => stop_area.id, + :registration_number => stop_area.registration_number || "", + :short_registration_number => truncate(stop_area.registration_number, :length => 10) || "", + :name => stop_area.name || "", + :short_name => truncate(stop_area.name, :length => 30) || "", + :zip_code => stop_area.zip_code || "", + :city_name => stop_area.city_name || "", + :short_city_name => truncate(stop_area.city_name, :length => 15) || "", + :user_objectid => stop_area.user_objectid, + :longitude => stop_area.longitude, + :latitude => stop_area.latitude, + :area_type => stop_area.area_type, + :comment => stop_area.comment, + :text => stop_area.full_name + } +end + +node(:stop_area_path) { |stop_area| + stop_area_picture_url(stop_area) || "" +} diff --git a/app/views/stop_areas/show.html.slim b/app/views/stop_areas/show.html.slim index 0c23710b6..f9de34a98 100644 --- a/app/views/stop_areas/show.html.slim +++ b/app/views/stop_areas/show.html.slim @@ -16,6 +16,7 @@ .row .col-lg-6.col-md-6.col-sm-12.col-xs-12 - attributes = { t('id_reflex') => @stop_area.get_objectid.short_id, + @stop_area.human_attribute_name(:parent) => @stop_area.parent ? link_to(@stop_area.parent.name, stop_area_referential_stop_area_path(@stop_area_referential, @stop_area.parent)) : "-", @stop_area.human_attribute_name(:stop_area_type) => Chouette::AreaType.find(@stop_area.area_type).try(:label), @stop_area.human_attribute_name(:registration_number) => @stop_area.registration_number, } @@ -23,6 +24,7 @@ - attributes.merge!({ "Coordonnées" => geo_data(@stop_area, @stop_area_referential), @stop_area.human_attribute_name(:zip_code) => @stop_area.zip_code, @stop_area.human_attribute_name(:city_name) => @stop_area.city_name, + @stop_area.human_attribute_name(:country_code) => @stop_area.country_code.presence || '-', 'Etat' => (@stop_area.deleted_at ? 'Supprimé' : 'Actif'), @stop_area.human_attribute_name(:comment) => @stop_area.try(:comment), }) diff --git a/app/views/vehicle_journeys/show.rabl b/app/views/vehicle_journeys/show.rabl index a07f09309..01175a85d 100644 --- a/app/views/vehicle_journeys/show.rabl +++ b/app/views/vehicle_journeys/show.rabl @@ -1,6 +1,6 @@ object @vehicle_journey -[:objectid, :published_journey_name, :published_journey_identifier, :company_id].each do |attr| +[:objectid, :published_journey_name, :published_journey_identifier, :company_id, :comment].each do |attr| attributes attr, :unless => lambda { |m| m.send( attr).nil?} end diff --git a/config/locales/carrier_wave.yml b/config/locales/carrier_wave.yml new file mode 100644 index 000000000..53dd44e86 --- /dev/null +++ b/config/locales/carrier_wave.yml @@ -0,0 +1,4 @@ +fr: + errors: + messages: + extension_whitelist_error: "Le format %{extension} n'est pas supporté, le(s) format(s) supporté(s) sont : %{allowed_types}" diff --git a/config/locales/import_messages.fr.yml b/config/locales/import_messages.fr.yml index e29da05f9..bdb0d6c50 100644 --- a/config/locales/import_messages.fr.yml +++ b/config/locales/import_messages.fr.yml @@ -1,8 +1,8 @@ fr: import_messages: compliance_check_messages: - corrupt_zip_file: "Le fichier zip %{source_filename} est corrompu, et ne peut être lu" - inconsistent_zip_file: "Le fichier zip %{source_filename} contient des repertoires non prévus : %{spurious_dirs} qui seront ignorés" + corrupt_zip_file: "Le fichier zip est corrompu, et ne peut être lu" + inconsistent_zip_file: "Le fichier zip contient des repertoires non prévus : %{spurious_dirs} qui seront ignorés" referential_creation: "Le référentiel n'a pas pu être créé car un référentiel existe déjà sur les mêmes périodes et lignes" 1_netexstif_2: "Le fichier %{source_filename} ne respecte pas la syntaxe XML ou la XSD NeTEx : erreur '%{error_value}' rencontré" 1_netexstif_5: "%{source_filename}-Ligne %{source_line_number}-Colonne %{source_column_number} : l'objet %{source_label} d'identifiant %{source_objectid} a une date de mise à jour dans le futur" diff --git a/config/locales/stop_areas.en.yml b/config/locales/stop_areas.en.yml index 4d84d1191..69f7c7e99 100644 --- a/config/locales/stop_areas.en.yml +++ b/config/locales/stop_areas.en.yml @@ -4,6 +4,7 @@ en: search_no_results: "No stop area matching your query" errors: empty: Aucun stop_area_id + parent_area_type: can not be of type %{area_type} default_geometry_success: "%{count} modified stop areas" stop_area: no_position: "No Position" @@ -103,7 +104,7 @@ en: area_type: "Area type" nearest_topic_name: "Nearest point of interest" street_name: "Street name" - country_code: "INSEE code" + country_code: "Country" fare_code: "Fare code" mobility_restricted_suitability: "Mobility reduced passenger suitable" stairs_availability: "Escalator" diff --git a/config/locales/stop_areas.fr.yml b/config/locales/stop_areas.fr.yml index eda1e4e3d..f6664afa8 100644 --- a/config/locales/stop_areas.fr.yml +++ b/config/locales/stop_areas.fr.yml @@ -4,6 +4,7 @@ fr: search_no_results: "Aucun arrêt ne correspond à votre recherche" errors: empty: Aucun stop_area_id + parent_area_type: ne peut être de type %{area_type} default_geometry_success: "%{count} arrêts édités" stop_area: no_position: "Pas de position" @@ -103,7 +104,7 @@ fr: area_type: "Type d'arrêt" nearest_topic_name: "Point d'intérêt le plus proche" street_name: "Nom de la rue" - country_code: "Code INSEE" + country_code: "Pays" fare_code: "Zone tarifaire" mobility_restricted_suitability: "Accès pour voyageur à mobilité réduite" stairs_availability: "Escalator" diff --git a/config/routes.rb b/config/routes.rb index 22ff58724..bf796a385 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -93,7 +93,11 @@ ChouetteIhm::Application.routes.draw do resources :stop_area_referentials, :only => [:show] do post :sync, on: :member - resources :stop_areas, &deactivable + resources :stop_areas do + put :deactivate, on: :member + put :activate, on: :member + get :autocomplete, on: :collection + end end resources :line_referentials, :only => [:show, :edit, :update] do diff --git a/spec/factories/chouette_lines.rb b/spec/factories/chouette_lines.rb index 95f760174..c013b9d2b 100644 --- a/spec/factories/chouette_lines.rb +++ b/spec/factories/chouette_lines.rb @@ -8,7 +8,7 @@ FactoryGirl.define do association :network, :factory => :network association :company, :factory => :company - + before(:create) do |line| line.line_referential ||= LineReferential.find_by! name: "first" end @@ -35,7 +35,7 @@ FactoryGirl.define do after(:create) do |line| line.routes.each do |route| route.stop_points.each do |stop_point| - comm = create(:stop_area, :area_type => "lda") + comm = create(:stop_area, :area_type => "gdl") stop_point.stop_area.update_attributes(:parent_id => comm.id) end end diff --git a/spec/factories/chouette_stop_points.rb b/spec/factories/chouette_stop_points.rb index 14e08b1ac..97baae2fd 100644 --- a/spec/factories/chouette_stop_points.rb +++ b/spec/factories/chouette_stop_points.rb @@ -2,7 +2,7 @@ FactoryGirl.define do factory :stop_point, :class => Chouette::StopPoint do sequence(:objectid) { |n| "test:StopPoint:#{n}:loc" } - association :stop_area, :factory => :stop_area + association :stop_area, :factory => :stop_area, area_type: "zdep" end end diff --git a/spec/helpers/common_helper_spec.rb b/spec/helpers/common_helper_spec.rb deleted file mode 100644 index 1ffdc5bab..000000000 --- a/spec/helpers/common_helper_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -RSpec.describe CommonHelper do - - subject do - Object.new.extend( described_class ) - end - - describe 'string_keys_to_symbols' do - context 'nullpotency on symbol keys' do - it { expect(subject.string_keys_to_symbols({})).to eq({}) } - it do - expect(subject.string_keys_to_symbols( - a: 1, b: 2 - )).to eq(a: 1, b: 2) - end - end - - context 'changing string keys' do - it { expect(subject.string_keys_to_symbols('alpha' => 100)).to eq(alpha: 100) } - - it do - expect( subject.string_keys_to_symbols('a' => 10, b: 20) ) - .to eq(a: 10, b: 20) - end - it do - expect( subject.string_keys_to_symbols('a' => 10, 'b' => 20) ) - .to eq(a: 10, b: 20) - end - end - - context 'keys, not values, are changed' do - it do - expect(subject.string_keys_to_symbols(a: 'a', 'b' => 'b', 'c' => :c)) - .to eq(a: 'a', b: 'b', c: :c) - end - end - - - end -end diff --git a/spec/javascript/vehicle_journeys/actions_spec.js b/spec/javascript/vehicle_journeys/actions_spec.js index 3af19ebc3..2f1daf0da 100644 --- a/spec/javascript/vehicle_journeys/actions_spec.js +++ b/spec/javascript/vehicle_journeys/actions_spec.js @@ -174,15 +174,55 @@ describe('when clicking on validate button inside shifting modal', () => { }) }) describe('when clicking on validate button inside editing modal', () => { - it('should create an action to update a vehiclejourney', () => { - const data = {} - const selectedCompany = {} - const expectedAction = { - type: 'EDIT_VEHICLEJOURNEY', - data, - selectedCompany - } - expect(actions.editVehicleJourney(data, selectedCompany)).toEqual(expectedAction) + context("with invalid data", () => { + it('should not validate the data', () => { + const data = { + foo: { + validity: { valid: false } + }, + bar: { + validity: { valid: true } + } + } + + expect(actions.validateFields(data)).toBeFalsy + }) + }) + + context("with data not needing validation", () => { + it('should validate the data', () => { + const data = { + foo: {} + } + + expect(actions.validateFields(data)).toBeTruthy + }) + }) + context("with valid data", () => { + it('should validate the data', () => { + const data = { + foo: { + validity: { valid: true } + }, + bar: { + validity: { valid: true } + } + } + + expect(actions.validateFields(data)).toBeTruthy + }) + }) + context("once the data has been validated", () => { + it('should create an action to update a vehiclejourney', () => { + const data = {} + const selectedCompany = {} + const expectedAction = { + type: 'EDIT_VEHICLEJOURNEY', + data, + selectedCompany + } + expect(actions.editVehicleJourney(data, selectedCompany)).toEqual(expectedAction) + }) }) }) describe('when clicking on validate button inside duplicating modal', () => { diff --git a/spec/javascript/vehicle_journeys/reducers/modal_spec.js b/spec/javascript/vehicle_journeys/reducers/modal_spec.js index ea8a002d2..ee50f091b 100644 --- a/spec/javascript/vehicle_journeys/reducers/modal_spec.js +++ b/spec/javascript/vehicle_journeys/reducers/modal_spec.js @@ -241,13 +241,12 @@ describe('modal reducer', () => { }) it('should handle SELECT_CP_EDIT_MODAL', () => { - let newModalProps = {selectedCompany : {name: 'ALBATRANS'}} expect( modalReducer(state, { type: 'SELECT_CP_EDIT_MODAL', selectedItem: {name: 'ALBATRANS'} - }) - ).toEqual(Object.assign({}, state, {modalProps: newModalProps})) + }).modalProps.vehicleJourney.company + ).toEqual({name: 'ALBATRANS'}) }) it('should handle UNSELECT_CP_EDIT_MODAL', () => { @@ -255,7 +254,7 @@ describe('modal reducer', () => { expect( modalReducer(state, { type: 'UNSELECT_CP_EDIT_MODAL' - }) - ).toEqual(Object.assign({}, state, {modalProps: newModalProps})) + }).modalProps.vehicleJourney.company + ).toBe(undefined) }) }) diff --git a/spec/models/chouette/access_point_spec.rb b/spec/models/chouette/access_point_spec.rb index c734ecedf..2184c6ec2 100644 --- a/spec/models/chouette/access_point_spec.rb +++ b/spec/models/chouette/access_point_spec.rb @@ -136,7 +136,7 @@ describe Chouette::AccessPoint, :type => :model do describe "#generic_access_link_matrix" do it "should have 2 generic_access_links in matrix" do - stop_place = create :stop_area, :area_type => "zdlp" + stop_place = create :stop_area, :area_type => "gdl" commercial_stop_point = create :stop_area, :area_type => "lda" ,:parent => stop_place subject = create :access_point, :stop_area => stop_place expect(subject.generic_access_link_matrix.size).to eq(2) diff --git a/spec/models/chouette/stop_area_spec.rb b/spec/models/chouette/stop_area_spec.rb index bec8c0868..9db0f11a5 100644 --- a/spec/models/chouette/stop_area_spec.rb +++ b/spec/models/chouette/stop_area_spec.rb @@ -426,6 +426,42 @@ describe Chouette::StopArea, :type => :model do # end # end + describe "#parent" do + + let(:stop_area) { FactoryGirl.build :stop_area, parent: FactoryGirl.build(:stop_area) } + + it "is valid when parent has an 'higher' type" do + stop_area.area_type = 'zdep' + stop_area.parent.area_type = 'zdlp' + + stop_area.valid? + expect(stop_area.errors).to_not have_key(:parent_id) + end + + it "is valid when parent is undefined" do + stop_area.parent = nil + + stop_area.valid? + expect(stop_area.errors).to_not have_key(:parent_id) + end + + it "isn't valid when parent has the same type" do + stop_area.parent.area_type = stop_area.area_type = 'zdep' + + stop_area.valid? + expect(stop_area.errors).to have_key(:parent_id) + end + + it "isn't valid when parent has a lower type" do + stop_area.area_type = 'lda' + stop_area.parent.area_type = 'zdep' + + stop_area.valid? + expect(stop_area.errors).to have_key(:parent_id) + end + + end + describe '#waiting_time' do let(:stop_area) { FactoryGirl.build :stop_area } diff --git a/spec/models/compliance_control_spec.rb b/spec/models/compliance_control_spec.rb index 4267459ea..5cffba58d 100644 --- a/spec/models/compliance_control_spec.rb +++ b/spec/models/compliance_control_spec.rb @@ -1,5 +1,15 @@ RSpec.describe ComplianceControl, type: :model do + context 'dynamic attributes' do + let(:compliance_control1) { build_stubbed :compliance_control } + let(:compliance_control2) { build_stubbed :compliance_control, type: 'VehicleJouneyControl::TimeTable' } + + it 'should always return a array' do + expect(compliance_control1.class.dynamic_attributes).to be_kind_of Array + expect(compliance_control2.class.dynamic_attributes).to be_kind_of Array + end + end + context 'standard validation' do let(:compliance_control) { build_stubbed :compliance_control } diff --git a/spec/models/import_spec.rb b/spec/models/import_spec.rb index 3e4128865..ffb2360c2 100644 --- a/spec/models/import_spec.rb +++ b/spec/models/import_spec.rb @@ -10,8 +10,9 @@ RSpec.describe Import, type: :model do it { should validate_presence_of(:workbench) } it { should validate_presence_of(:creator) } - it { should allow_value('file.zip').for(:file).with_message(I18n.t('activerecord.errors.models.import.attributes.file.wrong_file_extension')) } - it { should_not allow_values('file.json', 'file.png', 'file.pdf').for(:file) } + include ActionDispatch::TestProcess + it { should allow_value(fixture_file_upload('OFFRE_TRANSDEV_2017030112251.zip')).for(:file) } + it { should_not allow_value(fixture_file_upload('users.json')).for(:file).with_message(I18n.t('errors.messages.extension_whitelist_error', extension: '"json"', allowed_types: "zip")) } let(:workbench_import) {netex_import.parent} let(:workbench_import_with_completed_steps) do diff --git a/spec/views/imports/show.html.slim_spec.rb b/spec/views/imports/show.html.slim_spec.rb index 1811d2acf..7a046d1a2 100644 --- a/spec/views/imports/show.html.slim_spec.rb +++ b/spec/views/imports/show.html.slim_spec.rb @@ -22,20 +22,17 @@ RSpec.describe '/imports/show', type: :view do messages.each do | message | # require 'htmlbeautifier' # b = HtmlBeautifier.beautify(rendered, indent: ' ') - expect(rendered).to have_selector('dl#import_messages dt.import_message') do + expect(rendered).to have_selector('.import_message-list dl dt.criticity') do with_text message.criticity end - expect(rendered).to have_selector('dl#import_messages dd.import_message') do + expect(rendered).to have_selector('.import_message-list dl dd') do with_text rendered_message( message ) end end end - def rendered_message message - Object.new.extend(CommonHelper).tap do |helper| - return I18n.t(message.message_key, helper.string_keys_to_symbols( message.message_attributes )) - end + return I18n.t message.message_key, message.message_attributes.symbolize_keys end end |
