importo 3.0.13 → 3.0.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1d51a79f3ee31f31f1936df77da88c1908d1c0f3cf937113a15e59a4b85b203
4
- data.tar.gz: 815570655ace71f03b39e2bf98ef37e841e62d687e70f0df2afe1c0982074ff7
3
+ metadata.gz: 129f39dcc8d61a3eb8f38629fbcd97d176c645cff64ffbef92ec56344a3d3e63
4
+ data.tar.gz: 4ed23b370e993fd94d5a364d1dfa8632a4dcc2cfd875db1c4d00f8ec31058523
5
5
  SHA512:
6
- metadata.gz: f82c2398cb1e23f64edf656e1ba392f50826a96e040658da034f404b0ed44d65456d92befc2fed47f09220ebc7ca990fcee826e96e9161abb2e8489004e974a9
7
- data.tar.gz: 27a6bb968c5dd1f155bc452e6114fe474ec2a16b2d9fb35c318812404b19f133c8d3332bc2fd2c3601de2ec3022f9f37680835e7f016cca205d8ab94d0e8c042
6
+ metadata.gz: c8e202ba1d1d0c12d60b33bf13c2a3ecab28e039d5864cbf5c4b451a0addd0d86aa10a8db6010570414dc6007ec642cccdaee1314ba773225d30f00f41c4d9a7
7
+ data.tar.gz: a9ef9e5b42b6c11218717a4c2b213409be6e102bf543771f7472710dfc14c4a54f5285edea56256faec0afa5041455e4f083ae566c26934c7bca59e339393b06
data/Rakefile CHANGED
@@ -32,7 +32,3 @@ Rake::TestTask.new(:test) do |t|
32
32
  end
33
33
 
34
34
  task default: :test
35
-
36
- # Adds the Auxilium semver task
37
- spec = Gem::Specification.find_by_name "auxilium"
38
- load "#{spec.gem_dir}/lib/tasks/semver.rake"
@@ -0,0 +1,35 @@
1
+ module Importo
2
+ class SidekiqBatchAdapter
3
+ attr_reader :description
4
+ attr_accessor :properties
5
+ attr_writer :instance
6
+
7
+ def initialize
8
+ @instance = Sidekiq::Batch.new
9
+ end
10
+
11
+ delegate :description=, to: :@instance
12
+
13
+ def on_success(job)
14
+ @instance.on(:success, job.constantize, properties)
15
+ end
16
+
17
+ def add
18
+ @instance.jobs do
19
+ yield
20
+ end
21
+ end
22
+
23
+ def finished?
24
+ @instance.status.complete?
25
+ end
26
+
27
+ class << self
28
+ def find(id)
29
+ instance = new
30
+ instance.instance = Sidekiq::Batch.new(id)
31
+ instance
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_dependency 'importo/application_controller'
3
+ require_dependency "importo/application_controller"
4
4
 
5
5
  module Importo
6
6
  class ImportsController < ApplicationController
@@ -11,16 +11,16 @@ module Importo
11
11
  def create
12
12
  unless import_params
13
13
  @import = Import.new(kind: params[:kind], locale: I18n.locale)
14
- Signum.error(Current.user, text: t('.flash.no_file'))
14
+ Signum.error(Current.user, text: t(".flash.no_file"))
15
15
  render :new
16
16
  return
17
17
  end
18
18
  @import = Import.new(import_params.merge(locale: I18n.locale,
19
- importo_ownable: Importo.config.current_import_owner.call))
19
+ importo_ownable: Importo.config.current_import_owner.call))
20
20
  if @import.valid? && @import.schedule!
21
21
  redirect_to importo.new_import_path(params[:kind] || @import.kind)
22
22
  else
23
- Signum.error(Current.user, text: t('.flash.error', error: @import.errors&.full_messages&.join('.')))
23
+ Signum.error(Current.user, text: t(".flash.error", error: @import.errors&.full_messages&.join(".")))
24
24
  render :new
