solidus_feeds 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
data/bin/console
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require "bundler/setup"
|
6
|
+
require "solidus_feeds"
|
7
|
+
|
8
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
9
|
+
# with your gem easier. You can also use a different console, if you like.
|
10
|
+
$LOAD_PATH.unshift(*Dir["#{__dir__}/../app/*"])
|
11
|
+
|
12
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
13
|
+
# require "pry"
|
14
|
+
# Pry.start
|
15
|
+
|
16
|
+
require "irb"
|
17
|
+
IRB.start(__FILE__)
|
data/bin/rails
ADDED
data/bin/rails-engine
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails gems
|
3
|
+
# installed from the root of your application.
|
4
|
+
|
5
|
+
ENGINE_ROOT = File.expand_path('..', __dir__)
|
6
|
+
ENGINE_PATH = File.expand_path('../lib/solidus_feeds/engine', __dir__)
|
7
|
+
|
8
|
+
# Set up gems listed in the Gemfile.
|
9
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
10
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
11
|
+
|
12
|
+
require 'rails/all'
|
13
|
+
require 'rails/engine/commands'
|
data/bin/rails-sandbox
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
app_root = 'sandbox'
|
4
|
+
|
5
|
+
unless File.exist? "#{app_root}/bin/rails"
|
6
|
+
warn 'Creating the sandbox app...'
|
7
|
+
Dir.chdir "#{__dir__}/.." do
|
8
|
+
system "#{__dir__}/sandbox" or begin
|
9
|
+
warn 'Automatic creation of the sandbox app failed'
|
10
|
+
exit 1
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Dir.chdir app_root
|
16
|
+
exec 'bin/rails', *ARGV
|
data/bin/rake
ADDED
data/bin/sandbox
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
case "$DB" in
|
6
|
+
postgres|postgresql)
|
7
|
+
RAILSDB="postgresql"
|
8
|
+
;;
|
9
|
+
mysql)
|
10
|
+
RAILSDB="mysql"
|
11
|
+
;;
|
12
|
+
sqlite|'')
|
13
|
+
RAILSDB="sqlite3"
|
14
|
+
;;
|
15
|
+
*)
|
16
|
+
echo "Invalid DB specified: $DB"
|
17
|
+
exit 1
|
18
|
+
;;
|
19
|
+
esac
|
20
|
+
|
21
|
+
if [ ! -z $SOLIDUS_BRANCH ]
|
22
|
+
then
|
23
|
+
BRANCH=$SOLIDUS_BRANCH
|
24
|
+
else
|
25
|
+
BRANCH="master"
|
26
|
+
fi
|
27
|
+
|
28
|
+
extension_name="solidus_feeds"
|
29
|
+
|
30
|
+
# Stay away from the bundler env of the containing extension.
|
31
|
+
function unbundled {
|
32
|
+
ruby -rbundler -e'b = proc {system *ARGV}; Bundler.respond_to?(:with_unbundled_env) ? Bundler.with_unbundled_env(&b) : Bundler.with_clean_env(&b)' -- $@
|
33
|
+
}
|
34
|
+
|
35
|
+
rm -rf ./sandbox
|
36
|
+
unbundled bundle exec rails new sandbox --database="$RAILSDB" \
|
37
|
+
--skip-bundle \
|
38
|
+
--skip-git \
|
39
|
+
--skip-keeps \
|
40
|
+
--skip-rc \
|
41
|
+
--skip-spring \
|
42
|
+
--skip-test \
|
43
|
+
--skip-javascript
|
44
|
+
|
45
|
+
if [ ! -d "sandbox" ]; then
|
46
|
+
echo 'sandbox rails application failed'
|
47
|
+
exit 1
|
48
|
+
fi
|
49
|
+
|
50
|
+
cd ./sandbox
|
51
|
+
cat <<RUBY >> Gemfile
|
52
|
+
gem 'solidus', github: 'solidusio/solidus', branch: '$BRANCH'
|
53
|
+
gem 'solidus_auth_devise', '>= 2.1.0'
|
54
|
+
gem 'rails-i18n'
|
55
|
+
gem 'solidus_i18n'
|
56
|
+
|
57
|
+
gem '$extension_name', path: '..'
|
58
|
+
|
59
|
+
group :test, :development do
|
60
|
+
platforms :mri do
|
61
|
+
gem 'pry-byebug'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
RUBY
|
65
|
+
|
66
|
+
unbundled bundle install --gemfile Gemfile
|
67
|
+
|
68
|
+
unbundled bundle exec rake db:drop db:create
|
69
|
+
|
70
|
+
unbundled bundle exec rails generate spree:install \
|
71
|
+
--auto-accept \
|
72
|
+
--user_class=Spree::User \
|
73
|
+
--enforce_available_locales=true \
|
74
|
+
--with-authentication=false \
|
75
|
+
--payment-method=none \
|
76
|
+
$@
|
77
|
+
|
78
|
+
unbundled bundle exec rails generate solidus:auth:install
|
79
|
+
unbundled bundle exec rails generate ${extension_name}:install
|
80
|
+
|
81
|
+
echo
|
82
|
+
echo "🚀 Sandbox app successfully created for $extension_name!"
|
83
|
+
echo "🚀 Using $RAILSDB and Solidus $BRANCH"
|
84
|
+
echo "🚀 Use 'export DB=[postgres|mysql|sqlite]' to control the DB adapter"
|
85
|
+
echo "🚀 Use 'export SOLIDUS_BRANCH=<BRANCH-NAME>' to control the Solidus version"
|
86
|
+
echo "🚀 This app is intended for test purposes."
|
data/bin/setup
ADDED
data/config/routes.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusFeeds
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
class_option :auto_run_migrations, type: :boolean, default: false
|
7
|
+
source_root File.expand_path('templates', __dir__)
|
8
|
+
|
9
|
+
def copy_initializer
|
10
|
+
template 'initializer.rb', 'config/initializers/solidus_feeds.rb'
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_javascripts
|
14
|
+
append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/solidus_feeds\n"
|
15
|
+
append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_feeds\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_stylesheets
|
19
|
+
inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/solidus_feeds\n", before: %r{\*/}, verbose: true # rubocop:disable Layout/LineLength
|
20
|
+
inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_feeds\n", before: %r{\*/}, verbose: true # rubocop:disable Layout/LineLength
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_migrations
|
24
|
+
run 'bin/rails railties:install:migrations FROM=solidus_feeds'
|
25
|
+
end
|
26
|
+
|
27
|
+
def run_migrations
|
28
|
+
run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]')) # rubocop:disable Layout/LineLength
|
29
|
+
if run_migrations
|
30
|
+
run 'bin/rails db:migrate'
|
31
|
+
else
|
32
|
+
puts 'Skipping bin/rails db:migrate, don\'t forget to run it!' # rubocop:disable Rails/Output
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
SolidusFeeds.configure do |config|
|
4
|
+
# The store name appearing on the feeds
|
5
|
+
# config.title = 'My store name'
|
6
|
+
#
|
7
|
+
# The URL appearing on the feeds
|
8
|
+
# config.link = 'https://example.com'
|
9
|
+
#
|
10
|
+
# The description appearing on the feeds
|
11
|
+
# config.description = 'Find out about new products on https://example.com'
|
12
|
+
#
|
13
|
+
# The language of the feeds
|
14
|
+
# config.language = 'en-us'
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'solidus_core'
|
4
|
+
require 'solidus_support'
|
5
|
+
|
6
|
+
require 'solidus_feeds/configuration'
|
7
|
+
require 'solidus_feeds/version'
|
8
|
+
require 'solidus_feeds/engine'
|
9
|
+
|
10
|
+
require 'solidus_feeds/publishers/s3'
|
11
|
+
require 'solidus_feeds/publishers/static_file'
|
12
|
+
|
13
|
+
require 'solidus_feeds/generators/google_merchant'
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'solidus_feeds/feed'
|
4
|
+
|
5
|
+
module SolidusFeeds
|
6
|
+
class Configuration
|
7
|
+
# Define here the settings for this extensions, e.g.:
|
8
|
+
#
|
9
|
+
# attr_accessor :my_setting
|
10
|
+
|
11
|
+
def register(name, &builder)
|
12
|
+
feeds[name.to_sym] = Feed.new(&builder)
|
13
|
+
end
|
14
|
+
|
15
|
+
def find(name)
|
16
|
+
feeds.fetch(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def feeds
|
22
|
+
@feeds ||= {}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
attr_writer :title, :link, :description, :language
|
28
|
+
|
29
|
+
def configuration
|
30
|
+
@configuration ||= Configuration.new
|
31
|
+
end
|
32
|
+
|
33
|
+
alias config configuration
|
34
|
+
|
35
|
+
def reset_config!
|
36
|
+
@configuration
|
37
|
+
end
|
38
|
+
|
39
|
+
def configure
|
40
|
+
yield configuration
|
41
|
+
end
|
42
|
+
|
43
|
+
def title
|
44
|
+
@title ||= ::Spree::Store.default.name
|
45
|
+
end
|
46
|
+
|
47
|
+
def link
|
48
|
+
@link ||= "https://#{::Spree::Store.default.url}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def description
|
52
|
+
@description ||= "Find out about new products on https://#{::Spree::Store.default.url} first!"
|
53
|
+
end
|
54
|
+
|
55
|
+
def language
|
56
|
+
@language ||= 'en-us'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spree/core'
|
4
|
+
require 'solidus_feeds'
|
5
|
+
|
6
|
+
module SolidusFeeds
|
7
|
+
class Engine < Rails::Engine
|
8
|
+
include SolidusSupport::EngineExtensions
|
9
|
+
|
10
|
+
isolate_namespace ::Spree
|
11
|
+
|
12
|
+
engine_name 'solidus_feeds'
|
13
|
+
|
14
|
+
# use rspec for tests
|
15
|
+
config.generators do |g|
|
16
|
+
g.test_framework :rspec
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusFeeds
|
4
|
+
class Feed
|
5
|
+
attr_accessor :generator, :publisher
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
yield(self) if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate(output)
|
12
|
+
generator.call(output)
|
13
|
+
end
|
14
|
+
|
15
|
+
def publish
|
16
|
+
publisher.call do |output|
|
17
|
+
generate(output)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'builder'
|
4
|
+
|
5
|
+
module SolidusFeeds
|
6
|
+
module Generators
|
7
|
+
# The GoogleMerchant XML feed as described in https://support.google.com/merchants/answer/7052112.
|
8
|
+
class GoogleMerchant
|
9
|
+
attr_accessor :products, :host
|
10
|
+
|
11
|
+
def initialize(products, host:)
|
12
|
+
self.products = products
|
13
|
+
self.host = host
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(io)
|
17
|
+
builder = Builder::XmlMarkup.new(target: io, indent: 0)
|
18
|
+
render_template(builder)
|
19
|
+
end
|
20
|
+
|
21
|
+
def render_template(xml)
|
22
|
+
xml.rss version: "2.0", "xmlns:g" => "http://base.google.com/ns/1.0" do
|
23
|
+
xml.channel do
|
24
|
+
xml.title SolidusFeeds.title
|
25
|
+
xml.link SolidusFeeds.link
|
26
|
+
xml.description SolidusFeeds.description
|
27
|
+
xml.language SolidusFeeds.language
|
28
|
+
products.find_each do |product|
|
29
|
+
xml.item do
|
30
|
+
xml.tag! 'g:id', id(product)
|
31
|
+
xml.tag! 'g:title', title(product)
|
32
|
+
xml.tag! 'g:description', description(product)
|
33
|
+
xml.tag! 'g:link', link(product)
|
34
|
+
xml.tag! 'g:image_link', image_link(product)
|
35
|
+
xml.tag! 'g:condition', condition(product)
|
36
|
+
xml.tag! 'g:price', price(product)
|
37
|
+
xml.tag! 'g:availability', availability(product)
|
38
|
+
xml.tag! 'g:brand', brand(product)
|
39
|
+
xml.tag! 'g:mpn', mpn(product)
|
40
|
+
xml.tag! 'g:google_product_category', google_product_category_id(product)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def id(product)
|
48
|
+
product.id
|
49
|
+
end
|
50
|
+
|
51
|
+
def title(product)
|
52
|
+
product.name
|
53
|
+
end
|
54
|
+
|
55
|
+
def description(product)
|
56
|
+
product.description
|
57
|
+
end
|
58
|
+
|
59
|
+
def link(product)
|
60
|
+
spree_routes.product_url(product, host: host)
|
61
|
+
end
|
62
|
+
|
63
|
+
def image_link(product)
|
64
|
+
return unless product.images.any?
|
65
|
+
|
66
|
+
attachment_url = product.images.first.attachment.url(:large)
|
67
|
+
asset_host = ActionController::Base.asset_host || host
|
68
|
+
|
69
|
+
URI.join(asset_host, attachment_url).to_s
|
70
|
+
end
|
71
|
+
|
72
|
+
# Must be "new", "refurbished", or "used".
|
73
|
+
def condition(product)
|
74
|
+
product.property("condition") || "new"
|
75
|
+
end
|
76
|
+
|
77
|
+
def price(product)
|
78
|
+
::Spree::Money.new(product.price).money.format(symbol: false, with_currency: true)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Must be "in stock", "preorder" or "out of stock"
|
82
|
+
def availability(product)
|
83
|
+
product.master.in_stock? ? 'in stock' : 'out of stock'
|
84
|
+
end
|
85
|
+
|
86
|
+
def brand(product)
|
87
|
+
product.property("brand") || SolidusFeeds.title
|
88
|
+
end
|
89
|
+
|
90
|
+
def mpn(product)
|
91
|
+
product.master.sku
|
92
|
+
end
|
93
|
+
|
94
|
+
def google_product_category_id(product)
|
95
|
+
# Must be selected from https://support.google.com/merchants/answer/1705911
|
96
|
+
product.property("google_product_category_id")
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def spree_routes
|
102
|
+
@spree_routes ||= ::Spree::Core::Engine.routes.url_helpers
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|