diff options
36 files changed, 446 insertions, 251 deletions
| diff --git a/app/controllers/concerns/iev_interfaces.rb b/app/controllers/concerns/iev_interfaces.rb new file mode 100644 index 000000000..590482c7f --- /dev/null +++ b/app/controllers/concerns/iev_interfaces.rb @@ -0,0 +1,65 @@ +module IevInterfaces +  extend ActiveSupport::Concern + +  included do +    before_action only: [:index] { set_date_time_params("started_at", DateTime) } +    before_action :ransack_status_params, only: [:index] +    respond_to :html +    belongs_to :workbench +  end + +  def show +    show! do +      instance_variable_set "@#{collection_name.singularize}", resource.decorate(context: { +        workbench: @workbench +      }) +    end +  end + +  def index +    index! do |format| +      format.html { +        if collection.out_of_bounds? +          redirect_to params.merge(:page => 1) +        end +        collection = decorate_collection(collection) +      } +    end +  end + +  protected +  def collection +    scope = parent.send(collection_name).where(type: "#{resource_class.parent.name}::Workbench") + +    scope = self.ransack_period_range(scope: scope, error_message:  t("#{collection_name}.filters.error_period_filter"), query: :where_started_at_in) + +    @q = scope.search(params[:q]) + +    unless instance_variable_get "@#{collection_name}" +      coll = if sort_column && sort_direction +        @q.result(distinct: true).order(sort_column + ' ' + sort_direction).paginate(page: params[:page], per_page: 10) +      else +        @q.result(distinct: true).order(:name).paginate(page: params[:page], per_page: 10) +      end +      instance_variable_set "@#{collection_name}", decorate_collection(coll) +    end +    instance_variable_get "@#{collection_name}" +  end + +  private +  def ransack_status_params +    if params[:q] +      return params[:q].delete(:status_eq_any) if params[:q][:status_eq_any].empty? || ( (resource_class.status.values & params[:q][:status_eq_any]).length >= 4 ) +      params[:q][:status_eq_any].push("new", "running") if params[:q][:status_eq_any].include?("pending") +      params[:q][:status_eq_any].push("aborted", "canceled") if params[:q][:status_eq_any].include?("failed") +    end +  end + +  def sort_column +    parent.imports.column_names.include?(params[:sort]) ? params[:sort] : 'created_at' +  end + +  def sort_direction +    %w[asc desc].include?(params[:direction]) ?  params[:direction] : 'desc' +  end +end diff --git a/app/controllers/exports_controller.rb b/app/controllers/exports_controller.rb index 095720aa0..1b947299f 100644 --- a/app/controllers/exports_controller.rb +++ b/app/controllers/exports_controller.rb @@ -1,74 +1,41 @@ -require 'will_paginate/array' -require 'open-uri' -  class ExportsController < ChouetteController -  include ReferentialSupport -  # defaults :resource_class => Export -  # -  # respond_to :html, :only => [:show, :index, :destroy, :exported_file] -  # respond_to :js, :only => [:index] -  # belongs_to :referential -  # -  # def index -  #   begin -  #     index! -  #   rescue Ievkit::Error, Faraday::Error => error -  #     logger.error("Iev failure : #{error.message}") -  #     flash[:error] = t(error.locale_for_error) -  #     redirect_to referential_path(@referential) -  #   end -  # end -  # -  # def show -  #   begin -  #     show! -  #   rescue Ievkit::Error, Faraday::Error => error -  #     logger.error("Iev failure : #{error.message}") -  #     flash[:error] = t(error.locale_for_error) -  #     redirect_to referential_path(@referential) -  #   end -  # end -  # -  # def destroy -  #   begin -  #     destroy! -  #   rescue Ievkit::Error, Faraday::Error => error -  #     logger.error("Iev failure : #{error.message}") -  #     flash[:error] = t(error.locale_for_error) -  #     redirect_to referential_path(@referential) -  #   end -  # end -  # -  # def exported_file -  #   # WARNING : files under 10kb in size get treated as StringIO by OpenUri -  #   # http://stackoverflow.com/questions/10496874/why-does-openuri-treat-files-under-10kb-in-size-as-stringio -  #   OpenURI::Buffer.send :remove_const, 'StringMax' if OpenURI::Buffer.const_defined?('StringMax') -  #   OpenURI::Buffer.const_set 'StringMax', 0 -  #   begin -  #     send_file open(resource.file_path), { :type => "application/#{resource.filename_extension}", :disposition => "attachment", :filename => resource.filename } -  #   rescue Ievkit::Error, Faraday::Error => error -  #     logger.error("Iev failure : #{error.message}") -  #     flash[:error] = t(error.locale_for_error) -  #     redirect_to referential_path(@referential) -  #   end -  # end -  # -  # protected -  # -  # def export_service -  #   ExportService.new(@referential) -  # end -  # -  # def resource -  #   @export ||= export_service.find( params[:id] ) -  #   @line_items = @export.report.line_items -  #   if @line_items.size > 500 -  #     @line_items = @line_items.paginate(page: params[:page], per_page: 20) -  #   end -  #   @export -  # end -  # -  # def collection -  #   @exports ||= export_service.all.sort_by{ |export| export.created_at }.reverse.paginate(:page => params[:page]) -  # end +  include PolicyChecker +  include RansackDateFilter +  include IevInterfaces +  skip_before_action :authenticate_user!, only: [:upload] +  defaults resource_class: Export::Base, collection_name: 'exports', instance_name: 'export' + +  def upload +    if params[:token] == resource.token_download +      send_file resource.file.path +    else +      user_not_authorized +    end +  end + +  private + +  def build_resource +    @export ||= Export::Workbench.new(*resource_params) do |export| +      export.workbench = parent +      export.creator   = current_user.name +    end +  end + +  def export_params +    params.require(:export).permit( +      :name, +      :type, +      :referential_id +    ) +  end + +  def decorate_collection(exports) +    ExportDecorator.decorate( +      exports, +      context: { +        workbench: @workbench +      } +    ) +  end  end diff --git a/app/controllers/imports_controller.rb b/app/controllers/imports_controller.rb index 3ebbeb665..f95b6acf1 100644 --- a/app/controllers/imports_controller.rb +++ b/app/controllers/imports_controller.rb @@ -1,31 +1,9 @@  class ImportsController < ChouetteController    include PolicyChecker    include RansackDateFilter -  before_action only: [:index] { set_date_time_params("started_at", DateTime) } +  include IevInterfaces    skip_before_action :authenticate_user!, only: [:download]    defaults resource_class: Import::Base, collection_name: 'imports', instance_name: 'import' -  before_action :ransack_status_params, only: [:index] -  respond_to :html -  belongs_to :workbench - -  def show -    show! do -      @import = @import.decorate(context: { -        workbench: @workbench -      }) -    end -  end - -  def index -    index! do |format| -      format.html { -        if collection.out_of_bounds? -          redirect_to params.merge(:page => 1) -        end -        @imports = decorate_imports(@imports) -      } -    end -  end    def download      if params[:token] == resource.token_download @@ -35,31 +13,8 @@ class ImportsController < ChouetteController      end    end -  protected -  def collection -    scope = parent.imports.where(type: "Import::Workbench") - -    scope = self.ransack_period_range(scope: scope, error_message:  t('imports.filters.error_period_filter'), query: :where_started_at_in) - -    @q = scope.search(params[:q]) - -    if sort_column && sort_direction -      @imports ||= @q.result(distinct: true).order(sort_column + ' ' + sort_direction).paginate(page: params[:page], per_page: 10) -    else -      @imports ||= @q.result(distinct: true).order(:name).paginate(page: params[:page], per_page: 10) -    end -  end -    private -  def ransack_status_params -    if params[:q] -      return params[:q].delete(:status_eq_any) if params[:q][:status_eq_any].empty? || ( (Import::Base.status.values & params[:q][:status_eq_any]).length >= 4 ) -      params[:q][:status_eq_any].push("new", "running") if params[:q][:status_eq_any].include?("pending") -      params[:q][:status_eq_any].push("aborted", "canceled") if params[:q][:status_eq_any].include?("failed") -    end -  end -    def build_resource      @import ||= Import::Workbench.new(*resource_params) do |import|        import.workbench = parent @@ -76,14 +31,7 @@ class ImportsController < ChouetteController      )    end -  def sort_column -    parent.imports.column_names.include?(params[:sort]) ? params[:sort] : 'created_at' -  end -  def sort_direction -    %w[asc desc].include?(params[:direction]) ?  params[:direction] : 'desc' -  end - -  def decorate_imports(imports) +  def decorate_collection(imports)      ImportDecorator.decorate(        imports,        context: { diff --git a/app/decorators/export_decorator.rb b/app/decorators/export_decorator.rb new file mode 100644 index 000000000..26682f383 --- /dev/null +++ b/app/decorators/export_decorator.rb @@ -0,0 +1,21 @@ +class ExportDecorator < AF83::Decorator +  decorates Export::Base + +  set_scope { context[:workbench] } + +  define_instance_method :export_status_css_class do +    cls ='' +    cls = 'overheaded-success' if object.status == 'successful' +    cls = 'overheaded-warning' if object.status == 'warning' +    cls = 'overheaded-danger' if %w[failed aborted canceled].include? object.status +    cls +  end + +  create_action_link do |l| +    l.content t('exports.actions.new') +  end + +  with_instance_decorator do |instance_decorator| +    instance_decorator.show_action_link +  end +end diff --git a/app/decorators/import/base_decorator.rb b/app/decorators/import_decorator.rb index 8c10479c6..a20dfbc42 100644 --- a/app/decorators/import/base_decorator.rb +++ b/app/decorators/import_decorator.rb @@ -1,4 +1,4 @@ -class Import::BaseDecorator < AF83::Decorator +class ImportDecorator < AF83::Decorator    decorates Import::Base    set_scope { context[:workbench] } diff --git a/app/helpers/table_builder_helper/column.rb b/app/helpers/table_builder_helper/column.rb index ff6f2f36f..907707670 100644 --- a/app/helpers/table_builder_helper/column.rb +++ b/app/helpers/table_builder_helper/column.rb @@ -28,7 +28,9 @@ module TableBuilderHelper        return @name if @name.present?        # Transform `Chouette::Line` into "line" -      model_key = model.to_s.demodulize.underscore +      model_key = model.to_s.underscore +      model_key.gsub! 'chouette/', '' +      model_key.gsub! '/', '.'        I18n.t("activerecord.attributes.#{model_key}.#{@key}")      end diff --git a/app/models/concerns/iev_interfaces/task.rb b/app/models/concerns/iev_interfaces/task.rb index b142850fb..c84c588b6 100644 --- a/app/models/concerns/iev_interfaces/task.rb +++ b/app/models/concerns/iev_interfaces/task.rb @@ -7,7 +7,6 @@ module IevInterfaces::Task      belongs_to :referential      mount_uploader :file, ImportUploader -    validates :file, presence: true      has_many :children, foreign_key: :parent_id, class_name: self.name, dependent: :destroy @@ -17,8 +16,8 @@ module IevInterfaces::Task      validates :name, presence: true      validates_presence_of :workbench, :creator -    has_many :messages, class_name: messages_class_name, dependent: :destroy, foreign_key: :import_id -    has_many :resources, class_name: resources_class_name, dependent: :destroy, foreign_key: :import_id +    has_many :messages, class_name: messages_class_name, dependent: :destroy, foreign_key: "#{messages_class_name.split('::').first.downcase}_id" +    has_many :resources, class_name: resources_class_name, dependent: :destroy, foreign_key: "#{resources_class_name.split('::').first.downcase}_id"      scope :where_started_at_in, ->(period_range) do        where('started_at BETWEEN :begin AND :end', begin: period_range.begin, end: period_range.end) diff --git a/app/models/export/base.rb b/app/models/export/base.rb index d809055db..844c66d82 100644 --- a/app/models/export/base.rb +++ b/app/models/export/base.rb @@ -12,7 +12,7 @@ class Export::Base < ActiveRecord::Base    include IevInterfaces::Task    def self.model_name -    ActiveModel::Name.new Export::Base, Export::Base, "Export::Base" +    ActiveModel::Name.new Export::Base, Export::Base, "Export"    end    private diff --git a/app/models/export/workbench.rb b/app/models/export/workbench.rb new file mode 100644 index 000000000..a4b14cf55 --- /dev/null +++ b/app/models/export/workbench.rb @@ -0,0 +1,7 @@ +class Export::Workbench < Export::Base +  after_commit :launch_worker, :on => :create + +  def launch_worker +    # WorkbenchImportWorker.perform_async(id) +  end +end diff --git a/app/models/import/base.rb b/app/models/import/base.rb index e2ae129be..73d06d968 100644 --- a/app/models/import/base.rb +++ b/app/models/import/base.rb @@ -1,5 +1,6 @@  class Import::Base < ActiveRecord::Base    self.table_name = "imports" +  validates :file, presence: true    def self.messages_class_name      "Import::Message" @@ -12,7 +13,7 @@ class Import::Base < ActiveRecord::Base    include IevInterfaces::Task    def self.model_name -    ActiveModel::Name.new Import::Base, Import::Base, "Import::Base" +    ActiveModel::Name.new Import::Base, Import::Base, "Import"    end    def child_change diff --git a/app/models/workbench.rb b/app/models/workbench.rb index 44415f102..b5f4673bb 100644 --- a/app/models/workbench.rb +++ b/app/models/workbench.rb @@ -14,6 +14,7 @@ class Workbench < ActiveRecord::Base    has_many :group_of_lines, through: :line_referential    has_many :stop_areas, through: :stop_area_referential    has_many :imports, class_name: Import::Base +  has_many :exports, class_name: Export::Base    has_many :workbench_imports, class_name: Import::Workbench    has_many :compliance_check_sets    has_many :compliance_control_sets diff --git a/app/policies/export_policy.rb b/app/policies/export_policy.rb new file mode 100644 index 000000000..e667f3207 --- /dev/null +++ b/app/policies/export_policy.rb @@ -0,0 +1,15 @@ +class ExportPolicy < ApplicationPolicy +  class Scope < Scope +    def resolve +      scope +    end +  end + +  def create? +    user.has_permission?('exports.create') +  end + +  def update? +    user.has_permission?('exports.update') +  end +end diff --git a/app/policies/import/base_policy.rb b/app/policies/import_policy.rb index 62345e452..512bfc8ac 100644 --- a/app/policies/import/base_policy.rb +++ b/app/policies/import_policy.rb @@ -1,4 +1,4 @@ -class Import::BasePolicy < ApplicationPolicy +class ImportPolicy < ApplicationPolicy    class Scope < Scope      def resolve        scope diff --git a/app/views/exports/_export.html.slim b/app/views/exports/_export.html.slim deleted file mode 100644 index f1f7e9753..000000000 --- a/app/views/exports/_export.html.slim +++ /dev/null @@ -1,20 +0,0 @@ -#index_item.panel.panel-default.export -  .panel-heading -    .panel-title.clearfix -      span.pull-right -        = link_to referential_export_path(@referential, export.id), :method => :delete, :data => {:confirm =>  t('exports.actions.destroy_confirm')}, class: 'btn btn-danger btn-sm' do -          span.fa.fa-trash-o -       -      h5 -      	= link_to( referential_export_path(@referential, export.id), :class => "preview", :title => "#{Export.model_name.human.capitalize} #{export.name}") do -      	  = job_status_title(export) - -  .panel-body -    p -      = link_to( font_awesome_classic_tag("fa-file-#{export.filename_extension}-o") + t("exports.show.exported_file"), exported_file_referential_export_path(@referential, export.id) ) if export.file_path - -  .panel-footer -    = export_attributes_tag(export) -    .history -      = l export.created_at, :format => "%d/%m/%Y %H:%M" -      = " | #{export.user_name}"
\ No newline at end of file diff --git a/app/views/exports/_exports.html.slim b/app/views/exports/_exports.html.slim deleted file mode 100644 index 7a0461def..000000000 --- a/app/views/exports/_exports.html.slim +++ /dev/null @@ -1,9 +0,0 @@ -.page_info -  span.search = t("will_paginate.page_entries_info.search") -  = page_entries_info @exports - -.exports.paginated_content -  = paginated_content @exports, "exports/export" - -.pagination -  = will_paginate @exports, :container => false, renderer: RemoteBootstrapPaginationLinkRenderer
\ No newline at end of file diff --git a/app/views/exports/_form.html.slim b/app/views/exports/_form.html.slim new file mode 100644 index 000000000..c4748b5f9 --- /dev/null +++ b/app/views/exports/_form.html.slim @@ -0,0 +1,7 @@ += simple_form_for export, as: :export, url: workbench_exports_path(workbench), html: {class: 'form-horizontal', id: 'wb_export_form'}, wrapper: :horizontal_form do |form| + +  .row +    .col-lg-12 +      = form.input :name + +  = form.button :submit, t('actions.submit'), class: 'btn btn-default formSubmitr', form: 'wb_export_form' diff --git a/app/views/exports/index.html.slim b/app/views/exports/index.html.slim index bbcb2a5a7..f97b07231 100644 --- a/app/views/exports/index.html.slim +++ b/app/views/exports/index.html.slim @@ -1,10 +1,44 @@ -= title_tag t('.title') +- breadcrumb :exports, @workbench -.warning = t('.warning') +.page_content +  .container-fluid +    - if params[:q].present? or collection.any? +      .row +        .col-lg-12 +          = render 'shared/iev_interfaces/filters' -#exports = render 'exports' +    - if collection.any? +      .row +        .col-lg-12 +          = table_builder_2 collection, +            [ \ +              TableBuilderHelper::Column.new( \ +                key: :status, \ +                attribute: Proc.new { |n| export_status(n.status) }, \ +              ), \ +              TableBuilderHelper::Column.new( \ +                key: :started_at, \ +                attribute: Proc.new { |n| l(n.started_at, format: :long) if n.started_at }, \ +              ), \ +              TableBuilderHelper::Column.new( \ +                key: :name, \ +                attribute: 'name', \ +                link_to: lambda do |export| \ +                  workbench_export_path(@workbench, export) \ +                end \ +              ), \ +              TableBuilderHelper::Column.new( \ +                key: :creator, \ +                attribute: 'creator' \ +              ) \ +            ], +            cls: 'table has-search' -- content_for :sidebar do -  ul.actions -    li -      = link_to t('exports.actions.new'), new_referential_export_task_path(@referential), class: 'add'
\ No newline at end of file +          = new_pagination collection, 'pull-right' + +    - unless collection.any? +      .row.mt-xs +        .col-lg-12 +          = replacement_msg t('exports.search_no_results') + += javascript_pack_tag 'date_filters' diff --git a/app/views/exports/index.js.slim b/app/views/exports/index.js.slim deleted file mode 100644 index b9a413b1b..000000000 --- a/app/views/exports/index.js.slim +++ /dev/null @@ -1 +0,0 @@ -| $('#exports').html("#{escape_javascript(render('exports'))}");
\ No newline at end of file diff --git a/app/views/exports/new.html.slim b/app/views/exports/new.html.slim new file mode 100644 index 000000000..f62386caf --- /dev/null +++ b/app/views/exports/new.html.slim @@ -0,0 +1,7 @@ +- breadcrumb :exports, @workbench + +.page_content +  .container-fluid +    .row +      .col-lg-8.col-lg-offset-2.col-md-8.col-md-offset-2.col-sm-10.col-sm-offset-1 +        = render 'form', export: @export, workbench: @workbench diff --git a/app/views/exports/show.html.slim b/app/views/exports/show.html.slim index 1631e0e7e..dab50ced8 100644 --- a/app/views/exports/show.html.slim +++ b/app/views/exports/show.html.slim @@ -1,26 +1,60 @@ -.title.row -  .col-md-8 -    = title_tag job_status_title(@export) +- breadcrumb :export, @workbench, @export -  .col-md-4 -    = export_attributes_tag(@export) +- page_header_content_for @export -- if @export.report.failure_code? -  .alert.alert-danger -    = t("iev.failure.#{@export.report.failure_code}") +.page_content +  .container-fluid +    .row +      .col-lg-6.col-md-6.col-sm-12.col-xs-12 +        = definition_list t('metadatas'), { 'Récupération des données' => '-', "Nom de l'archive" => @export.try(:file_identifier)} -.progress_bars -  = progress_bar_tag(@export) +    .row +      .col-lg-12 +        .error_messages +          = render 'shared/iev_interfaces/messages', messages: @export.messages -.export_show -  .links -    = link_to( font_awesome_classic_tag("fa-file-#{@export.filename_extension}-o") + t("exports.show.exported_file"), exported_file_referential_export_path(@referential, @export.id) ) if @export.file_path -   -  = render partial: "shared/ie_report.html", locals: { job: @export, line_items: @line_items } - -- content_for :sidebar do -  ul.actions -    li -      = link_to t('exports.actions.destroy'), referential_export_path(@referential, @export.id), :method => :delete, :data => {:confirm => t('exports.actions.destroy_confirm')}, class: 'remove' -   -  = history_tag(@export)
\ No newline at end of file +    - if @export.children.any? +      .row +        .col-lg-12 +          = table_builder_2 @export.children, +            [ \ +              TableBuilderHelper::Column.new( \ +                name: 'Nom du jeu de données', \ +                attribute: 'name', \ +                sortable: false, \ +                link_to: lambda do |export| \ +                  referential_path(export.referential) if export.referential.present? \ +                end \ +              ), \ +              TableBuilderHelper::Column.new( \ +                key: :status, \ +                attribute: Proc.new { |n| export_status(n.status) }, \ +                sortable: false, \ +                link_to: lambda do |export| \ +                  workbench_export_export_resources_path(export.workbench_id, export) \ +                end \ +              ), \ +              TableBuilderHelper::Column.new( \ +                name: 'Contrôle STIF', \ +                attribute: '', \ +                sortable: false, \ +              ), \ +              TableBuilderHelper::Column.new( \ +                name: 'Contrôle organisation', \ +                attribute: '', \ +                sortable: false, \ +              ) \ +            ], +            cls: 'table', +            overhead: [ \ +              {}, \ +              { \ +                title: "#{@export.children_succeedeed} jeu de données validé sur #{@export.children.count} présent(s) dans l'archive", \ +                width: 1, \ +                cls: "#{@export.export_status_css_class} full-border" \ +              }, { \ +                title: 'Bilan des jeux de contrôles d\'export <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/imports/_import_messages.html.slim b/app/views/imports/_import_messages.html.slim deleted file mode 100644 index af10b23e5..000000000 --- a/app/views/imports/_import_messages.html.slim +++ /dev/null @@ -1,8 +0,0 @@ -- if import_messages.any? -  ul.list-unstyled.import_message-list -    - import_messages.each do | import_message | -      li -        span(class="#{bootstrap_class_for_message_criticity import_message.criticity}") -          = t( ['import_messages', -            'compliance_check_messages', -            import_message.message_key].join('.'), import_message.message_attributes.symbolize_keys) diff --git a/app/views/imports/index.html.slim b/app/views/imports/index.html.slim index 4fc077bd6..3dff4d80e 100644 --- a/app/views/imports/index.html.slim +++ b/app/views/imports/index.html.slim @@ -2,15 +2,15 @@  .page_content    .container-fluid -    - if params[:q].present? or @imports.any? +    - if params[:q].present? or collection.any?        .row          .col-lg-12 -          = render 'filters' +          = render 'shared/iev_interfaces/filters'      - if @imports.any?        .row          .col-lg-12 -          = table_builder_2 @imports, +          = table_builder_2 collection,              [ \                TableBuilderHelper::Column.new( \                  key: :status, \ @@ -34,9 +34,9 @@              ],              cls: 'table has-search' -          = new_pagination @imports, 'pull-right' +          = new_pagination collection, 'pull-right' -    - unless @imports.any? +    - unless collection.any?        .row.mt-xs          .col-lg-12            = replacement_msg t('imports.search_no_results') diff --git a/app/views/imports/show.html.slim b/app/views/imports/show.html.slim index 7a9d02077..48a4f334c 100644 --- a/app/views/imports/show.html.slim +++ b/app/views/imports/show.html.slim @@ -11,7 +11,7 @@      .row        .col-lg-12          .error_messages -          = render 'import_messages', import_messages: @import.messages +          = render 'shared/iev_interfaces/messages', messages: @import.messages      - if @import.children.any?        .row diff --git a/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim b/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim index cb0698cf8..02614dcab 100644 --- a/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim +++ b/app/views/layouts/navigation/_main_nav_left_content_stif.html.slim @@ -29,6 +29,8 @@              span Jeux de données            = link_to workbench_imports_path(current_workbench), class: "list-group-item #{(params[:controller] == 'imports') ? 'active' : ''}" do              span Import +          = link_to workbench_exports_path(current_workbench), class: "list-group-item #{(params[:controller] == 'exports') ? 'active' : ''}" do +            span Export            = link_to workgroup_calendars_path(current_workbench.workgroup), class: 'list-group-item' do              span Modèles de calendrier            = link_to workbench_compliance_check_sets_path(current_workbench), class: 'list-group-item' do diff --git a/app/views/layouts/navigation/_page_header.html.slim b/app/views/layouts/navigation/_page_header.html.slim index e407e53da..49f56544b 100644 --- a/app/views/layouts/navigation/_page_header.html.slim +++ b/app/views/layouts/navigation/_page_header.html.slim @@ -1,6 +1,5 @@  - action_links = resource.action_links(params[:action]) rescue nil  - action_links ||= decorated_collection.action_links(params[:action]) rescue nil -  .page_header    .container-fluid      .row @@ -13,7 +12,7 @@              h1 = yield :page_header_title            - else              - if defined?(resource_class) -              h1 = t("#{resource_class.model_name.name.underscore.pluralize}.#{params[:action]}.title") +              h1 = t("#{resource_class.model_name.name.underscore.gsub('/', '.').pluralize}.#{params[:action]}.title")        .col-lg-3.col-md-4.col-sm-5.col-xs-5.text-right          .page-action diff --git a/app/views/imports/_filters.html.slim b/app/views/shared/iev_interfaces/_filters.html.slim index 25c0d10d9..9b114c38d 100644 --- a/app/views/imports/_filters.html.slim +++ b/app/views/shared/iev_interfaces/_filters.html.slim @@ -8,11 +8,11 @@    .ffg-row      .form-group.togglable class=filter_item_class(params[:q], :status_eq_any) -      = f.label Import.human_attribute_name(:status), required: false, class: 'control-label' +      = f.label Import::Base.human_attribute_name(:status), required: false, class: 'control-label'        = f.input :status_eq_any, collection: %w(pending successful warning failed), as: :check_boxes, label: false, label_method: lambda{|l| ("<span>" + import_status(l) + "</span>").html_safe}, required: false, wrapper_html: { class: "checkbox_list"}      .form-group.togglable class=filter_item_class(params[:q], :started_at) -      = f.label Import.human_attribute_name(:started_at), required: false, class: 'control-label' +      = f.label Import::Base.human_attribute_name(:started_at), required: false, class: 'control-label'        .filter_menu          = f.simple_fields_for :started_at do |p|            = p.input :start_date, as: :date, label: false, wrapper_html: { class: 'date smart_date filter_menu-item' }, default: @begin_range, include_blank: @begin_range ? false : true diff --git a/app/views/shared/iev_interfaces/_messages.html.slim b/app/views/shared/iev_interfaces/_messages.html.slim new file mode 100644 index 000000000..bb6eea9f9 --- /dev/null +++ b/app/views/shared/iev_interfaces/_messages.html.slim @@ -0,0 +1,7 @@ +- if messages.any? +  ul.list-unstyled.import_message-list +    - messages.each do | message | +      li +        div(class="#{bootstrap_class_for_message_criticity message.criticity}") +          = t( [message.class.name.underscore.gsub('/', '_').pluralize, +            message.message_key].join('.'), message.message_attributes.symbolize_keys) diff --git a/config/breadcrumbs.rb b/config/breadcrumbs.rb index adcbb0b6f..87d6f5846 100644 --- a/config/breadcrumbs.rb +++ b/config/breadcrumbs.rb @@ -111,11 +111,21 @@ crumb :imports do |workbench|    parent :workbench, workbench  end +crumb :exports do |workbench| +  link I18n.t('exports.index.title'), workbench_exports_path(workbench) +  parent :workbench, workbench +end +  crumb :import do |workbench, import|    link breadcrumb_name(import), workbench_import_path(workbench, import)    parent :imports, workbench  end +crumb :export do |workbench, export| +  link breadcrumb_name(export), workbench_export_path(workbench, export) +  parent :exports, workbench +end +  crumb :import_resources do |import, import_resources|    link I18n.t('import_resources.index.title'), workbench_import_import_resources_path(import.workbench, import.parent)    parent :import, import.workbench, import.parent diff --git a/config/locales/exports.en.yml b/config/locales/exports.en.yml index 2a47fba54..73d49b1f8 100644 --- a/config/locales/exports.en.yml +++ b/config/locales/exports.en.yml @@ -1,25 +1,32 @@  en:    exports: +    search_no_results: "No export matching your query" +    filters: +      referential: "Select data space..." +      name_or_creator_cont: "Select an export or creator name..." +      error_period_filter: "End date must be greater or equal than begin date"      actions:        new: "New export" +      create: "New export" +      show: "Export report" +      download: "Download original file"        destroy: "Destroy"        destroy_confirm: "Are you sure you want destroy this export?" -    new: -      title: "New export" -      all: "All" -      flash: "Export task on queue, refresh page to see progression"      index:        title: "Exports"        warning: "" +    new: +      title: "Generate a new export" +    create: +      title: "Generate a new export"      show: +      title: "Export %{name}"        report: "Report" -      exported_file: "Exported file" -    statuses: -      started: "Started"       -      scheduled: "Processing ..." -      terminated: "Completed" -      canceled: "Canceled" -      aborted: "Failed"     +      exported_file: "Original file" +      compliance_check: "Validation report" +      compliance_check_of: "Validation of export: " +      export_of_validation: "Export of the validation" +    compliance_check_task: "Validate Report"      severities:        info: "Information"        uncheck: "Unchecked" @@ -27,7 +34,7 @@ en:        warning: "Warning"        error: "Error"        fatal: "Fatal" -  activemodel: +  activerecord:      models:        export:          zero:  "export" @@ -37,6 +44,10 @@ en:          zero:  "export"          one:   "Neptune export"          other: "exports" +      csv_export: +        zero:  "export" +        one:   "CSV export" +        other: "exports"        gtfs_export:          zero:  "export"          one:   "GTFS export" @@ -44,4 +55,34 @@ en:        netex_export:          zero:  "export"          one:   "NeTEx export" -        other: "exports"
\ No newline at end of file +        other: "exports" +    errors: +      models: +        export: +          base: +            attributes: +              file: +                wrong_file_extension: "The exported file must be a zip file" +    attributes: +      attrs: &attrs +        resources: "File to export" +        created_at: "Created on" +        started_at: "Started at" +        name: "Name" +        status: "Status" +        creator: "Creator" +        references_type: "Data to be exported" +        no_save: "No save" +        object_id_prefix: "Neptune Id prefix" +        max_distance_for_commercial: "Max distance for commercial stop" +        max_distance_for_connection_link: "Max distance for connection link" +        ignore_last_word: "ignore last word" +        ignore_end_chars: "ignore last chars" +      export: +        <<: *attrs +        base: +          <<: *attrs +  flash: +    exports: +      create: +        notice: "The export is in progress. Please wait and refresh the page in a few moments." diff --git a/config/locales/exports.fr.yml b/config/locales/exports.fr.yml index 2d7cc0259..c5b8a5e3b 100644 --- a/config/locales/exports.fr.yml +++ b/config/locales/exports.fr.yml @@ -1,33 +1,43 @@  fr: -  exports: +  exports: &exports +    search_no_results: "Aucun export ne correspond à votre recherche" +    filters: +      referential: "Sélectionnez un jeu de données..." +      name_or_creator_cont: "Indiquez un nom d'export ou d'opérateur..." +      error_period_filter: "La date de fin doit être supérieure ou égale à la date de début"      actions:        new: "Nouvel export" +      create: "Nouvel export" +      show: "Rapport d'export" +      download: "Téléch. fichier source"        destroy: "Supprimer cet export"        destroy_confirm: "Etes vous sûr de supprimer cet export ?" -    new: -      title: "Nouvel export" -      all: "Toutes" -      flash: "La demande d'export est mise en file d'attente, veuillez rafraichir régulièrement la page pour en suivre la progression"      index:        title: "Exports"        warning: "" +    new: +      title: "Générer un export" +    create: +      title: "Générer un export"      show: +      title: "Export %{name}"        report: "Rapport" -      exported_file: "Fichier exporté" -    statuses: -      started: "En file d'attente..." -      scheduled: "En cours..." -      terminated: "Achevé" -      canceled: "Annulé" -      aborted: "Echoué" +      exported_file: "Fichier source" +      compliance_check: "Test de conformité" +      compliance_check_of: "Validation de l'export : " +      export_of_validation: "L'export de la validation" +    compliance_check_task: "Validation"      severities:        info: "Information" -      uncheck: "Non disponible" +      uncheck: "Non testé"        ok: "Ok"        warning: "Alerte"        error: "Erreur"        fatal: "Fatal" -  activemodel: +  export: +    base: +      <<: *exports +  activerecord:      models:        export:          zero:  "export" @@ -35,7 +45,11 @@ fr:          other: "exports"        neptune_export:          zero:  "export" -        one:   "export neptune" +        one:   "export Neptune" +        other: "exports" +      csv_export: +        zero:  "export" +        one:   "export CSV"          other: "exports"        gtfs_export:          zero:  "export" @@ -45,3 +59,33 @@ fr:          zero:  "export"          one:   "export NeTEx"          other: "exports" +    errors: +      models: +        export: +          base: +            attributes: +              file: +                wrong_file_extension: "Le fichier exporté doit être au format zip" +    attributes: +      attrs: &attrs +        resources: "Fichier à exporter" +        created_at: "Créé le" +        started_at: Démarrage +        name: "Nom de l'export" +        status: "Etat" +        creator: "Opérateur" +        no_save: "Pas de sauvegarde" +        references_type: "Données à exporter" +        object_id_prefix: "Préfixe d'identifiants" +        max_distance_for_commercial: "Distance max pour créer les zones" +        max_distance_for_connection_link: "Distance max pour créer les correspondances" +        ignore_last_word: "ignorer le dernier mot" +        ignore_end_chars: "ignorer les n derniers caractères" +      export: +        <<: *attrs +        base: +          <<: *attrs +  flash: +    exports: +      create: +        notice: "L'export est en cours, veuillez patienter. Actualiser votre page si vous voulez voir l'avancement de votre traitement." diff --git a/config/locales/import_messages.en.yml b/config/locales/import_messages.en.yml index aad4fb772..bc06c46f0 100644 --- a/config/locales/import_messages.en.yml +++ b/config/locales/import_messages.en.yml @@ -1,5 +1,5 @@  en: -  import_messages: +  import_message:      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êmes périodes et lignes" @@ -50,4 +50,4 @@ en:      2_netexstif_servicejourneypattern_2: "%{source_filename}-Ligne %{source_line_number}-Colonne %{source_column_number} : l'objet ServiceJourneyPattern d'identifiant %{source_objectid} doit contenir au moins 2 StopPointInJourneyPattern"      2_netexstif_servicejourneypattern_3_1: "%{source_filename}-Ligne %{source_line_number}-Colonne %{source_column_number} : l'objet ServiceJourneyPattern d'identifiant %{source_objectid} n'a pas de valeur pour l'attribut ServiceJourneyPatternType"      2_netexstif_servicejourneypattern_3_2: "%{source_filename}-Ligne %{source_line_number}-Colonne %{source_column_number} : l'objet ServiceJourneyPattern d'identifiant %{source_objectid} a une valeur interdite %{error_value} pour l'attribut ServiceJourneyPatternType différente de 'passenger'" -    2_netexstif_servicejourneypattern_4: "%{source_filename}-Ligne %{source_line_number}-Colonne %{source_column_number}, objet ServiceJourneyPattern d'identifiant %{source_objectid} : les attributs 'order' des StopPointInJourneyPattern ne sont pas croissants."
\ No newline at end of file +    2_netexstif_servicejourneypattern_4: "%{source_filename}-Ligne %{source_line_number}-Colonne %{source_column_number}, objet ServiceJourneyPattern d'identifiant %{source_objectid} : les attributs 'order' des StopPointInJourneyPattern ne sont pas croissants." diff --git a/config/locales/import_resources.en.yml b/config/locales/import_resources.en.yml index 5f0f3213e..3e737f9bc 100644 --- a/config/locales/import_resources.en.yml +++ b/config/locales/import_resources.en.yml @@ -1,5 +1,5 @@  en: -  import_resources: +  import_resources: &resources      index:        title: "NeTEx conformity"        table_state: "%{lines_imported} line(s) imported on %{lines_in_zipfile} presents in zipfile" diff --git a/config/locales/imports.en.yml b/config/locales/imports.en.yml index b0644acd3..d0db87fb1 100644 --- a/config/locales/imports.en.yml +++ b/config/locales/imports.en.yml @@ -59,11 +59,12 @@ en:      errors:        models:          import: -          attributes: -            file: -              wrong_file_extension: "The imported file must be a zip file" +          base: +            attributes: +              file: +                wrong_file_extension: "The imported file must be a zip file"      attributes: -      import: +      attrs: &attrs          resources: "File to import"          created_at: "Created on"          started_at: "Started at" @@ -77,6 +78,10 @@ en:          max_distance_for_connection_link: "Max distance for connection link"          ignore_last_word: "ignore last word"          ignore_end_chars: "ignore last chars" +      import: +        <<: *attrs +        base: +          <<: *attrs    flash:      imports:        create: diff --git a/config/locales/imports.fr.yml b/config/locales/imports.fr.yml index 2380eac45..40272889a 100644 --- a/config/locales/imports.fr.yml +++ b/config/locales/imports.fr.yml @@ -1,5 +1,5 @@  fr: -  imports: +  imports: &imports      search_no_results: "Aucun import ne correspond à votre recherche"      filters:        referential: "Sélectionnez un jeu de données..." @@ -34,6 +34,9 @@ fr:        warning: "Alerte"        error: "Erreur"        fatal: "Fatal" +  import: +    base: +      <<: *imports    activerecord:      models:        import: @@ -59,11 +62,12 @@ fr:      errors:        models:          import: -          attributes: -            file: -              wrong_file_extension: "Le fichier importé doit être au format zip" +          base: +            attributes: +              file: +                wrong_file_extension: "Le fichier importé doit être au format zip"      attributes: -      import: +      attrs: &attrs          resources: "Fichier à importer"          created_at: "Créé le"          started_at: Démarrage @@ -77,6 +81,12 @@ fr:          max_distance_for_connection_link: "Distance max pour créer les correspondances"          ignore_last_word: "ignorer le dernier mot"          ignore_end_chars: "ignorer les n derniers caractères" + +      import: +        <<: *attrs +        base: +          <<: *attrs +    flash:      imports:        create: diff --git a/config/routes.rb b/config/routes.rb index b6934936b..6313b5678 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,6 +11,12 @@ ChouetteIhm::Application.routes.draw do          resources :import_messages, only: [:index]        end      end +    resources :exports do +      post :upload, on: :member +      resources :export_resources, only: [:index] do +        resources :export_messages, only: [:index] +      end +    end      resources :compliance_check_sets, only: [:index, :show] do        get :executed, on: :member        resources :compliance_checks, only: [:show] diff --git a/lib/stif/permission_translator.rb b/lib/stif/permission_translator.rb index 9e0feb9b8..09a7c610c 100644 --- a/lib/stif/permission_translator.rb +++ b/lib/stif/permission_translator.rb @@ -21,6 +21,7 @@ module Stif          calendars          footnotes          imports +        exports          merges          journey_patterns          referentials | 