25
25
  end
26
26
  end
@@ -28,15 +28,15 @@ module Importo
28
28
  def undo
29
29
  @import = Import.where(importo_ownable: Importo.config.current_import_owner.call).find(params[:id])
30
30
  if @import.can_revert? && @import.revert
31
- redirect_to action: :index, notice: 'Import reverted'
31
+ redirect_to action: :index, notice: "Import reverted"
32
32
  else
33
- redirect_to action: :index, alert: 'Import could not be reverted'
33
+ redirect_to action: :index, alert: "Import could not be reverted"
34
34
  end
35
35
  end
36
36
 
37
37
  def destroy
38
38
  @import = Import.find(params[:id])
39
- redirect_to(action: :index, alert: 'Not allowed') && return unless Importo.config.admin_can_destroy.call(@import)
39
+ redirect_to(action: :index, alert: "Not allowed") && return unless Importo.config.admin_can_destroy.call(@import)
40
40
 
41
41
  @import.destroy
42
42
  redirect_to action: :index
@@ -45,13 +45,13 @@ module Importo
45
45
  def sample
46
46
  import = Import.new(kind: params[:kind], locale: I18n.locale)
47
47
  send_data import.importer.sample_file.read,
48
- type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', filename: import.importer.file_name('sample')
48
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", filename: import.importer.file_name("sample")
49
49
  end
50
50
 
51
51
  def export
52
52
  import = Import.new(kind: params[:kind], locale: I18n.locale)
53
53
  send_data import.importer.export_file.read,
54
- type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', filename: import.importer.file_name('export')
54
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", filename: import.importer.file_name("export")
55
55
  end
56
56
 
57
57
  def index
@@ -62,7 +62,7 @@ module Importo
62
62
 
63
63
  def import_params
64
64
  params.require(:import).permit(:original, :kind, :column_overrides,
65
- column_overrides: params.dig(:import, :column_overrides)&.keys)
65
+ column_overrides: params.dig(:import, :column_overrides)&.keys)
66
66
  end
67
67
  end
68
68
  end
@@ -126,11 +126,12 @@ module Importable
126
126
  def import!
127
127
  raise ArgumentError, "Invalid data structure" unless structure_valid?
128
128
 
129
- batch = Sidekiq::Batch.new
129
+ batch = Importo::SidekiqBatchAdapter.new
130
130
  batch.description = "#{import.original.filename} - #{import.kind}"
131
- batch.on(:success, Importo::ImportJobCallback, import_id: import.id)
131
+ batch.properties = {import_id: import.id}
132
+ batch.on_success("Importo::ImportJobCallback")
132
133
 
133
- batch.jobs do
134
+ batch.add do
134
135
  column_with_delay = columns.select { |k, v| v.delay.present? }
135
136
  loop_data_rows do |attributes, index|
136
137
  if column_with_delay.present?
@@ -2,7 +2,7 @@ module Importo
2
2
  class ImportJobCallback
3
3
  include Rails.application.routes.url_helpers
4
4
 
5
- def on_complete(_status, options)
5
+ def on_complete(options)
6
6
  options = options.deep_stringify_keys
7
7
  import = Import.find(options["import_id"])
8
8
  if import.present?
@@ -21,9 +21,5 @@ module Importo
21
21
  end
22
22
  end
23
23
  end
24
-
25
- def on_success(status, options)
26
- on_complete(status, options)
27
- end
28
24
  end
29
25
  end
@@ -30,10 +30,10 @@ module Importo
30
30
  import = Import.find(import_id)
31
31
  record = import.importer.process_data_row(attributes, index, last_attempt: last_attempt)
32
32
 
33
- batch = Sidekiq::Batch.new(bid)
33
+ batch = Importo::SidekiqBatchAdapter.find(bid)
34
34
 
