passworks 0.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 +22 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +4 -0
- data/README.md +319 -0
- data/Rakefile +2 -0
- data/lib/passworks.rb +49 -0
- data/lib/passworks/asset_resource.rb +11 -0
- data/lib/passworks/campaign_resource.rb +40 -0
- data/lib/passworks/client.rb +53 -0
- data/lib/passworks/collection_proxy.rb +46 -0
- data/lib/passworks/configuration.rb +58 -0
- data/lib/passworks/exception.rb +5 -0
- data/lib/passworks/exceptions/bad_gateway.rb +8 -0
- data/lib/passworks/exceptions/bad_request.rb +8 -0
- data/lib/passworks/exceptions/enhance_your_calm.rb +9 -0
- data/lib/passworks/exceptions/file_not_found.rb +8 -0
- data/lib/passworks/exceptions/forbidden.rb +8 -0
- data/lib/passworks/exceptions/gateway_timeout.rb +8 -0
- data/lib/passworks/exceptions/internal_server_error.rb +8 -0
- data/lib/passworks/exceptions/method_not_allowed.rb +8 -0
- data/lib/passworks/exceptions/not_found.rb +8 -0
- data/lib/passworks/exceptions/not_implemented.rb +8 -0
- data/lib/passworks/exceptions/payment_required.rb +8 -0
- data/lib/passworks/exceptions/precondition_failed.rb +8 -0
- data/lib/passworks/exceptions/service_unavailable.rb +8 -0
- data/lib/passworks/exceptions/unauthorized.rb +8 -0
- data/lib/passworks/exceptions/unprocessable_entity.rb +8 -0
- data/lib/passworks/faraday/http_exception_middleware.rb +73 -0
- data/lib/passworks/inflector.rb +38 -0
- data/lib/passworks/pass_resource.rb +40 -0
- data/lib/passworks/request.rb +49 -0
- data/lib/passworks/request_proxy.rb +115 -0
- data/lib/passworks/resource.rb +18 -0
- data/lib/passworks/response.rb +56 -0
- data/lib/passworks/version.rb +3 -0
- data/passworks.gemspec +34 -0
- metadata +208 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
module Passworks
|
2
|
+
|
3
|
+
# Client is the HTTP API Wrapper to comunicate with the Passworks API
|
4
|
+
#
|
5
|
+
class Client
|
6
|
+
|
7
|
+
include Passworks::Configuration
|
8
|
+
include Passworks::Request
|
9
|
+
|
10
|
+
def initialize(params={})
|
11
|
+
Configuration::VALID_CONFIG_KEYS.each do |key|
|
12
|
+
self.instance_variable_set(:"@#{key}", params[key])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Check if the current {Client} instance options are equal to the passed ones
|
17
|
+
# @param options [Hash] options
|
18
|
+
# @return [Boolean]
|
19
|
+
def same_options?(options)
|
20
|
+
self.options == options
|
21
|
+
end
|
22
|
+
|
23
|
+
# @!method assets
|
24
|
+
# Allows to to access the Assets API
|
25
|
+
# @return [Passworks::RequestProxy]
|
26
|
+
# @!method boarding_passes
|
27
|
+
# Allows to to access the Boarding Pass API
|
28
|
+
# @return [Passworks::RequestProxy]
|
29
|
+
# @!method store_cards
|
30
|
+
# Allows to to access the Store Cards API
|
31
|
+
# @return [Passworks::RequestProxy]
|
32
|
+
# @!method coupons
|
33
|
+
# Allows to to access the Coupons API
|
34
|
+
# @return [Passworks::RequestProxy]
|
35
|
+
# @!method generics
|
36
|
+
# Allows to to access the Generic API
|
37
|
+
# @return [Passworks::RequestProxy]
|
38
|
+
|
39
|
+
%w(assets boarding_passes store_cards coupons generics).each do |collection_name|
|
40
|
+
define_method(collection_name) do
|
41
|
+
Passworks::RequestProxy.new(self, collection_name, nil)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def inspect
|
46
|
+
inspected = super
|
47
|
+
inspected.gsub!(/\@api_secret=(.+)/){ "@api_secret=\"**********\"" }
|
48
|
+
inspected
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'passworks/inflector'
|
2
|
+
|
3
|
+
module Passworks
|
4
|
+
class CollectionProxy
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
include Passworks::Inflector
|
8
|
+
|
9
|
+
attr_reader :collection_name, :collection_uuid, :client, :options
|
10
|
+
|
11
|
+
def initialize(client, collection_name, collection_uuid=nil, options={})
|
12
|
+
@collection_name = collection_name
|
13
|
+
@collection_uuid = collection_uuid
|
14
|
+
@client = client
|
15
|
+
@options = options
|
16
|
+
end
|
17
|
+
|
18
|
+
def each(&block)
|
19
|
+
next_page = nil
|
20
|
+
loop do
|
21
|
+
if next_page
|
22
|
+
response = client.get(collection_url, options.merge({query: {page: next_page}}))
|
23
|
+
else
|
24
|
+
response = client.get(collection_url, options)
|
25
|
+
end
|
26
|
+
response.data.each do |item_data|
|
27
|
+
yield resource_class.new(client, collection_name, item_data)
|
28
|
+
end
|
29
|
+
next_page = response.next_page
|
30
|
+
break if next_page.nil?
|
31
|
+
end
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def collection_url
|
38
|
+
if collection_uuid
|
39
|
+
"#{collection_name}/#{collection_uuid}/passes"
|
40
|
+
else
|
41
|
+
collection_name
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'passworks/version'
|
2
|
+
|
3
|
+
module Passworks
|
4
|
+
module Configuration
|
5
|
+
|
6
|
+
VALID_CONNECTION_KEYS = [:endpoint, :user_agent].freeze
|
7
|
+
|
8
|
+
VALID_OPTION_KEYS = [:api_username, :api_secret, :debug].freeze
|
9
|
+
|
10
|
+
# @!visibility private
|
11
|
+
VALID_CONFIG_KEYS = VALID_CONNECTION_KEYS + VALID_OPTION_KEYS
|
12
|
+
|
13
|
+
DEFAULT_ENDPOINT = 'https://api.passworks.io'
|
14
|
+
|
15
|
+
DEFAULT_USER_AGENT = "Passworks Ruby API Client/#{Passworks::VERSION} Ruby/#{RUBY_VERSION} Platform/#{RUBY_PLATFORM}"
|
16
|
+
|
17
|
+
attr_accessor *VALID_CONFIG_KEYS
|
18
|
+
|
19
|
+
def configure
|
20
|
+
yield self
|
21
|
+
end
|
22
|
+
|
23
|
+
def reset!
|
24
|
+
Configuration.default_options.each do |key, value|
|
25
|
+
self.instance_variable_set(:"@#{key}", value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def options
|
30
|
+
Configuration.default_options.keys.inject({}) do |hash, key|
|
31
|
+
hash[key] = self.instance_variable_get(:"@#{key}")
|
32
|
+
hash
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!visibility private
|
37
|
+
def self.default_options
|
38
|
+
@default_options ||= {
|
39
|
+
endpoint: ENV['PASSWORKS_ENDPOINT'] || DEFAULT_ENDPOINT ,
|
40
|
+
user_agent: ENV['PASSWORKS_USER_AGENT'] || DEFAULT_USER_AGENT ,
|
41
|
+
api_username: ENV['PASSWORKS_API_USERNAME'] ,
|
42
|
+
api_secret: ENV['PASSWORKS_API_SECRET'] ,
|
43
|
+
debug: false
|
44
|
+
}
|
45
|
+
end
|
46
|
+
# @return the endpoint address with API version appended
|
47
|
+
def endpoint
|
48
|
+
File.join(@endpoint, 'v1').to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
class << self
|
52
|
+
def extended(base)
|
53
|
+
base.reset!
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'passworks/exception'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
module Passworks
|
5
|
+
module Faraday
|
6
|
+
class HttpExceptionMiddleware < ::Faraday::Middleware
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
@app.call(env).on_complete do |response|
|
10
|
+
case response[:status].to_i
|
11
|
+
when 400
|
12
|
+
raise Passworks::Exceptions::BadRequest, error_400(response)
|
13
|
+
when 401
|
14
|
+
raise Passworks::Exceptions::Unauthorized, error_400(response)
|
15
|
+
when 402
|
16
|
+
raise Passworks::Exceptions::PaymentRequired, error_400(response)
|
17
|
+
when 403
|
18
|
+
raise Passworks::Exceptions::Forbidden, error_400(response)
|
19
|
+
when 404
|
20
|
+
raise Passworks::Exceptions::NotFound, error_400(response)
|
21
|
+
when 405
|
22
|
+
raise Passworks::Exceptions::MethodNotAllowed, error_400(response)
|
23
|
+
when 412
|
24
|
+
raise Passworks::Exceptions::PreconditionFailed, error_400(response)
|
25
|
+
when 420
|
26
|
+
raise Passworks::Exceptions::EnhanceYourCalm, error_400(response)
|
27
|
+
when 422
|
28
|
+
raise Passworks::Exceptions::UnprocessableEntity, error_400(response)
|
29
|
+
when 500
|
30
|
+
raise Passworks::Exceptions::InternalServerError, error_500(response, 'Internal Server Error' , 'The server encountered an unexpected condition which prevented it from fulfilling the request.')
|
31
|
+
when 501
|
32
|
+
raise Passworks::Exceptions::NotImplemented, error_500(response, 'Not Implemented' , 'Current method not implemented.')
|
33
|
+
when 502
|
34
|
+
raise Passworks::Exceptions::BadGateway, error_500(response, 'Bad Gateway', 'The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request.')
|
35
|
+
when 503
|
36
|
+
raise Passworks::Exceptions::ServiceUnavailable, error_500(response, 'Service Unavailable', 'The server is currently unable to handle the request due to a temporary overloading or maintenance of the server.')
|
37
|
+
when 504
|
38
|
+
raise Passworks::Exceptions::GatewayTimeout, error_500(response, 'Gateway Timeout', 'The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI.')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(app)
|
44
|
+
super
|
45
|
+
@parser = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def error_400(response)
|
50
|
+
"#{response[:method].to_s.upcase} #{response[:url].to_s}: #{response[:status]} - #{error_body(response)}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def error_500(response, short_description, long_description)
|
54
|
+
end
|
55
|
+
|
56
|
+
# {"status_code"=>412, "error_code"=>10103, "message"=>"Asset in use by 1 templates, e.g.: Cocacola"}
|
57
|
+
def error_body(response)
|
58
|
+
body = response[:body]
|
59
|
+
# body gets passed as a string, not sure if it is passed as something else from other spots?
|
60
|
+
if not body.nil? and not body.empty? and body.kind_of?(String)
|
61
|
+
body = ::JSON.parse(body)
|
62
|
+
end
|
63
|
+
|
64
|
+
if body.nil?
|
65
|
+
nil
|
66
|
+
elsif body['message']
|
67
|
+
"(#{body['error_code']}) #{body['message']}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Passworks
|
2
|
+
module Inflector
|
3
|
+
|
4
|
+
# Return the singular version of the *curren_collection* name
|
5
|
+
# @return [String] singular version of the current collection name
|
6
|
+
def single_name
|
7
|
+
case collection_name
|
8
|
+
when 'assets'
|
9
|
+
'asset'
|
10
|
+
when 'boarding_passes'
|
11
|
+
'boarding_pass'
|
12
|
+
when 'coupons'
|
13
|
+
'coupon'
|
14
|
+
when 'store_cards'
|
15
|
+
'store_card'
|
16
|
+
when 'event_tickets'
|
17
|
+
'event_ticket'
|
18
|
+
when 'generics'
|
19
|
+
'generic'
|
20
|
+
else
|
21
|
+
raise 'Invalid Collection Name'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return resource class based in collection_name and collection_uuid
|
26
|
+
# If collection_name return [Passworks::AssetResource]
|
27
|
+
# If collection_uuid == nil return [Passworks::CampaignResource] else return [Passworks::PassResource]
|
28
|
+
def resource_class
|
29
|
+
return Passworks::AssetResource if collection_name == 'assets'
|
30
|
+
if collection_uuid
|
31
|
+
Passworks::PassResource
|
32
|
+
else
|
33
|
+
Passworks::CampaignResource
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'passworks/resource'
|
2
|
+
|
3
|
+
module Passworks
|
4
|
+
|
5
|
+
# Represents a Pass of a given collection type Coupon, Boarding Pass, Event Ticket, Generic, Store Card
|
6
|
+
#
|
7
|
+
class PassResource < Resource
|
8
|
+
|
9
|
+
# Deletes the current pass
|
10
|
+
# @return [Boolean] True in case the pass is deleted
|
11
|
+
def delete
|
12
|
+
client.delete("#{collection_name}/#{collection_uuid}/passes/#{id}").ok?
|
13
|
+
end
|
14
|
+
|
15
|
+
# Sends a push notification to all clients with this pass installed
|
16
|
+
# @return [Boolean] True in case the pass
|
17
|
+
def push
|
18
|
+
client.post("#{collection_name}/#{collection_uuid}/passes/#{id}/push").ok?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Updates the {PassResource} and returns the updated instance
|
22
|
+
# @return [PassResource] Updated instance
|
23
|
+
def update(data, params={})
|
24
|
+
content = {
|
25
|
+
body: {
|
26
|
+
pass: data
|
27
|
+
}.merge(params)
|
28
|
+
}
|
29
|
+
response = client.patch("#{collection_name}/#{collection_uuid}/passes/#{id}", content)
|
30
|
+
self.class.new(client, collection_name, response.data)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def collection_uuid
|
35
|
+
@collection_uuid ||= send("#{single_name}_id")
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|