solidus_importer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +35 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.gitignore +20 -0
  6. data/.hound.yml +8 -0
  7. data/.rspec +2 -0
  8. data/.rubocop.yml +2 -0
  9. data/Gemfile +33 -0
  10. data/LICENSE +26 -0
  11. data/README.md +170 -0
  12. data/Rakefile +6 -0
  13. data/app/assets/javascripts/spree/backend/solidus_importer.js +2 -0
  14. data/app/assets/javascripts/spree/frontend/solidus_importer.js +2 -0
  15. data/app/assets/stylesheets/spree/backend/solidus_importer.css +16 -0
  16. data/app/assets/stylesheets/spree/frontend/solidus_importer.css +4 -0
  17. data/app/controllers/spree/admin/solidus_importer/import_rows_controller.rb +24 -0
  18. data/app/controllers/spree/admin/solidus_importer/imports_controller.rb +44 -0
  19. data/app/jobs/solidus_importer/import_job.rb +30 -0
  20. data/app/models/solidus_importer/import.rb +48 -0
  21. data/app/models/solidus_importer/row.rb +26 -0
  22. data/app/views/spree/admin/solidus_importer/import_rows/show.html.erb +46 -0
  23. data/app/views/spree/admin/solidus_importer/imports/_form.html.erb +14 -0
  24. data/app/views/spree/admin/solidus_importer/imports/index.html.erb +80 -0
  25. data/app/views/spree/admin/solidus_importer/imports/new.html.erb +13 -0
  26. data/app/views/spree/admin/solidus_importer/imports/show.html.erb +87 -0
  27. data/bin/console +17 -0
  28. data/bin/rails +7 -0
  29. data/bin/rails-engine +13 -0
  30. data/bin/rails-sandbox +16 -0
  31. data/bin/rake +7 -0
  32. data/bin/sandbox +84 -0
  33. data/bin/setup +8 -0
  34. data/config/initializers/spree.rb +11 -0
  35. data/config/locales/en.yml +28 -0
  36. data/config/routes.rb +11 -0
  37. data/db/migrate/20191216101011_create_solidus_importer_imports.rb +19 -0
  38. data/db/migrate/20191216101012_create_solidus_importer_rows.rb +14 -0
  39. data/examples/importers/custom_importer.rb +20 -0
  40. data/examples/processors/notify_on_failure.rb +22 -0
  41. data/lib/generators/solidus_importer/install/install_generator.rb +22 -0
  42. data/lib/solidus_importer.rb +25 -0
  43. data/lib/solidus_importer/base_importer.rb +26 -0
  44. data/lib/solidus_importer/configuration.rb +39 -0
  45. data/lib/solidus_importer/engine.rb +23 -0
  46. data/lib/solidus_importer/exception.rb +5 -0
  47. data/lib/solidus_importer/factories.rb +4 -0
  48. data/lib/solidus_importer/process_import.rb +88 -0
  49. data/lib/solidus_importer/process_row.rb +46 -0
  50. data/lib/solidus_importer/processors/address.rb +47 -0
  51. data/lib/solidus_importer/processors/base.rb +15 -0
  52. data/lib/solidus_importer/processors/customer.rb +41 -0
  53. data/lib/solidus_importer/processors/log.rb +15 -0
  54. data/lib/solidus_importer/processors/option_types.rb +43 -0
  55. data/lib/solidus_importer/processors/option_values.rb +49 -0
  56. data/lib/solidus_importer/processors/order.rb +40 -0
  57. data/lib/solidus_importer/processors/product.rb +51 -0
  58. data/lib/solidus_importer/processors/product_images.rb +30 -0
  59. data/lib/solidus_importer/processors/taxon.rb +52 -0
  60. data/lib/solidus_importer/processors/variant.rb +51 -0
  61. data/lib/solidus_importer/processors/variant_images.rb +30 -0
  62. data/lib/solidus_importer/version.rb +5 -0
  63. data/solidus_importer.gemspec +36 -0
  64. data/spec/factories/solidus_importer_imports.rb +27 -0
  65. data/spec/factories/solidus_importer_rows.rb +82 -0
  66. data/spec/features/admin/solidus_importer/import_rows_spec.rb +30 -0
  67. data/spec/features/admin/solidus_importer/imports_spec.rb +121 -0
  68. data/spec/features/solidus_importer/import_spec.rb +138 -0
  69. data/spec/features/solidus_importer/processors_spec.rb +53 -0
  70. data/spec/fixtures/solidus_importer/apparel.csv +23 -0
  71. data/spec/fixtures/solidus_importer/customers.csv +3 -0
  72. data/spec/fixtures/solidus_importer/home-and-garden.csv +22 -0
  73. data/spec/fixtures/solidus_importer/invalid_headers.csv +3 -0
  74. data/spec/fixtures/solidus_importer/invalid_product.csv +2 -0
  75. data/spec/fixtures/solidus_importer/jewelery.csv +55 -0
  76. data/spec/fixtures/solidus_importer/orders.csv +5 -0
  77. data/spec/fixtures/solidus_importer/products.csv +8 -0
  78. data/spec/fixtures/solidus_importer/thinking-cat.jpg +0 -0
  79. data/spec/jobs/solidus_importer/import_job_spec.rb +54 -0
  80. data/spec/lib/solidus_importer/base_importer_spec.rb +23 -0
  81. data/spec/lib/solidus_importer/process_import_spec.rb +74 -0
  82. data/spec/lib/solidus_importer/process_row_spec.rb +24 -0
  83. data/spec/lib/solidus_importer/processors/address_spec.rb +18 -0
  84. data/spec/lib/solidus_importer/processors/base_spec.rb +9 -0
  85. data/spec/lib/solidus_importer/processors/customer_spec.rb +65 -0
  86. data/spec/lib/solidus_importer/processors/log_spec.rb +18 -0
  87. data/spec/lib/solidus_importer/processors/option_types_spec.rb +38 -0
  88. data/spec/lib/solidus_importer/processors/option_values_spec.rb +43 -0
  89. data/spec/lib/solidus_importer/processors/order_spec.rb +56 -0
  90. data/spec/lib/solidus_importer/processors/product_images_spec.rb +42 -0
  91. data/spec/lib/solidus_importer/processors/product_spec.rb +66 -0
  92. data/spec/lib/solidus_importer/processors/taxon_spec.rb +33 -0
  93. data/spec/lib/solidus_importer/processors/variant_images_spec.rb +44 -0
  94. data/spec/lib/solidus_importer/processors/variant_spec.rb +86 -0
  95. data/spec/lib/solidus_importer_spec.rb +14 -0
  96. data/spec/models/solidus_importer/import_spec.rb +60 -0
  97. data/spec/models/solidus_importer/row_spec.rb +18 -0
  98. data/spec/spec_helper.rb +27 -0
  99. data/spec/support/solidus_importer_helpers.rb +13 -0
  100. metadata +227 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3c368dcdb23d45c02c54cd01f247debce0e9083119bda2dc1f358a0718e3b7d8