35
- if !import.completed? && import.can_complete? && batch.status.complete?
36
- ImportJobCallback.new.on_complete(batch.status, {import_id: import_id})
35
+ if !import.completed? && import.can_complete? && batch.finished?
36
+ ImportJobCallback.new.on_complete(import_id: import_id)
37
37
  end
38
38
  end
39
39
  end
@@ -0,0 +1,11 @@
1
+ module Importo
2
+ class ImportScheduledJob < ApplicationJob
3
+ def perform()
4
+ imports = Import.where(state: "scheduled", created_at: ..30.minutes.ago)
5
+
6
+ imports.each do |import|
7
+ ImportService.perform_async(import: import)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -76,7 +76,7 @@ module Importo
76
76
  invalid_headers: importer.invalid_header_names.join(", ")))
77
77
  end
78
78
  rescue => e
79
- errors.add(:original, I18n.t("importo.errors.parse_error", error: e.message))
79
+ errors.add(:original, I18n.t("importo.errors.parse_error", error: e.message)) unless state == "failed"
80
80
  end
81
81
 
82
82
  def importer
@@ -1,9 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Importo
4
- class ImportContext < ApplicationContext
5
- input do
6
- attribute :import, type: Import, typecaster: ->(value) { value.is_a?(Import) ? value : Import.find(value) }
4
+ if defined?(Servitium) && ApplicationContext < Servitium::Context
5
+ class ImportContext < ApplicationContext
6
+ input do
7
+ attribute :import, type: Import, typecaster: ->(value) { value.is_a?(Import) ? value : Import.find(value) }
8
+ end
7
9
  end
10
+ else
11
+ class ImportContext < ApplicationContext
12
+ attribute :import, :model, class_name: "Importo::Import"
13
+ end
14
+
8
15
  end
9
16
  end
@@ -6,8 +6,7 @@ module Importo
6
6
  context.import.import!
7
7
  context.import.importer.import!
8
8
  rescue
9
- context.import.failure!
10
- context.fail!
9
+ context.import.failure!
11
10
  end
12
11
  end
13
12
  end
@@ -2,38 +2,38 @@
2
2
 
3
3
  if defined? ActionTable
4
4
  class Importo::ImportsTable < ActionTable::ActionTable
5
- model Importo::Import
5
+ model Importo::Import
6
6
 
7
- column(:created_at, html_value: proc { |import| l(import.created_at.in_time_zone(Time.zone), format: :short).to_s })
8
- column(:user, sortable: false) { |import| import.importo_ownable.name }
9
- column(:kind, sortable: false)
10
- column(:original, sortable: false) { |import| link_to(import.original.filename, main_app.rails_blob_path(import.original, disposition: "attachment"), target: "_blank") }
11
- column(:state)
12
- column(:result, sortable: false) { |import| import.result.attached? ? link_to(import.result_message, main_app.rails_blob_path(import.result, disposition: "attachment"), target: "_blank") : import.result_message }
13
- column(:extra_links, sortable: false) { |import| Importo.config.admin_extra_links.call(import).map { |name, link| link_to(link[:text], link[:url], title: link[:title], target: "_blank", class: link[:icon]) } }
7
+ column(:created_at, html_value: proc { |import| l(import.created_at.in_time_zone(Time.zone), format: :short).to_s })
8
+ column(:user, sortable: false) { |import| import.importo_ownable.name }
9
+ column(:kind, sortable: false)
10
+ column(:original, sortable: false) { |import| link_to(import.original.filename, main_app.rails_blob_path(import.original, disposition: "attachment"), target: "_blank") }
11
+ column(:state)
12
+ column(:result, sortable: false) { |import| import.result.attached? ? link_to(import.result_message, main_app.rails_blob_path(import.result, disposition: "attachment"), target: "_blank") : import.result_message }
13
+ column(:extra_links, sortable: false) { |import| Importo.config.admin_extra_links.call(import).map { |name, link| link_to(link[:text], link[:url], title: link[:title], target: "_blank", class: link[:icon]) } }
14
14
 
