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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +41 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.github_changelog_generator +2 -0
  6. data/.gitignore +20 -0
  7. data/.rspec +2 -0
  8. data/.rubocop.yml +12 -0
  9. data/Gemfile +33 -0
  10. data/LICENSE +26 -0
  11. data/README.md +246 -0
  12. data/Rakefile +6 -0
  13. data/app/assets/javascripts/spree/backend/solidus_feeds.js +2 -0
  14. data/app/assets/javascripts/spree/frontend/solidus_feeds.js +2 -0
  15. data/app/assets/stylesheets/spree/backend/solidus_feeds.css +4 -0
  16. data/app/assets/stylesheets/spree/frontend/solidus_feeds.css +4 -0
  17. data/bin/console +17 -0
  18. data/bin/rails +7 -0
  19. data/bin/rails-engine +13 -0
  20. data/bin/rails-sandbox +16 -0
  21. data/bin/rake +7 -0
  22. data/bin/sandbox +86 -0
  23. data/bin/setup +8 -0
  24. data/config/locales/en.yml +5 -0
  25. data/config/routes.rb +5 -0
  26. data/lib/generators/solidus_feeds/install/install_generator.rb +37 -0
  27. data/lib/generators/solidus_feeds/install/templates/initializer.rb +15 -0
  28. data/lib/solidus_feeds.rb +13 -0
  29. data/lib/solidus_feeds/configuration.rb +59 -0
  30. data/lib/solidus_feeds/engine.rb +19 -0
  31. data/lib/solidus_feeds/factories.rb +4 -0
  32. data/lib/solidus_feeds/feed.rb +21 -0
  33. data/lib/solidus_feeds/generators/google_merchant.rb +106 -0
  34. data/lib/solidus_feeds/publishers/s3.rb +30 -0
  35. data/lib/solidus_feeds/publishers/static_file.rb +17 -0
  36. data/lib/solidus_feeds/testing_support/factories.rb +4 -0
  37. data/lib/solidus_feeds/version.rb +5 -0
  38. data/solidus_feeds.gemspec +36 -0
  39. data/spec/lib/solidus_feeds/generators/google_merchant_spec.rb +132 -0
  40. data/spec/lib/solidus_feeds/publishers/s3_spec.rb +37 -0
  41. data/spec/lib/solidus_feeds/publishers/static_file_spec.rb +31 -0
  42. data/spec/lib/solidus_feeds/solidus_feeds_spec.rb +23 -0
  43. data/spec/solidus_feeds_spec.rb +29 -0
  44. data/spec/spec_helper.rb +31 -0
  45. metadata +157 -0
@@ -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,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__)
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if %w[g generate].include? ARGV.first
4
+ exec "#{__dir__}/rails-engine", *ARGV
5
+ else
6
+ exec "#{__dir__}/rails-sandbox", *ARGV
7
+ end
@@ -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'
@@ -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
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "rubygems"
5
+ require "bundler/setup"
6
+
7
+ load Gem.bin_path("rake", "rake")
@@ -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."
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ gem install bundler --conservative
7
+ bundle update
8
+ bin/rake clobber
@@ -0,0 +1,5 @@
1
+ # Sample localization file for English. Add more files in this directory for other locales.
2
+ # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3
+
4
+ en:
5
+ hello: Hello world
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ Spree::Core::Engine.routes.draw do
4
+ # Add your extension routes here
5
+ end
@@ -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,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ 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