4
+ data.tar.gz: 4336a3ad45dc07ba7e6aa5d0e12a953242439a8698c3b8c6a0b36a175e38384d
5
+ SHA512:
6
+ metadata.gz: 0a3de867687407c132ffe9444a4a1e3b5913dcde1cedabc3b28353bac061f9822bd87ce66fba277904ca20a9c63cfeb8854edadcc37cbff3a9852b80092066c2
7
+ data.tar.gz: e32d1dc88ccc3db3a234223d0149514aa8173b163f940ada667e43e128a74802d4e2331ec41a7773694ba0cc744051390756c76f22eb2cad7c09504e3fc9c4cd
@@ -0,0 +1,35 @@
1
+ version: 2.1
2
+
3
+ orbs:
4
+ # Always take the latest version of the orb, this allows us to
5
+ # run specs against Solidus supported versions only without the need
6
+ # to change this configuration every time a Solidus version is released
7
+ # or goes EOL.
8
+ solidusio_extensions: solidusio/extensions@volatile
9
+
10
+ jobs:
11
+ run-specs-with-postgres:
12
+ executor: solidusio_extensions/postgres
13
+ steps:
14
+ - solidusio_extensions/run-tests
15
+ run-specs-with-mysql:
16
+ executor: solidusio_extensions/mysql
17
+ steps:
18
+ - solidusio_extensions/run-tests
19
+
20
+ workflows:
21
+ "Run specs on supported Solidus versions":
22
+ jobs:
23
+ - run-specs-with-postgres
24
+ - run-specs-with-mysql
25
+ "Weekly run specs against master":
26
+ triggers:
27
+ - schedule:
28
+ cron: "0 0 * * 4" # every Thursday
29
+ filters:
30
+ branches:
31
+ only:
32
+ - master
33
+ jobs:
34
+ - run-specs-with-postgres
35
+ - run-specs-with-mysql
@@ -0,0 +1,5 @@
1
+ bump:
2
+ recurse: false
3
+ file: 'lib/solidus_importer/version.rb'
4
+ message: Bump SolidusImporter to %{version}
5
+ tag: true
@@ -0,0 +1,17 @@
1
+ # Number of days of inactivity before an issue becomes stale
2
+ daysUntilStale: 60
3
+ # Number of days of inactivity before a stale issue is closed
4
+ daysUntilClose: 7
5
+ # Issues with these labels will never be considered stale
6
+ exemptLabels:
7
+ - pinned
8
+ - security
9
+ # Label to use when marking an issue as stale
10
+ staleLabel: wontfix
11
+ # Comment to post when marking an issue as stale. Set to `false` to disable
12
+ markComment: >
13
+ This issue has been automatically marked as stale because it has not had
14
+ recent activity. It will be closed if no further activity occurs. Thank you
15
+ for your contributions.
16
+ # Comment to post when closing a stale issue. Set to `false` to disable
17
+ closeComment: false
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ \#*
3
+ *~
4
+ .#*
5
+ .DS_Store
6
+ .idea
7
+ .project
8
+ .sass-cache
9
+ coverage
10
+ Gemfile.lock
11
+ tmp
12
+ nbproject
13
+ pkg
14
+ *.swp
15
+ spec/dummy
16
+ spec/examples.txt
17
+ /sandbox
18
+ .rvmrc
19
+ .ruby-version
20
+ .ruby-gemset
@@ -0,0 +1,8 @@
1
+ fail_on_violations: true
2
+
3
+ rubocop:
4
+ config_file: .rubocop.yml
5
+ version: 0.75.0
6
+
7
+ scss:
8
+ enabled: false
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,2 @@
1
+ require:
2
+ - solidus_dev_support/rubocop
data/Gemfile ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
5
+
6
+ branch = ENV.fetch('SOLIDUS_BRANCH', 'master')
7
+ gem 'solidus', github: 'solidusio/solidus', branch: branch
8
+
9
+ # Needed to help Bundler figure out how to resolve dependencies,
10
+ # otherwise it takes forever to resolve them.
11
+ # See https://github.com/bundler/bundler/issues/6677
12
+ gem 'rails', '>0.a'
13
+
14
+ # Provides basic authentication functionality for testing parts of your engine
15
+ gem 'solidus_auth_devise'
16
+
17
+ case ENV['DB']
18
+ when 'mysql'
19
+ gem 'mysql2'
20
+ when 'postgresql'
21
+ gem 'pg'
22
+ else
23
+ gem 'sqlite3'
24
+ end
25
+
26
+ gemspec
27
+
28
+ # Use a local Gemfile to include development dependencies that might not be
29
+ # relevant for the project or for other contributors, e.g. pry-byebug.
30
+ #
31
+ # We use `send` instead of calling `eval_gemfile` to work around an issue with
32
+ # how Dependabot parses projects: https://github.com/dependabot/dependabot-core/issues/1658.
33
+ send(:eval_gemfile, 'Gemfile-local') if File.exist? 'Gemfile-local'
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2020 Nebulab SRLs and other contributors
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name Solidus nor the names of its contributors may be used to
13
+ endorse or promote products derived from this software without specific
14
+ prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,170 @@
1
+ # Solidus Importer
2
+
3
+ This extension aims to create a component to import data from other popular
4
+ e-commerce solutions to Solidus.
5
+
6
+ ## Installation
7
+
8
+ Add solidus_importer to your Gemfile:
9
+
10
+ ```ruby
11
+ gem 'solidus_importer'
12
+ ```
13
+
14
+ Bundle your dependencies and run the installation generator:
15
+
16
+ ```shell
17
+ bundle
18
+ bundle exec rails g solidus_importer:install
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Sample code to import some products:
24
+
25
+ ```ruby
26
+ SolidusImporter.import! 'some_path/sample_products.csv', type: :products
27
+ ```
28
+
29
+ ### Accepted Format
30
+
31
+ The accepted format is the [Shopify CSV](https://help.shopify.com/en/manual/products/import-export/using-csv) for which is also relatively easy to find exporters for every major platform (e.g. [shopify_transporter](https://github.com/Shopify/shopify_transporter)).
32
+
33
+ There are three supported CSV types:
34
+
35
+ 1. [Product](https://help.shopify.com/en/manual/migrating-to-shopify/transporter-app/csv-products)
36
+ 2. [Order](https://help.shopify.com/en/manual/migrating-to-shopify/transporter-app/csv-orders)
37
+ 3. [Customer](https://help.shopify.com/en/manual/migrating-to-shopify/transporter-app/csv-customers)
38
+
39
+ ### The Processors
40
+
41
+ The importing is managed by a list of processors for each CSV type, the default processors are:
42
+
43
+ ```rb
44
+ customers: {
45
+ importer: SolidusImporter::BaseImporter,
46
+ processors: [
47
+ SolidusImporter::Processors::Address,
48
+ SolidusImporter::Processors::Customer,
49
+ SolidusImporter::Processors::Log
50
+ ]
51
+ },
52
+ orders: {
53
+ importer: SolidusImporter::BaseImporter,
54
+ processors: [
55
+ SolidusImporter::Processors::Order,
56
+ SolidusImporter::Processors::Log
57
+ ]
58
+ },
59
+ products: {
60
+ importer: SolidusImporter::BaseImporter,
61
+ processors: [
62
+ SolidusImporter::Processors::Product,
63
+ SolidusImporter::Processors::Variant,
64
+ SolidusImporter::Processors::OptionTypes,
65
+ SolidusImporter::Processors::OptionValues,
66
+ SolidusImporter::Processors::ProductImages,
67
+ SolidusImporter::Processors::VariantImages,
68
+ SolidusImporter::Processors::Log
69
+ ]
70
+ }
71
+ ```
72
+
73
+ Each processor is a callable that will accept a context Hash. It will perform its function within the `#call(context)` method and will return an equally valid context Hash. The returned context can be augmented with additional data.
74
+
75
+ Example:
76
+
77
+ ```rb
78
+ CUSTOM_LOGGER = Logger.new(Rails.root.join('log/importer.log'))
79
+ CustomLoggerProcessor = ->(context) {
80
+ context.merge(logger: CUSTOM_LOGGER)
81
+ }
82
+ # Replace the original Log processor with CustomLoggerProcessor
83
+ SolidusImporter::Config.solidus_importer[:customers][:processors].map! do |processor|
84
+ if processor == 'SolidusImporter::Processors::Log'
85
+ 'CustomLoggerProcessor'
86
+ else
87
+ processors
88
+ end
89
+ end
90
+ ```
91
+
92
+ Each list of processors can be configured to add, remove, or replace any of the default processors.
93
+
94
+ ### Advanced Configuration
95
+
96
+ To define your own processors (in this example for products), add to the spree
97
+ initializer:
98
+
99
+ ```ruby
100
+ SolidusImporter::Config[:solidus_importer] = {
101
+ products: {
102
+ importer: SolidusImporter::Importers::Products,
103
+ processors: [
104
+ SolidusImporter::Processors::Product,
105
+ SolidusImporter::Processors::Variant,
106
+ SolidusImporter::Processors::Log
107
+ ]
108
+ }
109
+ }
110
+ ```
111
+
112
+ The `importer` class is responsible of the whole import process of a single
113
+ source file. The `processors` classes are responsible of the import of a single
114
+ row of the source file; every processor has a `call` method (with an input
115
+ `context`) which makes a specific action and updates the context if needed.
116
+
117
+ ## Development
118
+
119
+ ### Testing the extension
120
+
121
+ First bundle your dependencies, then run `bin/rake`. `bin/rake` will default to building the dummy
122
+ app if it does not exist, then it will run specs. The dummy app can be regenerated by using
123
+ `bin/rake extension:test_app`.
124
+
125
+ ```shell
126
+ bin/setup
127
+ bin/rake
128
+ ```
129
+
130
+ To run [Rubocop](https://github.com/bbatsov/rubocop) static code analysis run
131
+
132
+ ```shell
133
+ bundle exec rubocop
134
+ ```
135
+
136
+ When testing your application's integration with this extension you may use its factories.
137
+ Simply add this require statement to your spec_helper:
138
+
139
+ ```ruby
140
+ require 'solidus_importer/factories'
141
+
142
+ ```
143
+
144
+ ### Running the sandbox
145
+
146
+ To run this extension in a sandboxed Solidus application, you can run `bin/sandbox`. The path for
147
+ the sandbox app is `./sandbox` and `bin/rails` will forward any Rails commands to
148
+ `sandbox/bin/rails`.
149
+
150
+ Here's an example:
151
+
152
+ ```shell
153
+ $ bin/rails server
154
+ => Booting Puma
155
+ => Rails 6.0.2.1 application starting in development
156
+ * Listening on tcp://127.0.0.1:3000
157
+ Use Ctrl-C to stop
158
+ ```
159
+
160
+ ### Releasing new versions
161
+
162
+ Your new extension version can be released using `gem-release` like this:
163
+
164
+ ```shell
165
+ bundle exec gem bump -v VERSION --tag --push --remote upstream && gem release
166
+ ```
167
+
168
+ ## License
169
+
170
+ Copyright (c) 2020 Nebulab SRLs, released under the New BSD License
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_dev_support/rake_tasks'
4
+ SolidusDevSupport::RakeTasks.install
5
+
6
+ task default: 'extension:specs'
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/backend/all.js'
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/frontend/all.js'
@@ -0,0 +1,16 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/backend/all.css'
4
+ */
5
+
6
+ .solidus_importer.state-failed {
7
+ color: #d00;
8
+ }
9
+
10
+ .solidus_importer.state-processing {
11
+ color: #fb1;
12
+ }
13
+
14
+ .solidus_importer.state-completed {
15
+ color: #0a0;
16
+ }
@@ -0,0 +1,4 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/frontend/all.css'
4
+ */
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Admin
5
+ module SolidusImporter
6
+ class ImportRowsController < BaseController
7
+ before_action :load_data, only: %i[show]
8
+
9
+ def show; end
10
+
11
+ private
12
+
13
+ def load_data
14
+ @import_row = ::SolidusImporter::Row.find_by!(id: params[:id], import_id: params[:import_id])
15
+ return unless (@log_entry = ::Spree::LogEntry.find_by(source: @import_row))
16
+
17
+ @log_details = JSON.parse(@log_entry.details)
18
+ target_class = @log_details['class_name']&.constantize
19
+ @target_entity = target_class.find_by(id: @log_details['id']) if target_class
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Admin
5
+ module SolidusImporter
6
+ class ImportsController < ResourceController
7
+ before_action :assigns_import_types
8
+ after_action :import!, if: -> { @import.valid? }, only: :create
9
+
10
+ def index
11
+ @search = ::SolidusImporter::Import.ransack(params[:q])
12
+ @imports = @search.result(distinct: true)
13
+ .page(params[:page])
14
+ .per(params[:per_page] || Spree::Config[:orders_per_page])
15
+ .order(id: :desc)
16
+ end
17
+
18
+ def show
19
+ @import = ::SolidusImporter::Import.find(params[:id])
20
+ @search = @import.rows.ransack(params[:q])
21
+ @import_rows = @search.result(distinct: true).page(params[:page]).per(params[:per_page]).order(id: :desc)
22
+ end
23
+
24
+ private
25
+
26
+ def import!
27
+ ::SolidusImporter::ImportJob.perform_later(@import.id)
28
+ end
29
+
30
+ def model_class
31
+ ::SolidusImporter::Import
32
+ end
33
+
34
+ def permitted_resource_params
35
+ params.require(:solidus_importer_import).permit(:file, :import_type)
36
+ end
37
+
38
+ def assigns_import_types
39
+ @import_types = ::SolidusImporter::Config.available_types
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end