15
- column :actions, title: "", sortable: false do |import|
16
- content_tag(:span) do
17
- if import.can_revert?
18
- concat link_to(content_tag(:i, nil, class: "fa fa-undo"), importo.undo_import_path(import), data: {turbo_method: :post, turbo_confirm: "Are you sure? This will undo this import."})
19
- end
20
- if Importo.config.admin_can_destroy.call(import)
21
- concat link_to(content_tag(:i, nil, class: "fa fa-trash"), importo.import_path(import), class: "float-right", data: {turbo_method: :delete, turbo_confirm: "Are you sure? This will prevent duplicate imports from being detected."})
15
+ column :actions, title: "", sortable: false do |import|
16
+ content_tag(:span) do
17
+ if import.can_revert?
18
+ concat link_to(content_tag(:i, nil, class: "fa fa-undo"), importo.undo_import_path(import), data: {turbo_method: :post, turbo_confirm: "Are you sure? This will undo this import."})
19
+ end
20
+ if Importo.config.admin_can_destroy.call(import)
21
+ concat link_to(content_tag(:i, nil, class: "fa fa-trash"), importo.import_path(import), class: "float-right", data: {turbo_method: :delete, turbo_confirm: "Are you sure? This will prevent duplicate imports from being detected."})
22
+ end
22
23
  end
23
24
  end
24
- end
25
25
 
26
- # filter(:importo_ownable){ parameter: :ownable, collection_proc: -> { Importo::Import.order(created_at: :desc).limit(200).map(&:importo_ownable).uniq.sort_by(&:name).map { |o| [o.name, "#{o.class.name}##{o.id}"] } } } )
26
+ # filter(:importo_ownable){ parameter: :ownable, collection_proc: -> { Importo::Import.order(created_at: :desc).limit(200).map(&:importo_ownable).uniq.sort_by(&:name).map { |o| [o.name, "#{o.class.name}##{o.id}"] } } } )
27
27
 
28
- initial_order :created_at, :desc
28
+ initial_order :created_at, :desc
29
29
 
30
- private
30
+ private
31
31
 
32
- def scope
33
- @scope = Importo.config.admin_visible_imports.call
34
- @scope
32
+ def scope
33
+ @scope = Importo.config.admin_visible_imports.call
34
+ @scope
35
+ end
35
36
  end
36
- end
37
37
  else
38
38
  class Importo::ImportsTable
39
39
  end
@@ -38,7 +38,6 @@ if defined? Mensa
38
38
  end
39
39
  end
40
40
 
41
-
42
41
  order created_at: :desc
43
42
  end
44
43
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "axlsx"
4
+ require "roo/excelx"
4
5
 
5
6
  module Importo
6
7
  module TestHelpers
@@ -15,5 +16,22 @@ module Importo
15
16
 
16
17
  xls.to_stream
17
18
  end
