dcparker-shopify 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/LICENSE +0 -0
- data/Manifest +13 -0
- data/README +9 -0
- data/lib/shopify.rb +93 -0
- data/lib/shopify/address.rb +17 -0
- data/lib/shopify/order.rb +36 -0
- data/lib/shopify/product.rb +45 -0
- data/lib/shopify/sale.rb +11 -0
- data/lib/shopify/session.rb +83 -0
- data/lib/shopify/shop.rb +8 -0
- data/lib/shopify/site.rb +14 -0
- data/shopify.gemspec +37 -0
- metadata +100 -0
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
v0.1.0 First release, a rewrite of Shopify's own Rails plugin, turned into a gem with similar workings.
|
data/LICENSE
ADDED
File without changes
|
data/Manifest
ADDED
data/README
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Example Usage:
|
2
|
+
|
3
|
+
Shopify.current_session = Shopify::Session.new('store_name', 'api-key', 'api-secret')
|
4
|
+
Shopify.current_session.token = 'api-session-token'
|
5
|
+
Shopify.apply_current_session!
|
6
|
+
|
7
|
+
Shopify::Shop.current
|
8
|
+
Shopify::Product.find(:first)
|
9
|
+
Shopify::Order.find(:first)
|
data/lib/shopify.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module Shopify
|
2
|
+
autoload :Session, 'shopify/session'
|
3
|
+
autoload :Shop, 'shopify/shop'
|
4
|
+
autoload :Product, 'shopify/product'
|
5
|
+
autoload :Variant, 'shopify/product'
|
6
|
+
autoload :Image, 'shopify/product'
|
7
|
+
autoload :Order, 'shopify/order'
|
8
|
+
autoload :LineItem, 'shopify/order'
|
9
|
+
autoload :ShippingLine, 'shopify/order'
|
10
|
+
autoload :CustomCollection, 'shopify/order'
|
11
|
+
autoload :ShippingAddress, 'shopify/address'
|
12
|
+
autoload :BillingAddress, 'shopify/address'
|
13
|
+
autoload :Country, 'shopify/address'
|
14
|
+
autoload :Province, 'shopify/address'
|
15
|
+
autoload :Sale, 'shopify/sale'
|
16
|
+
autoload :Authorization, 'shopify/sale'
|
17
|
+
autoload :Payment, 'shopify/sale'
|
18
|
+
autoload :Page, 'shopify/site'
|
19
|
+
autoload :Blog, 'shopify/site'
|
20
|
+
autoload :Article, 'shopify/site'
|
21
|
+
|
22
|
+
class << self
|
23
|
+
attr_reader :key, :secret
|
24
|
+
|
25
|
+
# Lists the session stack.
|
26
|
+
def sessions
|
27
|
+
@sessions ||= []
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the last session on the sessions stack.
|
31
|
+
def current_session
|
32
|
+
sessions.last
|
33
|
+
end
|
34
|
+
|
35
|
+
# Sets the current_session / appends a session to the sessions stack.
|
36
|
+
def current_session=(session)
|
37
|
+
sessions << session
|
38
|
+
end
|
39
|
+
|
40
|
+
# Injects the generated site (with basic auth params) into the ActiveResource::Base subclasses.
|
41
|
+
def apply_current_session!
|
42
|
+
current_session.apply!
|
43
|
+
end
|
44
|
+
|
45
|
+
# Perform a block within a specific session, and reset the current session to the previous after execution.
|
46
|
+
def with_session(session,&block)
|
47
|
+
sessions << session
|
48
|
+
apply_current_session!
|
49
|
+
result = yield
|
50
|
+
sessions.pop
|
51
|
+
apply_current_session!
|
52
|
+
return result
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# To fix a silly bug in ActiveResource loading... :(
|
58
|
+
module Enumerable # :nodoc: all
|
59
|
+
def group_by
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Load ActiveResource
|
64
|
+
gem 'activeresource', '>= 2.1.0'
|
65
|
+
require 'active_resource'
|
66
|
+
module ActiveResource # :nodoc: all
|
67
|
+
class Base
|
68
|
+
class << self
|
69
|
+
def site
|
70
|
+
# Not using superclass_delegating_reader because don't want subclasses to modify superclass instance
|
71
|
+
#
|
72
|
+
# With superclass_delegating_reader
|
73
|
+
#
|
74
|
+
# Parent.site = 'http://anonymous@test.com'
|
75
|
+
# Subclass.site # => 'http://anonymous@test.com'
|
76
|
+
# Subclass.site.user = 'david'
|
77
|
+
# Parent.site # => 'http://david@test.com'
|
78
|
+
#
|
79
|
+
# Without superclass_delegating_reader (expected behaviour)
|
80
|
+
#
|
81
|
+
# Parent.site = 'http://anonymous@test.com'
|
82
|
+
# Subclass.site # => 'http://anonymous@test.com'
|
83
|
+
# Subclass.site.user = 'david' # => TypeError: can't modify frozen object
|
84
|
+
#
|
85
|
+
if defined?(@site)
|
86
|
+
@site
|
87
|
+
elsif superclass != Object && superclass.site
|
88
|
+
superclass.site.dup.freeze
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Shopify
|
2
|
+
class ShippingAddress < ActiveResource::Base
|
3
|
+
end
|
4
|
+
|
5
|
+
class BillingAddress < ActiveResource::Base
|
6
|
+
def name
|
7
|
+
"#{first_name} #{last_name}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Country < ActiveResource::Base
|
12
|
+
end
|
13
|
+
|
14
|
+
class Province < ActiveResource::Base
|
15
|
+
self.prefix = "/admin/countries/:country_id/"
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Shopify
|
2
|
+
class Order < ActiveResource::Base
|
3
|
+
def fulfilled?
|
4
|
+
!!fulfillment_status
|
5
|
+
end
|
6
|
+
|
7
|
+
def closed?
|
8
|
+
closed_at < Time.now
|
9
|
+
end
|
10
|
+
|
11
|
+
def close
|
12
|
+
load_attributes_from_response(post(:close))
|
13
|
+
end
|
14
|
+
|
15
|
+
def open
|
16
|
+
load_attributes_from_response(post(:open))
|
17
|
+
end
|
18
|
+
|
19
|
+
def payments
|
20
|
+
Payment.get
|
21
|
+
end
|
22
|
+
|
23
|
+
def capture(amount=nil)
|
24
|
+
load_attributes_from_response(post(:capture, :amount => amount))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class LineItem < ActiveResource::Base
|
29
|
+
end
|
30
|
+
|
31
|
+
class ShippingLine < ActiveResource::Base
|
32
|
+
end
|
33
|
+
|
34
|
+
class CustomCollection < ActiveResource::Base
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Shopify
|
2
|
+
class Product < ActiveResource::Base
|
3
|
+
class << self
|
4
|
+
# Share all items of this store with the shopify marketplace
|
5
|
+
def share_all
|
6
|
+
post :share
|
7
|
+
end
|
8
|
+
# Stop sharing all items of this store with the shopify marketplace
|
9
|
+
def unshare_all
|
10
|
+
delete :share
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Auto-compute the price range
|
15
|
+
def price_range
|
16
|
+
prices = variants.collect(&:price)
|
17
|
+
format = "%0.2f"
|
18
|
+
if prices.min != prices.max
|
19
|
+
"#{format % prices.min} - #{format % prices.max}"
|
20
|
+
else
|
21
|
+
format % prices.min
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Variant < ActiveResource::Base
|
27
|
+
self.prefix = "/admin/products/:product_id/"
|
28
|
+
end
|
29
|
+
|
30
|
+
class Image < ActiveResource::Base
|
31
|
+
self.prefix = "/admin/products/:product_id/"
|
32
|
+
|
33
|
+
# generate a method for each possible image variant
|
34
|
+
[:pico, :icon, :thumb, :small, :medium, :large, :original].each do |m|
|
35
|
+
reg_exp_match = "/\\1_#{m}.\\2"
|
36
|
+
define_method(m) { src.gsub(/\/(.*)\.(\w{2,4})/, reg_exp_match) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Attach an image to a product.
|
40
|
+
def attach_image(data, filename = nil)
|
41
|
+
attributes[:attachment] = Base64.encode64(data)
|
42
|
+
attributes[:filename] = filename unless filename.nil?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/shopify/sale.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Shopify
|
4
|
+
# Shopify Session
|
5
|
+
#
|
6
|
+
# Example:
|
7
|
+
# class LoginController < ApplicationController
|
8
|
+
# layout 'empty'
|
9
|
+
#
|
10
|
+
# before { Shopify.sessions << Shopify::Session.new(session[:store_name] || params[:store_name], session[:shopify_token], SHOPIFY_APP_SECRET) if Shopify.sessions.empty? && (session[:store_name] || params[:store_name]) }
|
11
|
+
#
|
12
|
+
# def signin
|
13
|
+
# # ask user for his myshopify.com address.
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # POST to this with the store name
|
17
|
+
# def login
|
18
|
+
# # Set the store_name into the session for future requests.
|
19
|
+
# session[:store_name] = params[:store_name]
|
20
|
+
# # This will redirect the user to their Shopify store to authorize your application.
|
21
|
+
# # Shopify will redirect the user back to your :finalize action when finished.
|
22
|
+
# redirect Shopify.current_session.permission_url
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# def finalize
|
26
|
+
# Shopify.current_session.token = params[:t]
|
27
|
+
# Shopify.apply_current_session!
|
28
|
+
# if Shopify.current_session.signed_in?
|
29
|
+
# redirect # logged in area
|
30
|
+
# else
|
31
|
+
# flash[:notice] = "Couldn't sign in to your shopify store."
|
32
|
+
# redirect url(:signin)
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
class Session
|
38
|
+
cattr_accessor :protocol
|
39
|
+
self.protocol = 'http'
|
40
|
+
|
41
|
+
attr_accessor :host, :key, :secret, :token
|
42
|
+
|
43
|
+
def initialize(host, key=nil, secret=nil, token=nil)
|
44
|
+
host.gsub!(/https?:\/\//, '') # remove http://
|
45
|
+
host = "#{host}.myshopify.com" unless host.include?('.') # extend url to myshopify.com if no host is given
|
46
|
+
|
47
|
+
self.host = host
|
48
|
+
self.key = key
|
49
|
+
self.secret = secret
|
50
|
+
self.token = token
|
51
|
+
end
|
52
|
+
|
53
|
+
# mode can be either r to request read rights or w to request read/write rights.
|
54
|
+
def permission_url(mode='w')
|
55
|
+
"http://#{host}/admin/api/auth?api_key=#{key}&mode=#{mode}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def apply!
|
59
|
+
ActiveResource::Base.site = site if signed_in?
|
60
|
+
end
|
61
|
+
|
62
|
+
# use this to initialize ActiveResource:
|
63
|
+
#
|
64
|
+
# ActiveResource::Base.site = Shopify.current_session.site
|
65
|
+
#
|
66
|
+
def site
|
67
|
+
"#{protocol}://#{key}:#{password}@#{host}/admin"
|
68
|
+
end
|
69
|
+
|
70
|
+
def signed_in?
|
71
|
+
[host, key, secret, token].all?
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# The secret is computed by taking the shared_secret which we got when
|
77
|
+
# registring this third party application and concating the request_to it,
|
78
|
+
# and then calculating a MD5 hexdigest.
|
79
|
+
def password
|
80
|
+
Digest::MD5.hexdigest("#{secret.chomp}#{token.chomp}")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/shopify/shop.rb
ADDED
data/lib/shopify/site.rb
ADDED
data/shopify.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{shopify}
|
5
|
+
s.version = "0.1.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Daniel Parker"]
|
9
|
+
s.date = %q{2008-12-10}
|
10
|
+
s.description = %q{Easily communicate with Shopify.com's restful API.}
|
11
|
+
s.email = %q{gems@behindlogic.com}
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "lib/shopify/address.rb", "lib/shopify/order.rb", "lib/shopify/product.rb", "lib/shopify/sale.rb", "lib/shopify/session.rb", "lib/shopify/shop.rb", "lib/shopify/site.rb", "lib/shopify.rb", "LICENSE", "README"]
|
13
|
+
s.files = ["CHANGELOG", "lib/shopify/address.rb", "lib/shopify/order.rb", "lib/shopify/product.rb", "lib/shopify/sale.rb", "lib/shopify/session.rb", "lib/shopify/shop.rb", "lib/shopify/site.rb", "lib/shopify.rb", "LICENSE", "Manifest", "README", "shopify.gemspec"]
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.homepage = %q{http://github.com/dcparker/shopify/tree}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Shopify", "--main", "README"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{shopify}
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
20
|
+
s.summary = %q{Easily communicate with Shopify.com's restful API.}
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 2
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_runtime_dependency(%q<activeresource>, [">= 0", "= 2.1.0"])
|
28
|
+
s.add_development_dependency(%q<echoe>, [">= 0"])
|
29
|
+
else
|
30
|
+
s.add_dependency(%q<activeresource>, [">= 0", "= 2.1.0"])
|
31
|
+
s.add_dependency(%q<echoe>, [">= 0"])
|
32
|
+
end
|
33
|
+
else
|
34
|
+
s.add_dependency(%q<activeresource>, [">= 0", "= 2.1.0"])
|
35
|
+
s.add_dependency(%q<echoe>, [">= 0"])
|
36
|
+
end
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dcparker-shopify
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Parker
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-12-10 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activeresource
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
- - "="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 2.1.0
|
26
|
+
version:
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: echoe
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
version:
|
36
|
+
description: Easily communicate with Shopify.com's restful API.
|
37
|
+
email: gems@behindlogic.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- CHANGELOG
|
44
|
+
- lib/shopify/address.rb
|
45
|
+
- lib/shopify/order.rb
|
46
|
+
- lib/shopify/product.rb
|
47
|
+
- lib/shopify/sale.rb
|
48
|
+
- lib/shopify/session.rb
|
49
|
+
- lib/shopify/shop.rb
|
50
|
+
- lib/shopify/site.rb
|
51
|
+
- lib/shopify.rb
|
52
|
+
- LICENSE
|
53
|
+
- README
|
54
|
+
files:
|
55
|
+
- CHANGELOG
|
56
|
+
- lib/shopify/address.rb
|
57
|
+
- lib/shopify/order.rb
|
58
|
+
- lib/shopify/product.rb
|
59
|
+
- lib/shopify/sale.rb
|
60
|
+
- lib/shopify/session.rb
|
61
|
+
- lib/shopify/shop.rb
|
62
|
+
- lib/shopify/site.rb
|
63
|
+
- lib/shopify.rb
|
64
|
+
- LICENSE
|
65
|
+
- Manifest
|
66
|
+
- README
|
67
|
+
- shopify.gemspec
|
68
|
+
has_rdoc: true
|
69
|
+
homepage: http://github.com/dcparker/shopify/tree
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options:
|
72
|
+
- --line-numbers
|
73
|
+
- --inline-source
|
74
|
+
- --title
|
75
|
+
- Shopify
|
76
|
+
- --main
|
77
|
+
- README
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: "0"
|
85
|
+
version:
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: "1.2"
|
91
|
+
version:
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project: shopify
|
95
|
+
rubygems_version: 1.2.0
|
96
|
+
signing_key:
|
97
|
+
specification_version: 2
|
98
|
+
summary: Easily communicate with Shopify.com's restful API.
|
99
|
+
test_files: []
|
100
|
+
|