solidus_feeds 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +41 -0
- data/.gem_release.yml +5 -0
- data/.github/stale.yml +17 -0
- data/.github_changelog_generator +2 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.rubocop.yml +12 -0
- data/Gemfile +33 -0
- data/LICENSE +26 -0
- data/README.md +246 -0
- data/Rakefile +6 -0
- data/app/assets/javascripts/spree/backend/solidus_feeds.js +2 -0
- data/app/assets/javascripts/spree/frontend/solidus_feeds.js +2 -0
- data/app/assets/stylesheets/spree/backend/solidus_feeds.css +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_feeds.css +4 -0
- data/bin/console +17 -0
- data/bin/rails +7 -0
- data/bin/rails-engine +13 -0
- data/bin/rails-sandbox +16 -0
- data/bin/rake +7 -0
- data/bin/sandbox +86 -0
- data/bin/setup +8 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +5 -0
- data/lib/generators/solidus_feeds/install/install_generator.rb +37 -0
- data/lib/generators/solidus_feeds/install/templates/initializer.rb +15 -0
- data/lib/solidus_feeds.rb +13 -0
- data/lib/solidus_feeds/configuration.rb +59 -0
- data/lib/solidus_feeds/engine.rb +19 -0
- data/lib/solidus_feeds/factories.rb +4 -0
- data/lib/solidus_feeds/feed.rb +21 -0
- data/lib/solidus_feeds/generators/google_merchant.rb +106 -0
- data/lib/solidus_feeds/publishers/s3.rb +30 -0
- data/lib/solidus_feeds/publishers/static_file.rb +17 -0
- data/lib/solidus_feeds/testing_support/factories.rb +4 -0
- data/lib/solidus_feeds/version.rb +5 -0
- data/solidus_feeds.gemspec +36 -0
- data/spec/lib/solidus_feeds/generators/google_merchant_spec.rb +132 -0
- data/spec/lib/solidus_feeds/publishers/s3_spec.rb +37 -0
- data/spec/lib/solidus_feeds/publishers/static_file_spec.rb +31 -0
- data/spec/lib/solidus_feeds/solidus_feeds_spec.rb +23 -0
- data/spec/solidus_feeds_spec.rb +29 -0
- data/spec/spec_helper.rb +31 -0
- metadata +157 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 58531c73946da9c28461e17502503cf2b5a4705c6a616f08c9c113013c98a5a0
|
4
|
+
data.tar.gz: 57e0b6b0f02d1a6b9da731c6a6c4f248fc4804ab26e810324849a7691a7deab2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b57c1b93cfb53bd1d188028e101cb92355a3b5920becb8758374c511141f2eb91858a0277d00953537aa0537e3168670ed7989854e44590f46daae333f547645
|
7
|
+
data.tar.gz: aca21bcca2411cd27ae410ca6e13ea9a7848ad428a9d6168b59da33c2dfe94579fe376eca2046a395cdac3ee970c31ab67f513dadb922146dfbdf6e71c29fe8b
|
@@ -0,0 +1,41 @@
|
|
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
|
+
lint-code:
|
20
|
+
executor: solidusio_extensions/sqlite-memory
|
21
|
+
steps:
|
22
|
+
- solidusio_extensions/lint-code
|
23
|
+
|
24
|
+
workflows:
|
25
|
+
"Run specs on supported Solidus versions":
|
26
|
+
jobs:
|
27
|
+
- run-specs-with-postgres
|
28
|
+
- run-specs-with-mysql
|
29
|
+
- lint-code
|
30
|
+
|
31
|
+
"Weekly run specs against master":
|
32
|
+
triggers:
|
33
|
+
- schedule:
|
34
|
+
cron: "0 0 * * 4" # every Thursday
|
35
|
+
filters:
|
36
|
+
branches:
|
37
|
+
only:
|
38
|
+
- master
|
39
|
+
jobs:
|
40
|
+
- run-specs-with-postgres
|
41
|
+
- run-specs-with-mysql
|
data/.gem_release.yml
ADDED
data/.github/stale.yml
ADDED
@@ -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: false
|
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: stale
|
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 might 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
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
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) 2021 Nebulab SRLs
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
# Solidus Feeds
|
2
|
+
|
3
|
+
[![CircleCI](https://circleci.com/gh/solidusio-contrib/solidus_feeds.svg?style=shield)](https://circleci.com/gh/solidusio-contrib/solidus_feeds)
|
4
|
+
[![codecov](https://codecov.io/gh/solidusio-contrib/solidus_feeds/branch/master/graph/badge.svg)](https://codecov.io/gh/solidusio-contrib/solidus_feeds)
|
5
|
+
|
6
|
+
<!-- Explain what your extension does. -->
|
7
|
+
A framework for producing and publishing feeds on Solidus.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add solidus_feeds to your Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'solidus_feeds'
|
15
|
+
```
|
16
|
+
|
17
|
+
Bundle your dependencies and run the installation generator:
|
18
|
+
|
19
|
+
```shell
|
20
|
+
bin/rails generate solidus_feeds:install
|
21
|
+
```
|
22
|
+
|
23
|
+
## Out of the box usage
|
24
|
+
|
25
|
+
<!-- Explain how to use your extension once it's been installed. -->
|
26
|
+
|
27
|
+
Let's say that you want to generate a XML feed for products belonging to the `Shoes` taxon,
|
28
|
+
consumable by Google Merchant compatible marketplaces and make it publicly available on your
|
29
|
+
`my-bucket` S3 bucket at the path `foo/bar.xml`.
|
30
|
+
|
31
|
+
To register the feed you'd need to add the following code to an initializer such as
|
32
|
+
`config/initializers/solidus.rb` or better yet `config/initializers/solidus_feeds.rb`
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
SolidusFeeds.config.register :google_merchant_shoes do |feed|
|
36
|
+
taxon = Spree::Taxon.find_by(name: "Shoes")
|
37
|
+
products = Spree::Product.available.in_taxon(taxon)
|
38
|
+
|
39
|
+
feed.generator = SolidusFeeds::Generators::GoogleMerchant.new(products)
|
40
|
+
feed.publisher = SolidusFeeds::Publishers::S3.new(bucket: "my-bucket", object_key: "foo/bar.xml")
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
Then make your Solidus app generate and publish the feed by calling the following line. It's
|
45
|
+
recommended to call it in a background job, especially when generating feeds with large amounts of
|
46
|
+
products.
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
SolidusFeeds.find(:google_merchant_shoes).publish
|
50
|
+
```
|
51
|
+
|
52
|
+
Having it in a background job makes it easier to:
|
53
|
+
|
54
|
+
- Launch it manually from the backend dashboard
|
55
|
+
- Make it refresh periodically via cron, sidekiq-scheduler, Heroku scheduler or similar
|
56
|
+
- Refresh the feed when receiving data from a [webhook](https://github.com/solidusio-contrib/solidus_webhooks)
|
57
|
+
or after specific Solidus events
|
58
|
+
|
59
|
+
## Serving the feed from the products controller (legacy)
|
60
|
+
|
61
|
+
We suggest to avoid this behaviour because it could be resource intensive, especially with a large
|
62
|
+
number of products.
|
63
|
+
|
64
|
+
If you want to support the legacy behaviour of [`solidus_product_feed`](https://github.com/solidusio-contrib/solidus_product_feed)
|
65
|
+
and publish a XML feed at `/products.rss`, you can add the following decorator:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# app/decorators/controllers/solidus_feeds/spree/products_controller.rb
|
69
|
+
|
70
|
+
module SolidusFeeds
|
71
|
+
module Spree
|
72
|
+
module ProductsControllerDecorator
|
73
|
+
def self.prepended(klass)
|
74
|
+
klass.respond_to :rss, only: :index
|
75
|
+
klass.before_action :verify_requested_format!, only: :index
|
76
|
+
end
|
77
|
+
|
78
|
+
def index
|
79
|
+
render as: :xml, body: load_feed_products if request.format.rss?
|
80
|
+
super
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def load_feed_products
|
86
|
+
@products = ::Spree::Product.all
|
87
|
+
io = StringIO.new
|
88
|
+
SolidusFeeds::Generators::GoogleMerchant
|
89
|
+
.new(@products, host: 'https://example.com')
|
90
|
+
.call(io)
|
91
|
+
io.rewind
|
92
|
+
io.read
|
93
|
+
end
|
94
|
+
|
95
|
+
::Spree::ProductsController.prepend self
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
## Publishing backends
|
102
|
+
|
103
|
+
### S3
|
104
|
+
|
105
|
+
If you don't want to configure a S3 `client` each time, you can load your AWS config in an
|
106
|
+
initializer:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
# config/initializers/aws.rb
|
110
|
+
|
111
|
+
Aws.config[:profile] = 'my-profile'
|
112
|
+
```
|
113
|
+
|
114
|
+
Then config your S3 publisher specifying the `bucket`, `object_key` and an optional `client` if you
|
115
|
+
need custom configuration on a per-publisher basis.
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
# config/initializers/solidus_feeds.rb
|
119
|
+
|
120
|
+
SolidusFeeds.config.register :all_products do |feed|
|
121
|
+
feed.generator = SolidusFeeds::Generators::GoogleMerchant.new(Spree::Product.all)
|
122
|
+
feed.publisher = SolidusFeeds::Publishers::S3.new(
|
123
|
+
bucket: "foo",
|
124
|
+
object_key: "bar/my_feed.xml",
|
125
|
+
client: Aws::S3::Client.new(…), # This is optional - use only if a custom config is needed
|
126
|
+
)
|
127
|
+
|
128
|
+
# visit https://s3.us-east-1.amazonaws.com/foo/bar/my_feed.xml
|
129
|
+
end
|
130
|
+
```
|
131
|
+
|
132
|
+
### Static file
|
133
|
+
|
134
|
+
To publish the feed directly from an app directory (e.g. the `public` directory), you can use the
|
135
|
+
Static File Publisher as such:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
# config/initializers/solidus_feeds.rb
|
139
|
+
|
140
|
+
SolidusFeeds.config.register :all_products do |feed|
|
141
|
+
feed.generator = SolidusFeeds::Generators::GoogleMerchant.new(Spree::Product.all)
|
142
|
+
feed.publisher = SolidusFeeds::Publishers::StaticFile.new(
|
143
|
+
path: Rails.root.join('public/products.xml')
|
144
|
+
)
|
145
|
+
end
|
146
|
+
```
|
147
|
+
|
148
|
+
## Builtin Marketplace format generators
|
149
|
+
|
150
|
+
- Google Merchant XML: compatible with Google Merchant and Facebook/Instagram feeds
|
151
|
+
|
152
|
+
## Creating your own Generators and Publishers
|
153
|
+
|
154
|
+
Both the generator and the publisher are expected to respond to `#call`.
|
155
|
+
|
156
|
+
The publisher's `#call` method is expected to yield an IO-like object that responds to `#<<`.
|
157
|
+
|
158
|
+
### Example
|
159
|
+
|
160
|
+
For example a simple feed that will publish recently added products to Rails' public folder in JSON
|
161
|
+
format would look like this:
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
class FilePublisher < Struct.new(:path)
|
165
|
+
def call
|
166
|
+
File.open(path, 'w') do |file|
|
167
|
+
yield file
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
class JsonProductFeed < Struct.new(:products)
|
173
|
+
def call(io)
|
174
|
+
products.find_each do |product|
|
175
|
+
io << product.to_json
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
SolidusFeeds.register :recent_products do |feed|
|
181
|
+
recent_products = Spree::Product.where(created_at: Time.now..2.weeks.ago)
|
182
|
+
|
183
|
+
feed.generator = JsonProductFeed.new(recent_products)
|
184
|
+
feed.publisher = FilePublisher.new(Rails.root.join("public/product.json")
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
## Development
|
189
|
+
|
190
|
+
### Testing the extension
|
191
|
+
|
192
|
+
First bundle your dependencies, then run `bin/rake`. `bin/rake` will default to building the dummy
|
193
|
+
app if it does not exist, then it will run specs. The dummy app can be regenerated by using
|
194
|
+
`bin/rake extension:test_app`.
|
195
|
+
|
196
|
+
```shell
|
197
|
+
bin/rake
|
198
|
+
```
|
199
|
+
|
200
|
+
To run [Rubocop](https://github.com/bbatsov/rubocop) static code analysis run
|
201
|
+
|
202
|
+
```shell
|
203
|
+
bundle exec rubocop
|
204
|
+
```
|
205
|
+
|
206
|
+
When testing your application's integration with this extension you may use its factories.
|
207
|
+
Simply add this require statement to your spec_helper:
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
require 'solidus_feeds/factories'
|
211
|
+
```
|
212
|
+
|
213
|
+
### Running the sandbox
|
214
|
+
|
215
|
+
To run this extension in a sandboxed Solidus application, you can run `bin/sandbox`. The path for
|
216
|
+
the sandbox app is `./sandbox` and `bin/rails` will forward any Rails commands to
|
217
|
+
`sandbox/bin/rails`.
|
218
|
+
|
219
|
+
Here's an example:
|
220
|
+
|
221
|
+
```
|
222
|
+
$ bin/rails server
|
223
|
+
=> Booting Puma
|
224
|
+
=> Rails 6.0.2.1 application starting in development
|
225
|
+
* Listening on tcp://127.0.0.1:3000
|
226
|
+
Use Ctrl-C to stop
|
227
|
+
```
|
228
|
+
|
229
|
+
### Updating the changelog
|
230
|
+
|
231
|
+
Before and after releases the changelog should be updated to reflect the up-to-date status of
|
232
|
+
the project:
|
233
|
+
|
234
|
+
```shell
|
235
|
+
bin/rake changelog
|
236
|
+
git add CHANGELOG.md
|
237
|
+
git commit -m "Update the changelog"
|
238
|
+
```
|
239
|
+
|
240
|
+
### Releasing new versions
|
241
|
+
|
242
|
+
Please refer to the dedicated [page](https://github.com/solidusio/solidus/wiki/How-to-release-extensions) on Solidus wiki.
|
243
|
+
|
244
|
+
## License
|
245
|
+
|
246
|
+
Copyright (c) 2021 Nebulab SRLs, released under the New BSD License.
|
data/Rakefile
ADDED