19
+
20
+ def sample_sheet(kind, locale: I18n.locale)
21
+ excel = Importo::Import.new(kind: kind, locale: locale).importer.sample_file
22
+
23
+ Roo::Excelx.new(excel.set_encoding("BINARY"))
24
+ end
25
+
26
+ def import_sheet(kind, sheet, filename: "import.xlsx", locale: I18n.locale, owner: @owner)
27
+ import = Importo::Import.new(kind: kind, locale: locale, importo_ownable: owner)
28
+
29
+ import.original.attach(io: sheet, filename: filename, content_type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", identify: false)
30
+ import.save!
31
+
32
+ ImportService.perform(import: import)
33
+ ImportJobCallback.new.on_complete({import_id: import.id})
34
+ import
35
+ end
18
36
  end
19
37
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Importo
4
- VERSION = "3.0.13"
4
+ VERSION = "3.0.15"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: importo
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.13
4
+ version: 3.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andre Meij
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-04-24 00:00:00.000000000 Z
12
+ date: 2024-09-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: caxlsx
@@ -96,47 +96,47 @@ dependencies:
96
96
  - !ruby/object:Gem::Version
97
97
  version: '1.2'
98
98
  - !ruby/object:Gem::Dependency
99
- name: slim
99
+ name: signum
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - ">"
102
+ - - "~>"
103
103
  - !ruby/object:Gem::Version
104
- version: '3.0'
104
+ version: '0.3'
105
105
  type: :runtime
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - ">"
109
+ - - "~>"
110
110
  - !ruby/object:Gem::Version
111
- version: '3.0'
111
+ version: '0.3'
112
112
  - !ruby/object:Gem::Dependency
113
- name: state_machines-activerecord
113
+ name: slim
114
114
  requirement: !ruby/object:Gem::Requirement
115
115
  requirements:
116
- - - "~>"
116
+ - - ">"
117
117
  - !ruby/object:Gem::Version
118
- version: '0.5'
118
+ version: '3.0'
119
119
  type: :runtime
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
- - - "~>"
123
+ - - ">"
124
124
  - !ruby/object:Gem::Version
125
- version: '0.5'
125
+ version: '3.0'
126
126
  - !ruby/object:Gem::Dependency
127
- name: signum
127
+ name: state_machines-activerecord
128
128
  requirement: !ruby/object:Gem::Requirement
129
129
  requirements:
130
130
  - - "~>"
131
131
  - !ruby/object:Gem::Version
132
- version: '0.3'
132
+ version: '0.5'
133
133
  type: :runtime
134
134
  prerelease: false
135
135
  version_requirements: !ruby/object:Gem::Requirement
136
136
  requirements:
137
137
  - - "~>"
138
138
  - !ruby/object:Gem::Version
139
- version: '0.3'
139
+ version: '0.5'
140
140
  - !ruby/object:Gem::Dependency
141
141
  name: turbo-rails
142
142
  requirement: !ruby/object:Gem::Requirement
@@ -236,7 +236,7 @@ dependencies:
236
236
  - !ruby/object:Gem::Version
237
237
  version: '0'
238
238
  - !ruby/object:Gem::Dependency
239
- name: pry
239
+ name: debug
240
240
  requirement: !ruby/object:Gem::Requirement
241
241
  requirements:
242
242
  - - ">="
@@ -264,19 +264,19 @@ dependencies:
264
264
  - !ruby/object:Gem::Version
265
265
  version: '0.3'
266
266
  - !ruby/object:Gem::Dependency
267
- name: solargraph
267
+ name: rubocop
268
268
  requirement: !ruby/object:Gem::Requirement
269
269
  requirements:
270
- - - "~>"
270
+ - - ">="
271
271
  - !ruby/object:Gem::Version
272
- version: '0.47'
272
+ version: '1'
273
273
  type: :development
274
274
  prerelease: false
275
275
  version_requirements: !ruby/object:Gem::Requirement
276
276
  requirements:
277
- - - "~>"
277
+ - - ">="
278
278
  - !ruby/object:Gem::Version
279
- version: '0.47'
279
+ version: '1'
280
280
  - !ruby/object:Gem::Dependency
281
281
  name: standard
282
282
  requirement: !ruby/object:Gem::Requirement
@@ -302,6 +302,7 @@ files:
302
302
  - MIT-LICENSE
303
303
  - README.md
304
304
  - Rakefile
305
+ - app/adapters/importo/sidekiq_batch_adapter.rb
305
306
  - app/assets/config/importo_manifest.js
306
307
  - app/assets/javascripts/importo/application.js
307
308
  - app/assets/stylesheets/importo/application.css
@@ -319,6 +320,7 @@ files:
319
320
  - app/importers/importo/import_job_callback.rb
320
321
  - app/jobs/importo/application_job.rb
321
322
  - app/jobs/importo/import_job.rb
323
+ - app/jobs/importo/import_scheduled_job.rb
322
324
  - app/jobs/importo/purge_import_job.rb
323
325
  - app/mailers/importo/application_mailer.rb
324
326
  - app/models/importo/application_record.rb