moonclerk 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 +9 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/README.md +118 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/moonclerk.rb +110 -0
- data/lib/moonclerk/api_operations/list.rb +40 -0
- data/lib/moonclerk/api_operations/request.rb +30 -0
- data/lib/moonclerk/api_resource.rb +42 -0
- data/lib/moonclerk/customer.rb +11 -0
- data/lib/moonclerk/errors/api_error.rb +4 -0
- data/lib/moonclerk/errors/authentication_error.rb +4 -0
- data/lib/moonclerk/errors/invalid_request_error.rb +10 -0
- data/lib/moonclerk/errors/moonclerk_error.rb +26 -0
- data/lib/moonclerk/form.rb +5 -0
- data/lib/moonclerk/list_object.rb +98 -0
- data/lib/moonclerk/moonclerk_object.rb +309 -0
- data/lib/moonclerk/payment.rb +10 -0
- data/lib/moonclerk/util.rb +49 -0
- data/lib/moonclerk/version.rb +3 -0
- data/moonclerk.gemspec +34 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +26 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/models/moonclerk/customer_spec.rb +8 -0
- data/spec/moonclerk_spec.rb +7 -0
- data/spec/spec_helper.rb +63 -0
- metadata +314 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 93079434871ea140ae8925cb37243440f8462638
|
4
|
+
data.tar.gz: 3d8609c53bbf2fe1a9d40f420da14e5cd3c51455
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ed0e29fd060f41e5a43fcaa5baedbb58fe794a3b434857ca70e69c7fb22f78a00bc7dd52429fce2395e8752c0736f32899816bcf230ad5cdd4046c692fd08e1d
|
7
|
+
data.tar.gz: 7cb7b79a8bbd4168bc505be6e5b65309fe78b76424f22fff4898c9b44238dfc003a15f9b2f304db0de5b4c5ffae9956ff3c7d49baad095b50a39166bb943adc7
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# Moonclerk
|
2
|
+
|
3
|
+
Moonclerk is a Ruby wrapper around Moonclerk's read-only REST API.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'moonclerk'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install moonclerk
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Set your API key in an initializer (e.g. `config/initializers/moonclerk.rb`):
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
Moonclerk.api_key = "<API-KEY>"
|
27
|
+
```
|
28
|
+
|
29
|
+
### All
|
30
|
+
|
31
|
+
All objects have `find` and `list`, and some have `where` which allows filtering on certain attributes. For any `list` or `where` call, `next_page` and `previous_page` can be used to traverse the results returned from the API:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
Moonclerk::Customer.list.next_page
|
35
|
+
```
|
36
|
+
|
37
|
+
### Customers (known as "Plans" in the MoonClerk UI)
|
38
|
+
|
39
|
+
To retrieve a customer:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
Moonclerk::Customer.retrieve(id) # or Moonclerk::Customer.find(id)
|
43
|
+
```
|
44
|
+
|
45
|
+
To list customers:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
Moonclerk::Customer.list # or Moonclerk::Customer.all
|
49
|
+
|
50
|
+
# Options include count and offset
|
51
|
+
# NOTE: Count defaults to 10 (max is 100), and offset defaults to 0
|
52
|
+
```
|
53
|
+
|
54
|
+
To filter customers:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
Moonclerk::Customer.where(status: "active")
|
58
|
+
|
59
|
+
# Options include form_id, checkout_from, checkout_to, next_payment_from, next_payment_to, status, count, offset
|
60
|
+
# NOTE: Any parameter ending in _from or _to is expected to be a Date, Time or DateTime
|
61
|
+
# NOTE: Count defaults to 10 (max is 100), and offset defaults to 0
|
62
|
+
```
|
63
|
+
|
64
|
+
### Forms
|
65
|
+
|
66
|
+
To retrieve a form:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
Moonclerk::Form.retrieve(id) # or Moonclerk::Form.find(id)
|
70
|
+
```
|
71
|
+
|
72
|
+
To list forms:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
Moonclerk::Form.list # or Moonclerk::Form.all
|
76
|
+
|
77
|
+
# Options include count and offset
|
78
|
+
# NOTE: Count defaults to 10 (max is 100), and offset defaults to 0
|
79
|
+
```
|
80
|
+
|
81
|
+
### Payments
|
82
|
+
|
83
|
+
To retrieve a payment:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
Moonclerk::Payment.retrieve(id) # or Moonclerk::Payment.find(id)
|
87
|
+
```
|
88
|
+
|
89
|
+
To list payments:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
Moonclerk::Payment.list # or Moonclerk::Payment.all
|
93
|
+
|
94
|
+
# Options include count and offset
|
95
|
+
# NOTE: Count defaults to 10 (max is 100), and offset defaults to 0
|
96
|
+
```
|
97
|
+
|
98
|
+
To filter payments:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
Moonclerk::Payment.where(status: "active")
|
102
|
+
|
103
|
+
# Options include form_id, customer_id, date_from, date_to, status, count, offset
|
104
|
+
# NOTE: Any parameter ending in _from or _to is expected to be a Date, Time or DateTime
|
105
|
+
# NOTE: Count defaults to 10 (max is 100), and offset defaults to 0
|
106
|
+
```
|
107
|
+
|
108
|
+
## Development
|
109
|
+
|
110
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
111
|
+
|
112
|
+
## Contributing
|
113
|
+
|
114
|
+
1. Fork it ( https://github.com/[my-github-username]/moonclerk/fork )
|
115
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
116
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
117
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
118
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "moonclerk"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
require "pry"
|
11
|
+
Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/moonclerk.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
# Version
|
5
|
+
require "moonclerk/version"
|
6
|
+
|
7
|
+
# API Operations
|
8
|
+
require "moonclerk/api_operations/list"
|
9
|
+
require "moonclerk/api_operations/request"
|
10
|
+
|
11
|
+
# Resources
|
12
|
+
require "moonclerk/moonclerk_object"
|
13
|
+
require "moonclerk/api_resource"
|
14
|
+
require "moonclerk/list_object"
|
15
|
+
require "moonclerk/customer"
|
16
|
+
require "moonclerk/form"
|
17
|
+
require "moonclerk/payment"
|
18
|
+
require "moonclerk/util"
|
19
|
+
|
20
|
+
# Errors
|
21
|
+
require "moonclerk/errors/moonclerk_error"
|
22
|
+
require "moonclerk/errors/api_error"
|
23
|
+
require "moonclerk/errors/authentication_error"
|
24
|
+
require "moonclerk/errors/invalid_request_error"
|
25
|
+
|
26
|
+
module Moonclerk
|
27
|
+
API_BASE = "https://api.moonclerk.com"
|
28
|
+
API_VERSION = 1
|
29
|
+
|
30
|
+
class << self
|
31
|
+
attr_accessor :api_key
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.request(method, url, params = {})
|
35
|
+
unless api_key
|
36
|
+
raise AuthenticationError.new('No API key provided. ' \
|
37
|
+
'Set your API key using "Moonclerk.api_key = <API-KEY>". ' \
|
38
|
+
'You can generate API keys from the Moonclerk web interface' \
|
39
|
+
'by logging in at moonclerk.com.')
|
40
|
+
end
|
41
|
+
|
42
|
+
if api_key =~ /\s/
|
43
|
+
raise AuthenticationError.new('Your API key is invalid, as it contains ' \
|
44
|
+
'whitespace. (HINT: You can double-check your API key from the ' \
|
45
|
+
'MoonClerk web interface by logging in at moonclerk.com.)')
|
46
|
+
end
|
47
|
+
|
48
|
+
connection = Faraday.new
|
49
|
+
response = connection.send(method, url, params, headers)
|
50
|
+
parsed_response = JSON.parse(response.body)
|
51
|
+
symbolized_response = Util.symbolize_names(parsed_response)
|
52
|
+
|
53
|
+
if symbolized_response[:error]
|
54
|
+
handle_api_error(response)
|
55
|
+
else
|
56
|
+
symbolized_response[symbolized_response.keys.first]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.headers
|
61
|
+
{
|
62
|
+
"Authorization" => "Token token=#{api_key}",
|
63
|
+
"Accept" => "application/vnd.moonclerk+json;version=#{API_VERSION}"
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.default_param_keys
|
68
|
+
[:count, :offset]
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.general_api_error(status, response_body)
|
72
|
+
APIError.new("Invalid response object from API: #{response_body.inspect} " +
|
73
|
+
"(HTTP response code was #{status})", status, response_body)
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.handle_api_error(response)
|
77
|
+
begin
|
78
|
+
error_obj = JSON.parse(response.body)
|
79
|
+
error_obj = Util.symbolize_names(error_obj)
|
80
|
+
error = error_obj[:error]
|
81
|
+
raise MoonclerkError.new unless error && error.is_a?(Hash)
|
82
|
+
|
83
|
+
rescue JSON::ParserError, StripeError
|
84
|
+
raise general_api_error(response.status, response.body)
|
85
|
+
end
|
86
|
+
|
87
|
+
case response.status
|
88
|
+
when 400, 404
|
89
|
+
raise invalid_request_error(error, response, error_obj)
|
90
|
+
when 401
|
91
|
+
raise authentication_error(error, response, error_obj)
|
92
|
+
else
|
93
|
+
raise api_error(error, response, error_obj)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.invalid_request_error(error, response, error_obj)
|
98
|
+
InvalidRequestError.new(error[:message], response.status, response.body, error_obj,
|
99
|
+
response.headers)
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.authentication_error(error, response, error_obj)
|
103
|
+
AuthenticationError.new(error[:message], response.status, response.body, error_obj,
|
104
|
+
response.headers)
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.api_error(error, response, error_obj)
|
108
|
+
APIError.new(error[:message], response.status, response.body, error_obj, response.headers)
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Moonclerk
|
2
|
+
module APIOperations
|
3
|
+
module List
|
4
|
+
def list(params = {})
|
5
|
+
response = request(:get, url, params)
|
6
|
+
|
7
|
+
klass = self.is_a?(Moonclerk::ListObject) ? self[:object] : self.class_name.downcase
|
8
|
+
obj = ListObject.construct_from({ data: response, object: klass })
|
9
|
+
|
10
|
+
# Set a count and offset so that we can fetch the same number when accessing the
|
11
|
+
# next and previous pages
|
12
|
+
obj.count = params[:count]
|
13
|
+
obj.offset = params[:offset]
|
14
|
+
|
15
|
+
obj
|
16
|
+
end
|
17
|
+
|
18
|
+
# This method returns a page of objects, so #all
|
19
|
+
# is not an appropriate method name, but it is
|
20
|
+
# aliased for convenience.
|
21
|
+
alias :all :list
|
22
|
+
|
23
|
+
def where(options = {})
|
24
|
+
options = Util.symbolize_names(options)
|
25
|
+
params = {}
|
26
|
+
(@permitted_attributes + default_param_keys).each do |key|
|
27
|
+
if options[key]
|
28
|
+
if key.to_s.split("_").last =~ /from|to/
|
29
|
+
params[key] = CGI.escape(options[key].strftime("%Y-%m-%d"))
|
30
|
+
else
|
31
|
+
params[key] = CGI.escape(options[key].to_s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
list(params)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Moonclerk
|
2
|
+
module APIOperations
|
3
|
+
module Request
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
def request(method, url, params = {})
|
7
|
+
Moonclerk.request(method, url, params)
|
8
|
+
end
|
9
|
+
|
10
|
+
def default_param_keys
|
11
|
+
Moonclerk.default_param_keys
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.included(base)
|
16
|
+
base.extend(ClassMethods)
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def request(method, url, params = {})
|
22
|
+
self.class.request(method, url, params)
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_param_keys
|
26
|
+
self.class.default_param_keys
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Moonclerk
|
2
|
+
class APIResource < MoonclerkObject
|
3
|
+
include Moonclerk::APIOperations::Request
|
4
|
+
|
5
|
+
def self.class_name
|
6
|
+
self.name.split('::')[-1]
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.url
|
10
|
+
if self == APIResource
|
11
|
+
raise NotImplementedError.new('APIResource is an abstract class. You should perform actions on its subclasses (Customer, Payment, etc.)')
|
12
|
+
end
|
13
|
+
"#{API_BASE}/#{CGI.escape(class_name.downcase)}s"
|
14
|
+
end
|
15
|
+
|
16
|
+
def url
|
17
|
+
if self.is_a?(Moonclerk::ListObject)
|
18
|
+
return "#{API_BASE}/#{CGI.escape(self[:object])}s"
|
19
|
+
end
|
20
|
+
|
21
|
+
unless id = self['id']
|
22
|
+
raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", 'id')
|
23
|
+
end
|
24
|
+
"#{self.class.url}/#{CGI.escape(id)}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def refresh
|
28
|
+
response = request(:get, url, @retrieve_params)
|
29
|
+
refresh_from(response)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.retrieve(id)
|
33
|
+
instance = self.new(id.to_s)
|
34
|
+
instance.refresh
|
35
|
+
instance
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.find(id)
|
39
|
+
self.retrieve(id)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Moonclerk
|
2
|
+
class InvalidRequestError < MoonclerkError
|
3
|
+
attr_accessor :param
|
4
|
+
|
5
|
+
def initialize(message, http_status=nil, http_body=nil, json_body=nil,
|
6
|
+
http_headers=nil)
|
7
|
+
super(message, http_status, http_body, json_body, http_headers)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Moonclerk
|
2
|
+
class MoonclerkError < StandardError
|
3
|
+
attr_reader :message
|
4
|
+
attr_reader :http_status
|
5
|
+
attr_reader :http_body
|
6
|
+
attr_reader :http_headers
|
7
|
+
attr_reader :request_id
|
8
|
+
attr_reader :json_body
|
9
|
+
|
10
|
+
def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil,
|
11
|
+
http_headers=nil)
|
12
|
+
@message = message
|
13
|
+
@http_status = http_status
|
14
|
+
@http_body = http_body
|
15
|
+
@http_headers = http_headers || {}
|
16
|
+
@json_body = json_body
|
17
|
+
@request_id = @http_headers["x-request-id"]
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
|
22
|
+
id_string = @request_id.nil? ? "" : "(Request #{@request_id}) "
|
23
|
+
"#{status_string}#{id_string}#{@message}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|