diff options
32 files changed, 432 insertions, 136 deletions
| diff --git a/app/controllers/compliance_control_sets_controller.rb b/app/controllers/compliance_control_sets_controller.rb index f6002956b..cff67d5cb 100644 --- a/app/controllers/compliance_control_sets_controller.rb +++ b/app/controllers/compliance_control_sets_controller.rb @@ -17,8 +17,12 @@ class ComplianceControlSetsController < InheritedResources::Base    def show      show! do |format|        format.html { +        @q_controls_form        = @compliance_control_set.compliance_controls.ransack(params[:q])          @compliance_control_set = @compliance_control_set.decorate -        @compliance_controls_without_block = decorate_compliance_controls(@compliance_control_set.compliance_controls.where(compliance_control_block_id: nil)) +        @compliance_controls    = +          decorate_compliance_controls( @q_controls_form.result) +            .group_by(&:compliance_control_block) +        @indirect_compliance_controls = @compliance_controls.delete nil        }      end    end @@ -58,4 +62,4 @@ class ComplianceControlSetsController < InheritedResources::Base    def compliance_control_set_params      params.require(:compliance_control_set).permit(:name, :id)    end -end
\ No newline at end of file +end diff --git a/app/controllers/stop_areas_controller.rb b/app/controllers/stop_areas_controller.rb index 0c9f3067a..1d6f88068 100644 --- a/app/controllers/stop_areas_controller.rb +++ b/app/controllers/stop_areas_controller.rb @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*-  class StopAreasController < InheritedResources::Base    include ApplicationHelper diff --git a/app/helpers/compliance_control_blocks_helper.rb b/app/helpers/compliance_control_blocks_helper.rb index 09e22d6e9..311e6fb46 100644 --- a/app/helpers/compliance_control_blocks_helper.rb +++ b/app/helpers/compliance_control_blocks_helper.rb @@ -1,10 +1,10 @@  module ComplianceControlBlocksHelper    def transport_mode(transport_mode, transport_submode) -    if (transport_mode) && (transport_submode) != "" -      transportMode = "[" + t("enumerize.transport_mode.#{transport_mode}") + "]" + "[" + t("enumerize.transport_submode.#{transport_submode}") + "]" +    return "[Tous les modes de transport]" if transport_mode == "" +    if transport_submode == "" +       "[" + t("enumerize.transport_mode.#{transport_mode}") + "]"      else -      transportMode = "[Tous les modes de transport]" +      "[" + t("enumerize.transport_mode.#{transport_mode}") + "]" + "[" + t("enumerize.transport_submode.#{transport_submode}") + "]"      end -    transportMode    end -end
\ No newline at end of file +end diff --git a/app/helpers/compliance_controls_helper.rb b/app/helpers/compliance_controls_helper.rb new file mode 100644 index 000000000..ba0c538c9 --- /dev/null +++ b/app/helpers/compliance_controls_helper.rb @@ -0,0 +1,11 @@ +module ComplianceControlsHelper +  def subclass_selection_list +    ComplianceControl.subclass_patterns.map(&method(:make_subclass_selection_item)) +  end + + +  def make_subclass_selection_item(key_pattern) +    key, pattern = key_pattern +    [t("compliance_controls.filters.subclasses.#{key}"), "-#{pattern}-"] +  end +end  diff --git a/app/helpers/table_builder_helper.rb b/app/helpers/table_builder_helper.rb index 95f53a90d..37f01ce0d 100644 --- a/app/helpers/table_builder_helper.rb +++ b/app/helpers/table_builder_helper.rb @@ -83,17 +83,21 @@ module TableBuilderHelper      cls: '',      # A set of content, over the th line... -    overhead: [] +    overhead: [], + +    # Possibility to override the result of collection.model +    model: nil +    )      content_tag :table, -      thead(collection, columns, sortable, selectable, links.any?, overhead) + +      thead(collection, columns, sortable, selectable, links.any?, overhead, model || collection.model) +          tbody(collection, columns, selectable, links, overhead),        class: cls    end    private -  def thead(collection, columns, sortable, selectable, has_links, overhead) +  def thead(collection, columns, sortable, selectable, has_links, overhead, model )      content_tag :thead do        # Inserts overhead content if any specified        over_head = '' @@ -121,7 +125,7 @@ module TableBuilderHelper              hcont << content_tag(:th, build_column_header(                column,                sortable, -              collection.model, +              model,                params,                params[:sort],                params[:direction] @@ -137,7 +141,7 @@ module TableBuilderHelper                  hcont << content_tag(:th, build_column_header(                    column,                    sortable, -                  collection.model, +                  model,                    params,                    params[:sort],                    params[:direction] @@ -147,7 +151,7 @@ module TableBuilderHelper                  hcont << content_tag(:th, build_column_header(                    column,                    sortable, -                  collection.model, +                  model,                    params,                    params[:sort],                    params[:direction] @@ -160,7 +164,7 @@ module TableBuilderHelper                hcont << content_tag(:th, build_column_header(                  column,                  sortable, -                collection.model, +                model,                  params,                  params[:sort],                  params[:direction] @@ -299,14 +303,14 @@ module TableBuilderHelper    def build_column_header(      column,      table_is_sortable, -    collection_model, +    model,      params,      sort_on,      sort_direction    )      if !table_is_sortable || !column.sortable -      return column.header_label(collection_model) +      return column.header_label(model)      end      direction = @@ -331,7 +335,7 @@ module TableBuilderHelper        arrow_icons = content_tag :span, arrow_up + arrow_down, class: 'orderers'        ( -        column.header_label(collection_model) + +        column.header_label(model) +          arrow_icons        ).html_safe      end diff --git a/app/models/compliance_control.rb b/app/models/compliance_control.rb index 08efa7e9a..49fb6513f 100644 --- a/app/models/compliance_control.rb +++ b/app/models/compliance_control.rb @@ -1,29 +1,7 @@  class ComplianceControl < ActiveRecord::Base -  extend Enumerize -  belongs_to :compliance_control_set -  belongs_to :compliance_control_block - -  enumerize :criticity, in: %i(warning error), scope: true, default: :warning -  hstore_accessor :control_attributes, {} - -  validates :criticity, presence: true -  validates :name, presence: true -  validates :code, presence: true, uniqueness: { scope: :compliance_control_set } -  validates :origin_code, presence: true -  validates :compliance_control_set, presence: true - -  validate def coherent_control_set -    return true if compliance_control_block_id.nil? -    ids = [compliance_control_block.compliance_control_set_id, compliance_control_set_id] -    return true if ids.first == ids.last -    names = ids.map{|id| ComplianceControlSet.find(id).name} -    errors.add(:coherent_control_set, -               I18n.t('compliance_controls.errors.incoherent_control_sets', -                      indirect_set_name: names.first, -                      direct_set_name: names.last)) -  end    class << self +    def criticities; %i(warning error) end      def default_code; "" end      def dynamic_attributes        hstore_metadata_for_control_attributes.keys @@ -33,6 +11,17 @@ class ComplianceControl < ActiveRecord::Base        ComplianceControlPolicy      end +    def subclass_patterns +      {  +        generic: 'Generic', +        journey_pattern: 'JourneyPattern', +        line: 'Line', +        route: 'Route', +        routing_constraint_zone: 'RoutingConstraint', +        vehicle_journey: 'VehicleJourney' +      } +    end +      def inherited(child)        child.instance_eval do          def model_name @@ -43,12 +32,37 @@ class ComplianceControl < ActiveRecord::Base      end    end -  def initialize(attributes = {}) -    super -    self.name ||= I18n.t("activerecord.models.#{self.class.name.underscore}.one") -    self.code ||= self.class.default_code -    self.origin_code ||= self.class.default_code -  end +  extend Enumerize +  belongs_to :compliance_control_set +  belongs_to :compliance_control_block + +  enumerize :criticity, in: criticities, scope: true, default: :warning +  hstore_accessor :control_attributes, {} + +  validates :criticity, presence: true +  validates :name, presence: true +  validates :code, presence: true, uniqueness: { scope: :compliance_control_set } +  validates :origin_code, presence: true +  validates :compliance_control_set, presence: true + +  validate def coherent_control_set +  return true if compliance_control_block_id.nil? +  ids = [compliance_control_block.compliance_control_set_id, compliance_control_set_id] +  return true if ids.first == ids.last +  names = ids.map{|id| ComplianceControlSet.find(id).name} +  errors.add(:coherent_control_set, +             I18n.t('compliance_controls.errors.incoherent_control_sets', +                    indirect_set_name: names.first, +                    direct_set_name: names.last)) +end + + +def initialize(attributes = {}) +  super +  self.name ||= I18n.t("activerecord.models.#{self.class.name.underscore}.one") +  self.code ||= self.class.default_code +  self.origin_code ||= self.class.default_code +end  end diff --git a/app/models/import.rb b/app/models/import.rb index e0aae6ef1..20e7f2d8a 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -16,9 +16,10 @@ class Import < ActiveRecord::Base    extend Enumerize    enumerize :status, in: %i(new pending successful warning failed running aborted canceled), scope: true, default: :new +  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.imports.wrong_file_extension') +  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/views/compliance_control_sets/show.html.slim b/app/views/compliance_control_sets/show.html.slim index cf236feb8..294df6a53 100644 --- a/app/views/compliance_control_sets/show.html.slim +++ b/app/views/compliance_control_sets/show.html.slim @@ -24,54 +24,21 @@        .col-lg-6.col-md-6.col-sm-12.col-xs-12          = definition_list t('metadatas'),              ComplianceControlSet.human_attribute_name(:name) => @compliance_control_set.name +  - if params[:q].present? or @compliance_controls.any? +    .row +      .col-lg-12 +        = render '/compliance_controls/filters' +      .row        .col-lg-12          h2            = transport_mode("", "") -      .row -        .col-lg-12 -          .select_table -            = table_builder_2 @compliance_controls_without_block, -                    [ \ -                TableBuilderHelper::Column.new( \ -                  key: :code, \ -                  attribute: 'code' \ -                ), \ -                TableBuilderHelper::Column.new( \ -                  key: :name, \ -                  attribute: 'name', \ -                  link_to: lambda do |compliance_control| \ -                      compliance_control_set_compliance_control_path(@compliance_control_set, compliance_control) \ -                    end \ -                ), \ -                TableBuilderHelper::Column.new( \ -                  key: :criticity, \ -                  attribute: 'criticity' \ -                ), \ -                TableBuilderHelper::Column.new( \ -                  key: :comment, \ -                  attribute: 'comment' \ -                ), \ -              ], -              sortable: true, -              cls: 'table has-filter has-search' -    - @compliance_control_set.compliance_control_blocks.each do |block| -      .row -        .col-lg-12 -          h2 -            = transport_mode(block.transport_mode, block.transport_submode) -            .btn-group -              .btn.dropdown-toggle{ data-toggle="dropdown" } -                .span.fa.fa-cog -              ul.dropdown-menu -                li -                  = link_to t('compliance_control_sets.actions.edit'), edit_compliance_control_set_compliance_control_block_path(@compliance_control_set.id, block.id) -                  = link_to t('compliance_control_sets.actions.destroy'), compliance_control_set_compliance_control_block_path(@compliance_control_set.id, block.id), :method => :delete, :data => {:confirm =>  t('compliance_control_sets.actions.destroy_confirm')} +      - if @indirect_compliance_controls.try(:any?)          .row            .col-lg-12              .select_table -              = table_builder_2 ModelDecorator.decorate(block.compliance_controls, with: ComplianceControlDecorator), +              = table_builder_2 @indirect_compliance_controls,                        [ \                    TableBuilderHelper::Column.new( \                      key: :code, \ @@ -94,7 +61,52 @@                    ), \                  ],                  sortable: true, -                cls: 'table has-filter has-search' +                cls: 'table has-filter has-search', +                model: ComplianceControl + +    - @compliance_controls.each do |block, compliance_controls| + +      - if compliance_controls.try(:any?) +        .row +          .col-lg-12 +            h2 +              = transport_mode(block.transport_mode, block.transport_submode) +              .btn-group +                .btn.dropdown-toggle{ data-toggle="dropdown" } +                  .span.fa.fa-cog +                ul.dropdown-menu +                  li +                    = link_to t('compliance_control_sets.actions.edit'), edit_compliance_control_set_compliance_control_block_path(@compliance_control_set.id, block.id) +                    = link_to t('compliance_control_sets.actions.destroy'), compliance_control_set_compliance_control_block_path(@compliance_control_set.id, block.id), :method => :delete, :data => {:confirm =>  t('compliance_control_sets.actions.destroy_confirm')} +          .row +            .col-lg-12 +              .select_table +                = table_builder_2 compliance_controls, +                        [ \ +                    TableBuilderHelper::Column.new( \ +                      key: :code, \ +                      attribute: 'code' \ +                    ), \ +                    TableBuilderHelper::Column.new( \ +                      key: :name, \ +                      attribute: 'name', \ +                      link_to: lambda do |compliance_control| \ +                          compliance_control_set_compliance_control_path(@compliance_control_set, compliance_control) \ +                        end \ +                    ), \ +                    TableBuilderHelper::Column.new( \ +                      key: :criticity, \ +                      attribute: 'criticity' \ +                    ), \ +                    TableBuilderHelper::Column.new( \ +                      key: :comment, \ +                      attribute: 'comment' \ +                    ), \ +                  ], +                  sortable: true, +                  cls: 'table has-filter has-search', +                  model: ComplianceControl +      .select_toolbox        ul          li.st_action.with_text diff --git a/app/views/compliance_controls/_filters.html.slim b/app/views/compliance_controls/_filters.html.slim new file mode 100644 index 000000000..c729190a0 --- /dev/null +++ b/app/views/compliance_controls/_filters.html.slim @@ -0,0 +1,46 @@ += search_form_for @q_controls_form, +  url: compliance_control_set_path(@compliance_control_set), +  builder: SimpleForm::FormBuilder, +  class: 'form form-filter' do |f| + +  .ffg-row +    .input-group.search_bar +      = f.search_field :name_cont, +        class: 'form-control', +        placeholder: t('compliance_controls.filters.name') +      span.input-group-btn +        button.btn.btn-default type='submit' +          span.fa.fa-search + +  .ffg-row +    .form-group.togglable#compliance_control_block-filter +      = f.label t('activerecord.models.compliance_control_block.one'), required: false, class: 'control-label' +      = f.input :compliance_control_block_id_eq_any, +        collection: @compliance_control_set.compliance_control_blocks, +        as: :check_boxes, +        label: false, +        label_method: lambda {|w| ("<span>#{transport_mode(w.transport_mode, w.transport_submode)}</span>").html_safe}, +        required: false, +        wrapper_html: {class: 'checkbox_list'} +    .form-group.togglable#subclass-filter +      = f.label t('compliance_controls.filters.subclass'), required: false, class: 'control-label' +      = f.input :origin_code_cont_any, +        collection: subclass_selection_list, +        as: :check_boxes, +        label: false, +        label_method: lambda {|w| ("<span>#{w.first}</span>").html_safe}, +        required: false, +        wrapper_html: {class: 'checkbox_list'} +    .form-group.togglable#severity-filter +      = f.label t('compliance_controls.filters.criticity'), required: false, class: 'control-label' +      = f.input :criticity_eq_any, +        collection: ComplianceControl.criticities, +        as: :check_boxes, +        label: false, +        label_method: lambda {|w| ("<span>#{w}</span>").html_safe}, +        required: false, +        wrapper_html: {class: 'checkbox_list'} + +  .actions +    = link_to t('actions.erase'), @compliance_control_set, class: 'btn btn-link' +    = f.submit t('actions.filter'), class: 'btn btn-default', id: 'compliance_control_set_compliance_controls_filter_btn' diff --git a/app/views/layouts/navigation/_main_nav_left.html.slim b/app/views/layouts/navigation/_main_nav_left.html.slim index 062c9383c..837b9cb73 100644 --- a/app/views/layouts/navigation/_main_nav_left.html.slim +++ b/app/views/layouts/navigation/_main_nav_left.html.slim @@ -31,16 +31,17 @@          #miTwo.panel-collapse.collapse            .list-group -            = link_to workbench_path(current_offer_workbench), class: "list-group-item #{params[:controller] == 'workbenches' ? 'active' : ''}" do -              span Jeux de données -            = link_to workbench_imports_path(current_offer_workbench), class: "list-group-item #{(params[:controller] == 'imports') ? 'active' : ''}" do -              span Import -            = link_to calendars_path, class: 'list-group-item' do -              span Modèles de calendrier -            = link_to workbench_compliance_check_sets_path(current_offer_workbench), class: 'list-group-item' do -              span Rapport de contrôle -            = link_to compliance_control_sets_path, class: 'list-group-item' do -              span Jeux de contrôle +            - if current_user +              = link_to workbench_path(current_offer_workbench), class: "list-group-item #{params[:controller] == 'workbenches' ? 'active' : ''}" do +                span Jeux de données +              = link_to workbench_imports_path(current_offer_workbench), class: "list-group-item #{(params[:controller] == 'imports') ? 'active' : ''}" do +                span Import +              = link_to calendars_path, class: 'list-group-item' do +                span Modèles de calendrier +              = link_to workbench_compliance_check_sets_path(current_offer_workbench), class: 'list-group-item' do +                span Rapport de contrôle +              = link_to compliance_control_sets_path, class: 'list-group-item' do +                span Jeux de contrôle        .menu-item.panel          .panel-heading diff --git a/app/workers/compliance_control_set_copy_worker.rb b/app/workers/compliance_control_set_copy_worker.rb new file mode 100644 index 000000000..d18bb0c88 --- /dev/null +++ b/app/workers/compliance_control_set_copy_worker.rb @@ -0,0 +1,14 @@ +class ComplianceControlSetCopyWorker +  include Sidekiq::Worker + +  def perform(control_set_id, referential_id) +    check_set = ComplianceControlSetCopier.new.copy(control_set_id, referential_id) + +    begin +      Net::HTTP.get(URI("#{Rails.configuration.iev_url}/boiv_iev/referentials/validator/new?id=#{check_set.id}")) +    rescue Exception => e +      logger.error "IEV server error : #{e.message}" +      logger.error e.backtrace.inspect +    end +  end +end diff --git a/app/workers/workbench_import_worker.rb b/app/workers/workbench_import_worker.rb index 300fad9e2..de51efded 100644 --- a/app/workers/workbench_import_worker.rb +++ b/app/workers/workbench_import_worker.rb @@ -35,7 +35,7 @@ class WorkbenchImportWorker    end    def handle_corrupt_zip_file -    @workbench_import.messages.create(criticity: :error, message_key: 'corrupt_zip_file', message_attributes: {import_name: @workbench_import.name}) +    @workbench_import.messages.create(criticity: :error, message_key: 'corrupt_zip_file', message_attributes: {source_filename: @workbench_import.file.file.file})    end    def upload zip_service @@ -55,8 +55,8 @@ class WorkbenchImportWorker          criticity: :warning,          message_key: 'inconsistent_zip_file',          message_attributes: { -          'import_name' => @workbench_import.name, -          'spurious_dirs' => entry.spurious.join(', ') +          'source_filename' => @workbench_import.file.file.file, +          'spurious_dirs'   => entry.spurious.join(', ')          })       end    end diff --git a/config/environments/test.rb b/config/environments/test.rb index b3312be4a..8bf94f5da 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -62,6 +62,9 @@ Rails.application.configure do    # Reflex api url    config.reflex_api_url = "https://195.46.215.128/ws/reflex/V1/service=getData" +  # IEV url +  config.iev_url = ENV.fetch('IEV_URL', 'http://localhost:8080') +    config.rails_host = "http://www.example.com"    # file to data for demo    config.demo_data = "tmp/demo.zip" diff --git a/config/locales/compliance_controls.en.yml b/config/locales/compliance_controls.en.yml index 887bc2009..41971d9e9 100644 --- a/config/locales/compliance_controls.en.yml +++ b/config/locales/compliance_controls.en.yml @@ -2,6 +2,17 @@ en:    compliance_controls:      clone:        prefix: 'Copy of' +    filters: +      criticity: Severity +      name: "Search by a control's name or code" +      subclass: Object +      subclasses: +        generic: 'Generic' +        journey_pattern: 'JourneyPattern' +        line: 'Line' +        route: 'Route' +        routing_constraint_zone: 'RoutingConstraint' +        vehicle_journey: 'VehicleJourney'      min_max_values: "the minimum (%{min}) is not supposed to be greater than the maximum (%{max})"      errors:        incoherent_control_sets: "Impossible to assign a control to a set (id: %{direct_set_name}) differing from the one of its group (id: %{indirect_set_name})" @@ -179,4 +190,4 @@ en:          compliance_control_block: "Control Block"          minimum: "Minimum"          maximum: "Maximum" -        target: "Target"
\ No newline at end of file +        target: "Target" diff --git a/config/locales/compliance_controls.fr.yml b/config/locales/compliance_controls.fr.yml index 2feb201bf..3fa83a147 100644 --- a/config/locales/compliance_controls.fr.yml +++ b/config/locales/compliance_controls.fr.yml @@ -2,6 +2,17 @@ fr:    compliance_controls:      clone:        prefix: 'Copie de' +    filters: +      criticity: Criticité +      name: "Chercher le nom ou code d'un contrôl" +      subclass: Objet   +      subclasses: +        generic: 'Généric' +        journey_pattern: 'JourneyPattern' +        line: 'Ligne' +        route: 'Itinéraire' +        routing_constraint_zone: 'ITL' +        vehicle_journey: 'Course'      min_max_values: "la valeur de minimum (%{min}) ne doit pas être superieur à la valuer du maximum (%{max})"      errors:        incoherent_control_sets: "Le contrôle ne peut pas être associé à un jeu de contrôle (id: %{direct_set_name}) différent de celui de son groupe (id: %{indirect_set_name})" @@ -119,7 +130,7 @@ fr:    activerecord:      models:        compliance_control: -        one: "controle" +        one: "contrôle"          other: "contrôles"        route_control/zdl_stop_area:          one: "Deux arrêts d’une même ZDL ne peuvent pas se succéder dans un itinéraire" @@ -130,7 +141,7 @@ fr:        route_control/duplicates:          one: "Détection de double définition d'itinéraire"        route_control/opposite_route_terminus: -        one: "Vérification des terminus de l'itinéraire inverse" +       one: "Vérification des terminus de l'itinéraire inverse"        route_control/minimum_length:          one: "Un itinéraire doit contenir au moins 2 arrêts"        route_control/omnibus_journey_pattern: @@ -179,4 +190,4 @@ fr:          compliance_control_block: "Groupe de contrôle"          minimum: "Minimum"          maximum: "Maximum" -        target: "Cible"
\ No newline at end of file +        target: "Cible" diff --git a/config/locales/import_messages.en.yml b/config/locales/import_messages.en.yml index 2048b9794..bf6b45020 100644 --- a/config/locales/import_messages.en.yml +++ b/config/locales/import_messages.en.yml @@ -1,8 +1,8 @@  en:    import_messages:      compliance_check_messages: -      corrupt_zip_file: "The zip file of WorkbenchImport %{import_name} is corrupted and cannot be read" -      inconsistent_zip_file: "The zip file of WorkbenchImport %{import_name} contains the following spurious directories %{spurious_dirs}, which are ignored" +      corrupt_zip_file: "The zip file %{source_filename} is corrupted and cannot be read" +      inconsistent_zip_file: "The zip file %{source_filename} contains unexpected directories: %{spurious_dirs}, which are ignored"        referential_creation: "Le référentiel n'a pas pu être créé car un référentiel existe déjà sur les même 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/import_messages.fr.yml b/config/locales/import_messages.fr.yml index 9f0af1faa..7d3bbf23b 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 du WorkbenchImport %{import_name} est corrompu, et ne peut être lu"  -      inconsistent_zip_file: "Le fichier zip du WorkbenchImport %{import_name} contient les repertoirs illegeaux %{spurious_dirs} qui seront ignorés" +      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"        referential_creation: "Le référentiel n'a pas pu être créé car un référentiel existe déjà sur les même 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/imports.en.yml b/config/locales/imports.en.yml index f3bcad9e9..10434dd19 100644 --- a/config/locales/imports.en.yml +++ b/config/locales/imports.en.yml @@ -55,8 +55,10 @@ en:          other: "imports"      errors:        models: -        imports: -          wrong_file_extension: "The imported file must be a zip file" +        import: +          attributes: +            file: +              wrong_file_extension: "The imported file must be a zip file"      attributes:        import:          resources: "File to import" diff --git a/config/locales/imports.fr.yml b/config/locales/imports.fr.yml index 6e74fa33c..099488a6b 100644 --- a/config/locales/imports.fr.yml +++ b/config/locales/imports.fr.yml @@ -55,8 +55,10 @@ fr:          other: "imports"      errors:        models: -        imports: -          wrong_file_extension: "Le fichier importé doit être au format zip" +        import: +          attributes: +            file: +              wrong_file_extension: "Le fichier importé doit être au format zip"      attributes:        import:          resources: "Fichier à importer" diff --git a/config/routes.rb b/config/routes.rb index 214b12584..30ba51358 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -74,6 +74,7 @@ ChouetteIhm::Application.routes.draw do    resources :api_keys, :only => [:edit, :update, :new, :create, :destroy]    resources :compliance_control_sets do +    get :simple, on: :member      get :clone, on: :member      get :select_compliance_control_set      resources :compliance_controls, except: :index do diff --git a/db/schema.rb b/db/schema.rb index a64a426de..dd9461c78 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -284,6 +284,22 @@ ActiveRecord::Schema.define(version: 20171016074044) do    add_index "connection_links", ["objectid"], name: "connection_links_objectid_key", unique: true, using: :btree +  create_table "delayed_jobs", id: :bigserial, force: :cascade do |t| +    t.integer  "priority",               default: 0 +    t.integer  "attempts",               default: 0 +    t.text     "handler" +    t.text     "last_error" +    t.datetime "run_at" +    t.datetime "locked_at" +    t.datetime "failed_at" +    t.string   "locked_by",  limit: 255 +    t.string   "queue",      limit: 255 +    t.datetime "created_at" +    t.datetime "updated_at" +  end + +  add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree +    create_table "exports", id: :bigserial, force: :cascade do |t|      t.integer  "referential_id",  limit: 8      t.string   "status" @@ -405,12 +421,12 @@ ActiveRecord::Schema.define(version: 20171016074044) do      t.datetime "started_at"      t.datetime "ended_at"      t.string   "token_download" -    t.string   "type" +    t.string   "type",                  limit: 255      t.integer  "parent_id",             limit: 8      t.string   "parent_type" +    t.integer  "current_step",                      default: 0 +    t.integer  "total_steps",                       default: 0      t.datetime "notified_parent_at" -    t.integer  "current_step",                    default: 0 -    t.integer  "total_steps",                     default: 0      t.string   "creator"    end @@ -562,6 +578,11 @@ ActiveRecord::Schema.define(version: 20171016074044) do    add_index "networks", ["objectid"], name: "networks_objectid_key", unique: true, using: :btree    add_index "networks", ["registration_number"], name: "networks_registration_number_key", using: :btree +  create_table "object_id_factories", id: :bigserial, force: :cascade do |t| +    t.datetime "created_at", null: false +    t.datetime "updated_at", null: false +  end +    create_table "organisations", id: :bigserial, force: :cascade do |t|      t.string   "name"      t.datetime "created_at" @@ -750,7 +771,7 @@ ActiveRecord::Schema.define(version: 20171016074044) do    create_table "stop_areas", id: :bigserial, force: :cascade do |t|      t.integer  "parent_id",                       limit: 8 -    t.string   "objectid",                                                            null: false +    t.string   "objectid",                                                              null: false      t.integer  "object_version",                  limit: 8      t.string   "creator_id"      t.string   "name" @@ -759,8 +780,8 @@ ActiveRecord::Schema.define(version: 20171016074044) do      t.string   "registration_number"      t.string   "nearest_topic_name"      t.integer  "fare_code" -    t.decimal  "longitude",                                 precision: 19, scale: 16 -    t.decimal  "latitude",                                  precision: 19, scale: 16 +    t.decimal  "longitude",                                   precision: 19, scale: 16 +    t.decimal  "latitude",                                    precision: 19, scale: 16      t.string   "long_lat_type"      t.string   "country_code"      t.string   "street_name" @@ -778,7 +799,7 @@ ActiveRecord::Schema.define(version: 20171016074044) do      t.datetime "deleted_at"      t.datetime "created_at"      t.datetime "updated_at" -    t.string   "stif_type" +    t.string   "stif_type",                       limit: 255    end    add_index "stop_areas", ["name"], name: "index_stop_areas_on_name", using: :btree @@ -849,18 +870,18 @@ ActiveRecord::Schema.define(version: 20171016074044) do    add_index "time_table_periods", ["time_table_id"], name: "index_time_table_periods_on_time_table_id", using: :btree    create_table "time_tables", id: :bigserial, force: :cascade do |t| -    t.string   "objectid",                              null: false -    t.integer  "object_version",  limit: 8, default: 1 +    t.string   "objectid",                                null: false +    t.integer  "object_version",  limit: 8,   default: 1      t.string   "creator_id"      t.string   "version"      t.string   "comment" -    t.integer  "int_day_types",             default: 0 +    t.integer  "int_day_types",               default: 0      t.date     "start_date"      t.date     "end_date"      t.integer  "calendar_id",     limit: 8      t.datetime "created_at"      t.datetime "updated_at" -    t.string   "color" +    t.string   "color",           limit: 255      t.integer  "created_from_id"      t.string   "checksum"      t.text     "checksum_source" @@ -1007,9 +1028,13 @@ ActiveRecord::Schema.define(version: 20171016074044) do    add_foreign_key "compliance_controls", "compliance_control_blocks"    add_foreign_key "compliance_controls", "compliance_control_sets"    add_foreign_key "group_of_lines_lines", "group_of_lines", name: "groupofline_group_fkey", on_delete: :cascade +  add_foreign_key "journey_frequencies", "timebands", name: "journey_frequencies_timeband_id_fk", on_delete: :nullify    add_foreign_key "journey_frequencies", "timebands", on_delete: :nullify +  add_foreign_key "journey_frequencies", "vehicle_journeys", name: "journey_frequencies_vehicle_journey_id_fk", on_delete: :nullify    add_foreign_key "journey_frequencies", "vehicle_journeys", on_delete: :nullify +  add_foreign_key "journey_pattern_sections", "journey_patterns", name: "journey_pattern_sections_journey_pattern_id_fk", on_delete: :cascade    add_foreign_key "journey_pattern_sections", "journey_patterns", on_delete: :cascade +  add_foreign_key "journey_pattern_sections", "route_sections", name: "journey_pattern_sections_route_section_id_fk", on_delete: :cascade    add_foreign_key "journey_pattern_sections", "route_sections", on_delete: :cascade    add_foreign_key "journey_patterns", "routes", name: "jp_route_fkey", on_delete: :cascade    add_foreign_key "journey_patterns", "stop_points", column: "arrival_stop_point_id", name: "arrival_point_fkey", on_delete: :nullify diff --git a/lib/compliance_control_set_copier.rb b/lib/compliance_control_set_copier.rb index 20518ee0e..58d40cdbf 100644 --- a/lib/compliance_control_set_copier.rb +++ b/lib/compliance_control_set_copier.rb @@ -11,6 +11,8 @@ class ComplianceControlSetCopier      @referential_id = referential_id      check_organisation_coherence!      copy_set + +    cck_set    end diff --git a/spec/controllers/api/v1/imports_controller_spec.rb b/spec/controllers/api/v1/imports_controller_spec.rb index 266b25486..8077dd052 100644 --- a/spec/controllers/api/v1/imports_controller_spec.rb +++ b/spec/controllers/api/v1/imports_controller_spec.rb @@ -29,7 +29,7 @@ RSpec.describe Api::V1::ImportsController, type: :controller do        it 'should be successful' do          expect { -          post :create, workbench_id: workbench.id, workbench_import: {file: file, creator: 'test'}, format: :json +          post :create, workbench_id: workbench.id, workbench_import: {name: "test", file: file, creator: 'test'}, format: :json          }.to change{WorkbenchImport.count}.by(1)          expect(response).to be_success        end diff --git a/spec/features/compliance_control_sets_spec.rb b/spec/features/compliance_control_sets_spec.rb new file mode 100644 index 000000000..500d4ce6f --- /dev/null +++ b/spec/features/compliance_control_sets_spec.rb @@ -0,0 +1,82 @@ +RSpec.describe "ComplianceControlSets", type: :feature do + +  login_user + +  # We setup a control_set with two blocks and one direct control (meaning that it is not attached to a block) +  # Then we add one control to the first block and two controls to the second block +  let( :control_set ){ create :compliance_control_set, organisation: organisation } +  let( :controls ){ control_set.compliance_controls } + +  let(:blox){ +    2.times.map{ | _ | create :compliance_control_block, compliance_control_set: control_set } +  } + +  before do +    blox.first.update transport_mode: 'bus', transport_submode: 'bus' +    blox.second.update transport_mode: 'train', transport_submode: 'train' + +    make_control +    make_control blox.first, severity: :error +    make_control blox.second, times: 2 +  end + +  describe 'show' do +    before do +      visit compliance_control_set_path( control_set ) +    end + +    it 'we can see the controls inside their blocks' do +      controls.each do | control | +        expect( page ).to have_content(control.code) +      end +    end + +    it 'we can apply a severity filter' do +      controls.take(2).each do | control | +        control.update criticity: 'error' +      end +      check('error') +      click_on('Filtrer') +      controls.each do | control | +        if control.criticity == 'error' +          expect( page ).to have_content(control.code) +        else +          expect( page ).not_to have_content(control.code) +        end +      end +    end + +    it 'we can apply a subclass filter' do +      controls.first.update(origin_code: 'x-Route-y') +      controls.second.update(origin_code: 'x-Line-y') + +      within('#subclass-filter') do +        check('Itinéraire') +        check('Ligne') +      end +      click_on('Filtrer') +      controls.each do | control | +        if control.origin_code[/-Generic-/] +          expect( page ).not_to have_content(control.code) +        else +          expect( page ).to have_content(control.code) +        end +      end +    end + +  end + +  def make_control ccblock=nil, times: 1, severity: :warning +    times.times do +      make_one_control ccblock, severity +    end +  end + +  def make_one_control ccblock, severity +      create( :generic_attribute_control_min_max, +        code: random_string, +        compliance_control_block: ccblock, +        compliance_control_set: control_set) +  end + +end diff --git a/spec/features/connection_links_spec.rb b/spec/features/connection_links_spec.rb index 7272242fe..2f6283dcd 100644 --- a/spec/features/connection_links_spec.rb +++ b/spec/features/connection_links_spec.rb @@ -1,4 +1,4 @@ -RSpec.describe "ConnectionLinks", :type => :feature do +RSpec.describe "ConnectionLinks", type: :feature do    login_user    let!(:connection_links) { Array.new(2) { create(:connection_link) } } diff --git a/spec/lib/compliance_control_set_copier_spec.rb b/spec/lib/compliance_control_set_copier_spec.rb index a9e576cf7..0f15d86d0 100644 --- a/spec/lib/compliance_control_set_copier_spec.rb +++ b/spec/lib/compliance_control_set_copier_spec.rb @@ -99,6 +99,10 @@ RSpec.describe ComplianceControlSetCopier do            expect( actual ).to eq( expected )          end + +        it 'returns the newly-created ComplianceCheckSet' do +          expect(subject.copy(cc_set.id, ref.id)).to eq(cck_set) +        end        end      end diff --git a/spec/models/compliance_control_class_level_defaults/compliance_control_subclass_pattern_spec.rb b/spec/models/compliance_control_class_level_defaults/compliance_control_subclass_pattern_spec.rb new file mode 100644 index 000000000..868eca984 --- /dev/null +++ b/spec/models/compliance_control_class_level_defaults/compliance_control_subclass_pattern_spec.rb @@ -0,0 +1,17 @@ +RSpec.describe ComplianceControl do +  let( :subject ){ described_class.subclass_patterns } + +  context 'subclass_patterns' do +    it 'are correctly defined' do +      expect_it.to eq( +        generic: 'Generic', +        journey_pattern: 'JourneyPattern', +        line: 'Line', +        route: 'Route', +        routing_constraint_zone: 'RoutingConstraint', +        vehicle_journey: 'VehicleJourney' +      ) +    end +  end + +end diff --git a/spec/models/compliance_control_spec.rb b/spec/models/compliance_control_spec.rb index db73dab21..4267459ea 100644 --- a/spec/models/compliance_control_spec.rb +++ b/spec/models/compliance_control_spec.rb @@ -4,10 +4,6 @@ RSpec.describe ComplianceControl, type: :model do      let(:compliance_control) { build_stubbed :compliance_control } -    it 'should have a valid factory' do -      expect(compliance_control).to be_valid -    end -      it { should belong_to :compliance_control_set }      it { should belong_to :compliance_control_block } diff --git a/spec/models/import_spec.rb b/spec/models/import_spec.rb index c06d05dab..7be05908a 100644 --- a/spec/models/import_spec.rb +++ b/spec/models/import_spec.rb @@ -10,7 +10,7 @@ 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.imports.wrong_file_extension')) } +  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) }    let(:workbench_import) { build_stubbed(:workbench_import) } diff --git a/spec/workers/compliance_control_set_copy_worker_spec.rb b/spec/workers/compliance_control_set_copy_worker_spec.rb new file mode 100644 index 000000000..0ff721e75 --- /dev/null +++ b/spec/workers/compliance_control_set_copy_worker_spec.rb @@ -0,0 +1,35 @@ +RSpec.describe ComplianceControlSetCopyWorker do +  let(:control_set_id) { 55 } +  let(:referential_id) { 99 } +  let(:check_set) { double(ComplianceCheckSet, id: 888) } +  let(:stub_validation_request) do +    stub_request( +      :get, +      "#{Rails.configuration.iev_url}/boiv_iev/referentials/validator/new?id=#{check_set.id}" +    ) +  end + +  before(:each) do +    allow_any_instance_of( +      ComplianceControlSetCopier +    ).to receive(:copy).and_return(check_set) + +    stub_validation_request +  end + +  it "calls ComplianceControlSetCopier" do +    expect_any_instance_of( +      ComplianceControlSetCopier +    ).to receive(:copy) +      .with(control_set_id, referential_id) +      .and_return(check_set) + +    ComplianceControlSetCopyWorker.new.perform(control_set_id, referential_id) +  end + +  it "calls the Java API to launch validation" do +    ComplianceControlSetCopyWorker.new.perform(control_set_id, referential_id) + +    expect(stub_validation_request).to have_been_requested +  end +end diff --git a/spec/workers/workbench_import/workbench_import_with_corrupt_zip_spec.rb b/spec/workers/workbench_import/workbench_import_with_corrupt_zip_spec.rb index 5e34b208a..47626f5a1 100644 --- a/spec/workers/workbench_import/workbench_import_with_corrupt_zip_spec.rb +++ b/spec/workers/workbench_import/workbench_import_with_corrupt_zip_spec.rb @@ -1,6 +1,5 @@  RSpec.describe WorkbenchImportWorker do -    shared_examples_for 'corrupt zipfile data' do      subject { described_class.new }      let( :workbench_import ){ create :workbench_import, status: :pending } @@ -23,7 +22,7 @@ RSpec.describe WorkbenchImportWorker do        message = workbench_import.messages.last        expect( message.criticity ).to eq('error')        expect( message.message_key ).to eq('corrupt_zip_file') -      expect( message.message_attributes ).to eq( 'import_name' => workbench_import.name ) +      expect( message.message_attributes ).to eq( 'source_filename' => workbench_import.file.file.file )      end      it 'does not change current step' do diff --git a/spec/workers/workbench_import/workbench_import_worker_spec.rb b/spec/workers/workbench_import/workbench_import_worker_spec.rb index deaa1e3a5..47ca2b4ff 100644 --- a/spec/workers/workbench_import/workbench_import_worker_spec.rb +++ b/spec/workers/workbench_import/workbench_import_worker_spec.rb @@ -115,8 +115,8 @@ RSpec.describe WorkbenchImportWorker, type: [:worker, :request] do      let( :spurious ){ [spurious1, spurious2] }      let( :messages ){ double('messages') }      let( :message_attributes ){{criticity: :warning, message_key: 'inconsistent_zip_file'}} -    let( :message1_attributes ){ message_attributes.merge(message_attributes: {'import_name' => import.name, 'spurious_dirs' => spurious1.join(', ')}) } -    let( :message2_attributes ){ message_attributes.merge(message_attributes: {'import_name' => import.name, 'spurious_dirs' => spurious2.join(', ')}) } +    let( :message1_attributes ){ message_attributes.merge(message_attributes: {'source_filename' => import.file.file.file, 'spurious_dirs' => spurious1.join(', ')}) } +    let( :message2_attributes ){ message_attributes.merge(message_attributes: {'source_filename' => import.file.file.file, 'spurious_dirs' => spurious2.join(', ')}) }      before do        allow(import).to receive(:messages).and_return(messages) | 
