pwinty 1.0.1
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/.gitignore +5 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +85 -0
- data/Rakefile +11 -0
- data/lib/multipart.rb +76 -0
- data/lib/pwinty.rb +81 -0
- data/lib/pwinty/version.rb +3 -0
- data/pwinty.gemspec +24 -0
- data/test/test_client.rb +116 -0
- data/test/test_helper.rb +5 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5e2d69fca32fe28bbe4ed607577ebae56276c63b
|
4
|
+
data.tar.gz: 71683c3aec6864253728421f3aad4c0848bea4cf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c7ade263209666875e70958004b94adddd09a50b73ddcecbce7d25c272450f03561c484fecc35256ac52efd86a9d300390d83614870a91ff261af72bad147bf8
|
7
|
+
data.tar.gz: 25b59d9c7fbc884b0520dc7c0b4a6004e5fd76e86e327785e878cbd252b0a10426a90d5ac544256791cf30567d8ea9b99e691cc5ba062e4f6c3ceabd0e9fe473
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# Pwinty [](http://travis-ci.org/dereklucas/pwinty?branch=master) [](https://gemnasium.com/dereklucas/pwinty)
|
2
|
+
|
3
|
+
This library implements a Ruby client for the [Pwinty photo printing API](http://www.pwinty.com/Api).
|
4
|
+
|
5
|
+
Documentation
|
6
|
+
-------------
|
7
|
+
|
8
|
+
Import pwinty and set your API Key and Merchent ID:
|
9
|
+
|
10
|
+
ENV['PWINTY_MERCHANT_ID'] = 'xxxxxxx'
|
11
|
+
ENV['PWINTY_API_KEY'] = 'xxxxxxx'
|
12
|
+
@client = Pwinty.client
|
13
|
+
|
14
|
+
Create an Order:
|
15
|
+
|
16
|
+
order = @client.Order.create_order(
|
17
|
+
recipientName: "FirstName LastName",
|
18
|
+
address1: "123 Anywhere Street",
|
19
|
+
addressTownOrCity: "San Francisco",
|
20
|
+
stateOrCounty: "CA",
|
21
|
+
postalOrZipCode: "94101",
|
22
|
+
countryCode: "US",
|
23
|
+
payment: "InvoiceMe",
|
24
|
+
qualityLevel: "Standard"
|
25
|
+
)
|
26
|
+
|
27
|
+
Add photos to the order:
|
28
|
+
|
29
|
+
photo = @client.add_photo(
|
30
|
+
orderId: order['id'],
|
31
|
+
type: "4x6",
|
32
|
+
url: "http://i.imgur.com/xXnrL.jpg",
|
33
|
+
copies: 1,
|
34
|
+
sizing: "Crop"
|
35
|
+
)
|
36
|
+
|
37
|
+
Check the order is valid:
|
38
|
+
|
39
|
+
order_status = @client.get_order_status(order['id'])
|
40
|
+
if !order_status['isValid']
|
41
|
+
puts "Invalid Order"
|
42
|
+
end
|
43
|
+
|
44
|
+
Submit the order:
|
45
|
+
|
46
|
+
response = @client.update_order_status(order['id'], "Submitted")
|
47
|
+
|
48
|
+
|
49
|
+
You can retrieve a previous order and check its status like so:
|
50
|
+
|
51
|
+
order = @client.get_order_status(8765)
|
52
|
+
if order['status'] == 'Complete'
|
53
|
+
puts "Order has dispatched"
|
54
|
+
end
|
55
|
+
|
56
|
+
You should find the documentation for Pwinty on [their API](https://pwinty.com/Api).
|
57
|
+
|
58
|
+
Install
|
59
|
+
--------
|
60
|
+
|
61
|
+
```shell
|
62
|
+
gem install pwinty
|
63
|
+
```
|
64
|
+
or add the following line to Gemfile:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
gem 'pwinty'
|
68
|
+
```
|
69
|
+
and run `bundle install` from your shell.
|
70
|
+
|
71
|
+
Supported Ruby versions
|
72
|
+
-----------------------
|
73
|
+
|
74
|
+
The Ruby Pwinty gem has only been tested on Ruby 2.
|
75
|
+
|
76
|
+
License
|
77
|
+
-------
|
78
|
+
|
79
|
+
MIT License
|
80
|
+
|
81
|
+
More Information
|
82
|
+
----------------
|
83
|
+
|
84
|
+
* [Rubygems](https://rubygems.org/gems/pwinty)
|
85
|
+
* [Issues](https://github.com/dereklucas/pwinty/issues)
|
data/Rakefile
ADDED
data/lib/multipart.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# License:: Distributed under the terms of the WTFPL (http://www.wtfpl.net/txt/copying/)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'mime/types'
|
5
|
+
require 'cgi'
|
6
|
+
|
7
|
+
|
8
|
+
module Multipart
|
9
|
+
VERSION = "1.0.0"
|
10
|
+
|
11
|
+
# Formats a given hash as a multipart form post
|
12
|
+
# If a hash value responds to :string or :read messages, then it is
|
13
|
+
# interpreted as a file and processed accordingly; otherwise, it is assumed
|
14
|
+
# to be a string
|
15
|
+
class Post
|
16
|
+
# We have to pretend we're a web browser...
|
17
|
+
USERAGENT = "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6"
|
18
|
+
BOUNDARY = "0123456789ABLEWASIEREISAWELBA9876543210"
|
19
|
+
CONTENT_TYPE = "multipart/form-data; boundary=#{ BOUNDARY }"
|
20
|
+
HEADER = { "Content-Type" => CONTENT_TYPE, "User-Agent" => USERAGENT }
|
21
|
+
|
22
|
+
def self.prepare_query(params)
|
23
|
+
fp = []
|
24
|
+
|
25
|
+
params.each do |k, v|
|
26
|
+
# Are we trying to make a file parameter?
|
27
|
+
if v.respond_to?(:path) and v.respond_to?(:read) then
|
28
|
+
fp.push(FileParam.new(k.to_s, v.path, v.read))
|
29
|
+
# We must be trying to make a regular parameter
|
30
|
+
else
|
31
|
+
fp.push(StringParam.new(k.to_s, v))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Assemble the request body using the special multipart format
|
36
|
+
query = fp.collect {|p| "--" + BOUNDARY + "\r\n" + p.to_multipart }.join("") + "--" + BOUNDARY + "--"
|
37
|
+
return query, HEADER
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Formats a basic string key/value pair for inclusion with a multipart post
|
44
|
+
class StringParam
|
45
|
+
attr_accessor :k, :v
|
46
|
+
|
47
|
+
def initialize(k, v)
|
48
|
+
@k = k
|
49
|
+
@v = v
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_multipart
|
53
|
+
return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"\r\n\r\n#{v}\r\n"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Formats the contents of a file or string for inclusion with a multipart
|
58
|
+
# form post
|
59
|
+
class FileParam
|
60
|
+
attr_accessor :k, :filename, :content
|
61
|
+
|
62
|
+
def initialize(k, filename, content)
|
63
|
+
@k = k
|
64
|
+
@filename = filename
|
65
|
+
@content = content
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_multipart
|
69
|
+
# If we can tell the possible mime-type from the filename, use the
|
70
|
+
# first in the list; otherwise, use "application/octet-stream"
|
71
|
+
mime_type = MIME::Types.type_for(filename)[0] || MIME::Types["application/octet-stream"][0]
|
72
|
+
return "Content-Disposition: form-data; name=\"#{CGI::escape(k)}\"; filename=\"#{ filename }\"\r\n" +
|
73
|
+
"Content-Type: #{ mime_type.simplified }\r\n\r\n#{ content }\r\n"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/pwinty.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require "pwinty/version"
|
2
|
+
require "multipart"
|
3
|
+
require "rest_client"
|
4
|
+
|
5
|
+
module Pwinty
|
6
|
+
|
7
|
+
def self.client
|
8
|
+
@@client ||= Pwinty::Client.new
|
9
|
+
@@client
|
10
|
+
end
|
11
|
+
|
12
|
+
class Client
|
13
|
+
def initialize
|
14
|
+
subdomain = ENV['PWINTY_PRODUCTION'] == 'true' ? "api" : "sandbox"
|
15
|
+
domain = "https://#{subdomain}.pwinty.com/v2.1"
|
16
|
+
|
17
|
+
@pwinty = RestClient::Resource.new(domain, :headers => {
|
18
|
+
"X-Pwinty-MerchantId" => ENV['PWINTY_MERCHANT_ID'],
|
19
|
+
"X-Pwinty-REST-API-Key" => ENV['PWINTY_API_KEY'],
|
20
|
+
'Accept' => 'application/json'
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
def catalog(countryCode: 'US', qualityLevel: 'Standard')
|
25
|
+
JSON.parse @pwinty["/Catalogue/#{countryCode}/#{qualityLevel}"].get
|
26
|
+
end
|
27
|
+
|
28
|
+
# Orders
|
29
|
+
def get_orders
|
30
|
+
JSON.parse @pwinty["/Orders"].get
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_order(**args)
|
34
|
+
JSON.parse @pwinty["/Orders"].post(args)
|
35
|
+
end
|
36
|
+
|
37
|
+
def update_order(**args)
|
38
|
+
JSON.parse @pwinty["/Orders/#{args[:id]}"].put(args)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Order Status
|
42
|
+
def get_order_status(id)
|
43
|
+
JSON.parse @pwinty["/Orders/#{id}/SubmissionStatus"].get
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_order_status(id, status)
|
47
|
+
JSON.parse @pwinty["/Orders/#{id}/Status"].post(status: status)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Order Photos
|
51
|
+
def get_photos(orderId)
|
52
|
+
JSON.parse @pwinty["/Orders/#{orderId}/Photos"].get
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_photo(orderId, photoId)
|
56
|
+
JSON.parse @pwinty["/Orders/#{orderId}/Photos/#{photoId}"].get
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def add_photo(**args)
|
61
|
+
headers = {}
|
62
|
+
orderId = args.delete(:orderId)
|
63
|
+
|
64
|
+
unless args[:file].nil?
|
65
|
+
args, headers = Multipart::Post.prepare_query(args)
|
66
|
+
end
|
67
|
+
|
68
|
+
JSON.parse @pwinty["/Orders/#{orderId}/Photos"].post(args, headers)
|
69
|
+
end
|
70
|
+
|
71
|
+
# post :add_photos, "/Orders/:orderId/Photos/Batch"
|
72
|
+
def delete_photo(orderId, photoId)
|
73
|
+
JSON.parse @pwinty["/Orders/#{orderId}/Photos/#{photoId}"].delete
|
74
|
+
end
|
75
|
+
|
76
|
+
# Countries
|
77
|
+
def countries
|
78
|
+
JSON.parse @pwinty["/Country"].get
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/pwinty.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "pwinty/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "pwinty"
|
7
|
+
s.version = Pwinty::VERSION
|
8
|
+
s.authors = ["Derek Lucas"]
|
9
|
+
s.email = ["d@derekplucas.com"]
|
10
|
+
s.homepage = "http://github.com/dereklucas/pwinty"
|
11
|
+
s.licenses = ['MIT']
|
12
|
+
s.summary = %q{A Ruby client for the Pwinty API}
|
13
|
+
s.description = %q{Order photo prints with Ruby}
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_development_dependency "rake"
|
21
|
+
s.add_development_dependency "test-unit"
|
22
|
+
s.add_development_dependency "dotenv"
|
23
|
+
s.add_runtime_dependency "rest-client", '~> 1.8'
|
24
|
+
end
|
data/test/test_client.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class TestClient < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@params = {
|
7
|
+
recipientName: "FirstName LastName",
|
8
|
+
address1: "123 Anywhere Street",
|
9
|
+
addressTownOrCity: "San Francisco",
|
10
|
+
stateOrCounty: "CA",
|
11
|
+
postalOrZipCode: "94101",
|
12
|
+
countryCode: "US",
|
13
|
+
payment: "InvoiceMe",
|
14
|
+
qualityLevel: "Standard"
|
15
|
+
}
|
16
|
+
|
17
|
+
@client = Pwinty.client
|
18
|
+
|
19
|
+
@order_keys = %w[ id status price
|
20
|
+
address1 address2
|
21
|
+
addressTownOrCity
|
22
|
+
countryCode
|
23
|
+
destinationCountryCode
|
24
|
+
errorMessage qualityLevel
|
25
|
+
payment paymentUrl
|
26
|
+
photos postalOrZipCode
|
27
|
+
recipientName shippingInfo
|
28
|
+
stateOrCounty ]
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_initialize
|
32
|
+
body = @client.catalog
|
33
|
+
assert_equal body.class, Hash
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_catalog_integration
|
37
|
+
body = @client.catalog
|
38
|
+
assert_equal body.class, Hash
|
39
|
+
assert_equal body["countryCode"], "US"
|
40
|
+
assert_equal body["qualityLevel"], "Standard"
|
41
|
+
assert_equal body["shippingRates"].class, Array
|
42
|
+
assert_equal body["items"].class, Array
|
43
|
+
end
|
44
|
+
def test_get_orders_integration
|
45
|
+
body = @client.get_orders
|
46
|
+
assert_equal body.class, Array
|
47
|
+
assert_equal body.first.keys.sort!, @order_keys.sort!
|
48
|
+
end
|
49
|
+
def test_countries_integration
|
50
|
+
body = @client.countries
|
51
|
+
keys = %w[ countryCode name
|
52
|
+
hasProducts errorMessage ]
|
53
|
+
|
54
|
+
assert_equal body.class, Array
|
55
|
+
assert_equal body.first.keys.sort!, keys.sort!
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_orders_integration
|
59
|
+
# create Order
|
60
|
+
body = @client.create_order(@params)
|
61
|
+
assert_equal body.keys.sort!, @order_keys.sort!
|
62
|
+
assert_equal body["postalOrZipCode"], "94101"
|
63
|
+
id = body["id"]
|
64
|
+
|
65
|
+
|
66
|
+
body = @client.update_order(id: id, recipientName: 'Travis CI', postalOrZipCode: '94102')
|
67
|
+
assert_equal body.keys.sort!, @order_keys.sort!
|
68
|
+
assert_equal body["postalOrZipCode"], "94102"
|
69
|
+
|
70
|
+
# add Photo to Order via URL
|
71
|
+
body = @client.add_photo(orderId: id,
|
72
|
+
type: "4x6",
|
73
|
+
url: "http://i.imgur.com/xXnrL.jpg",
|
74
|
+
copies: 1, sizing: "Crop")
|
75
|
+
photo_id = body['id']
|
76
|
+
first_photo = body
|
77
|
+
|
78
|
+
keys = %w[ id type url
|
79
|
+
status copies
|
80
|
+
sizing priceToUser
|
81
|
+
price md5Hash previewUrl
|
82
|
+
thumbnailUrl attributes
|
83
|
+
errorMessage ]
|
84
|
+
|
85
|
+
assert_equal body.keys.sort!, keys.sort!
|
86
|
+
|
87
|
+
# Check photo was uploaded
|
88
|
+
body = @client.get_photos(id)
|
89
|
+
assert_equal body.length, 1
|
90
|
+
assert_equal body.first, first_photo
|
91
|
+
|
92
|
+
# Check photo was uploaded
|
93
|
+
body = @client.get_photo(id, photo_id)
|
94
|
+
assert_equal body, first_photo
|
95
|
+
|
96
|
+
# Delete photo
|
97
|
+
body = @client.delete_photo(id, photo_id)
|
98
|
+
assert_equal body['errorMessage'], nil
|
99
|
+
|
100
|
+
# TODO: Need to add a photo via file
|
101
|
+
|
102
|
+
# get Order Status
|
103
|
+
body = @client.get_order_status(id)
|
104
|
+
keys = %w[id isValid generalErrors photos]
|
105
|
+
if body["error"]
|
106
|
+
assert body["error"].class, String
|
107
|
+
else
|
108
|
+
assert_equal body.keys.sort!, keys.sort!
|
109
|
+
end
|
110
|
+
|
111
|
+
# Cancel Order
|
112
|
+
body = @client.update_order_status(id, "Cancelled")
|
113
|
+
assert_equal body['errorMessage'], nil
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pwinty
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Derek Lucas
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: test-unit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dotenv
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rest-client
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.8'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.8'
|
69
|
+
description: Order photo prints with Ruby
|
70
|
+
email:
|
71
|
+
- d@derekplucas.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".travis.yml"
|
78
|
+
- Gemfile
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/multipart.rb
|
82
|
+
- lib/pwinty.rb
|
83
|
+
- lib/pwinty/version.rb
|
84
|
+
- pwinty.gemspec
|
85
|
+
- test/test_client.rb
|
86
|
+
- test/test_helper.rb
|
87
|
+
homepage: http://github.com/dereklucas/pwinty
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.2.2
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: A Ruby client for the Pwinty API
|
111
|
+
test_files:
|
112
|
+
- test/test_client.rb
|
113
|
+
- test/test_helper.rb
|
114
|
+
has_rdoc:
|