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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/CHANGELOG.md +7 -0
  4. data/Gemfile +4 -0
  5. data/README.md +319 -0
  6. data/Rakefile +2 -0
  7. data/lib/passworks.rb +49 -0
  8. data/lib/passworks/asset_resource.rb +11 -0
  9. data/lib/passworks/campaign_resource.rb +40 -0
  10. data/lib/passworks/client.rb +53 -0
  11. data/lib/passworks/collection_proxy.rb +46 -0
  12. data/lib/passworks/configuration.rb +58 -0
  13. data/lib/passworks/exception.rb +5 -0
  14. data/lib/passworks/exceptions/bad_gateway.rb +8 -0
  15. data/lib/passworks/exceptions/bad_request.rb +8 -0
  16. data/lib/passworks/exceptions/enhance_your_calm.rb +9 -0
  17. data/lib/passworks/exceptions/file_not_found.rb +8 -0
  18. data/lib/passworks/exceptions/forbidden.rb +8 -0
  19. data/lib/passworks/exceptions/gateway_timeout.rb +8 -0
  20. data/lib/passworks/exceptions/internal_server_error.rb +8 -0
  21. data/lib/passworks/exceptions/method_not_allowed.rb +8 -0
  22. data/lib/passworks/exceptions/not_found.rb +8 -0
  23. data/lib/passworks/exceptions/not_implemented.rb +8 -0
  24. data/lib/passworks/exceptions/payment_required.rb +8 -0
  25. data/lib/passworks/exceptions/precondition_failed.rb +8 -0
  26. data/lib/passworks/exceptions/service_unavailable.rb +8 -0
  27. data/lib/passworks/exceptions/unauthorized.rb +8 -0
  28. data/lib/passworks/exceptions/unprocessable_entity.rb +8 -0
  29. data/lib/passworks/faraday/http_exception_middleware.rb +73 -0
  30. data/lib/passworks/inflector.rb +38 -0
  31. data/lib/passworks/pass_resource.rb +40 -0
  32. data/lib/passworks/request.rb +49 -0
  33. data/lib/passworks/request_proxy.rb +115 -0
  34. data/lib/passworks/resource.rb +18 -0
  35. data/lib/passworks/response.rb +56 -0
  36. data/lib/passworks/version.rb +3 -0
  37. data/passworks.gemspec +34 -0
  38. 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,5 @@
1
+ module Passworks
2
+ class Exception < ::StandardError
3
+ end
4
+ end
5
+ Dir[File.dirname(__FILE__) + "/exceptions/*.rb"].each { |file| require file }
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class BadGateway < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class BadRequest < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class EnhanceYourCalm < Exception
6
+ end
7
+ end
8
+ end
9
+
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class FileNotFound < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class Forbidden < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class GatewayTimeout < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class InternalServerError < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class MethodNotAllowed < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class NotFound < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class NotImplemented < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class PaymentRequired < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class PreconditionFailed < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class ServiceUnavailable < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class Unauthorized < Exception
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ require 'passworks/exception'
2
+
3
+ module Passworks
4
+ module Exceptions
5
+ class UnprocessableEntity < Exception
6
+ end
7
+ end
8
+ 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