cloudconvert 0.0.5 → 1.0.0
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 +5 -5
- data/LICENSE.txt +17 -18
- data/README.md +234 -39
- data/cloudconvert.gemspec +34 -22
- data/lib/cloudconvert.rb +33 -10
- data/lib/cloudconvert/base.rb +173 -0
- data/lib/cloudconvert/client.rb +107 -0
- data/lib/cloudconvert/collection.rb +15 -0
- data/lib/cloudconvert/entity.rb +21 -0
- data/lib/cloudconvert/error.rb +108 -0
- data/lib/cloudconvert/event.rb +14 -0
- data/lib/cloudconvert/file.rb +9 -0
- data/lib/cloudconvert/job.rb +18 -0
- data/lib/cloudconvert/middleware.rb +9 -0
- data/lib/cloudconvert/resource.rb +9 -0
- data/lib/cloudconvert/resources/jobs.rb +54 -0
- data/lib/cloudconvert/resources/tasks.rb +80 -0
- data/lib/cloudconvert/resources/users.rb +10 -0
- data/lib/cloudconvert/task.rb +43 -0
- data/lib/cloudconvert/user.rb +18 -0
- data/lib/cloudconvert/version.rb +2 -2
- data/lib/cloudconvert/webhook.rb +54 -0
- data/lib/cloudconvert/webhook/processor.rb +29 -0
- metadata +303 -24
- data/.gitignore +0 -21
- data/Gemfile +0 -7
- data/Rakefile +0 -1
- data/lib/cloudconvert/configuration.rb +0 -21
- data/lib/cloudconvert/conversion.rb +0 -105
@@ -0,0 +1,173 @@
|
|
1
|
+
module CloudConvert
|
2
|
+
class Base
|
3
|
+
extend Forwardable
|
4
|
+
include Memoizable
|
5
|
+
# @return [Hash]
|
6
|
+
attr_reader :attrs
|
7
|
+
alias to_h attrs
|
8
|
+
alias to_hash to_h
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Define methods that retrieve the value from attributes
|
12
|
+
#
|
13
|
+
# @param attrs [Array, Symbol]
|
14
|
+
def attr_reader(*attrs)
|
15
|
+
attrs.each do |attr|
|
16
|
+
define_attribute_method(attr)
|
17
|
+
define_predicate_method(attr)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Define collection methods from attributes
|
22
|
+
#
|
23
|
+
# @param klass [Symbol]
|
24
|
+
# @param attrs [Array, Symbol]
|
25
|
+
def collection_attr_reader(klass, *attrs)
|
26
|
+
attrs.each do |attr|
|
27
|
+
define_collection_method(attr, klass)
|
28
|
+
define_predicate_method(attr)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Define object methods from attributes
|
33
|
+
#
|
34
|
+
# @param klass [Symbol]
|
35
|
+
# @param attrs [Array, Symbol]
|
36
|
+
def object_attr_reader(klass, *attrs)
|
37
|
+
attrs.each do |attr|
|
38
|
+
define_object_method(attr, klass)
|
39
|
+
define_predicate_method(attr)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Define predicate methods from attributes
|
44
|
+
#
|
45
|
+
# @param attrs [Array, Symbol]
|
46
|
+
def predicate_attr_reader(*attrs)
|
47
|
+
attrs.each do |attr|
|
48
|
+
define_predicate_method(attr)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Define struct methods from attributes
|
53
|
+
#
|
54
|
+
# @param attrs [Array, Symbol]
|
55
|
+
def struct_attr_reader(*attrs)
|
56
|
+
attrs.each do |attr|
|
57
|
+
define_struct_method(attr)
|
58
|
+
define_predicate_method(attr)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Define symbol methods from attributes
|
63
|
+
#
|
64
|
+
# @param attrs [Array, Symbol]
|
65
|
+
def symbol_attr_reader(*attrs)
|
66
|
+
attrs.each do |attr|
|
67
|
+
define_symbol_method(attr)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Define time methods from attributes
|
72
|
+
#
|
73
|
+
# @param attrs [Array, Symbol]
|
74
|
+
def time_attr_reader(*attrs)
|
75
|
+
attrs.each do |attr|
|
76
|
+
define_time_method(attr)
|
77
|
+
define_predicate_method(attr.to_s.gsub(/_at$/, ""), attr)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
# Dynamically define a method for an attribute
|
84
|
+
#
|
85
|
+
# @param key [Symbol]
|
86
|
+
# @param klass [Symbol]
|
87
|
+
def define_attribute_method(key)
|
88
|
+
define_method(key) do
|
89
|
+
@attrs[key]
|
90
|
+
end
|
91
|
+
memoize(key)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Dynamically define a collection method for an attribute
|
95
|
+
#
|
96
|
+
# @param key [Symbol]
|
97
|
+
# @param klass [Symbol]
|
98
|
+
def define_collection_method(key, klass)
|
99
|
+
define_method(key) do
|
100
|
+
collection = @attrs[key] || []
|
101
|
+
entity = CloudConvert.const_get(klass)
|
102
|
+
Collection.new collection.map { |item| entity.new(item) }
|
103
|
+
end
|
104
|
+
memoize(key)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Dynamically define a predicate method for an attribute
|
108
|
+
#
|
109
|
+
# @param key1 [Symbol]
|
110
|
+
# @param key2 [Symbol]
|
111
|
+
def define_predicate_method(key1, key2 = key1)
|
112
|
+
define_method(:"#{key1}?") do
|
113
|
+
!attr_falsey_or_empty?(key2)
|
114
|
+
end
|
115
|
+
memoize(:"#{key1}?")
|
116
|
+
end
|
117
|
+
|
118
|
+
# Dynamically define a object method for an attribute
|
119
|
+
#
|
120
|
+
# @param key [Symbol]
|
121
|
+
def define_object_method(key, klass)
|
122
|
+
define_method(key) do
|
123
|
+
CloudConvert.const_get(klass).new(@attrs[key]) unless @attrs[key].nil?
|
124
|
+
end
|
125
|
+
memoize(key)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Dynamically define a struct method for an attribute
|
129
|
+
#
|
130
|
+
# @param key [Symbol]
|
131
|
+
def define_struct_method(key)
|
132
|
+
define_method(key) do
|
133
|
+
OpenStruct.new(@attrs[key]) unless @attrs[key].nil?
|
134
|
+
end
|
135
|
+
memoize(key)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Dynamically define a symbol method for an attribute
|
139
|
+
#
|
140
|
+
# @param key [Symbol]
|
141
|
+
def define_symbol_method(key)
|
142
|
+
define_method(key) do
|
143
|
+
@attrs[key].to_sym unless @attrs[key].nil?
|
144
|
+
end
|
145
|
+
memoize(key)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Dynamically define a time method for an attribute
|
149
|
+
#
|
150
|
+
# @param key [Symbol]
|
151
|
+
def define_time_method(key)
|
152
|
+
define_method(key) do
|
153
|
+
Time.parse(@attrs[key]).utc unless @attrs[key].nil?
|
154
|
+
end
|
155
|
+
memoize(key)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Initializes a new object
|
160
|
+
#
|
161
|
+
# @param attrs [Hash]
|
162
|
+
# @return [CloudConvert::Base]
|
163
|
+
def initialize(attrs = {})
|
164
|
+
@attrs = attrs || {}
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
def attr_falsey_or_empty?(key)
|
170
|
+
!@attrs[key] || @attrs[key].respond_to?(:empty?) && @attrs[key].empty?
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module CloudConvert
|
2
|
+
class Client
|
3
|
+
attr_reader :api_key, :sandbox
|
4
|
+
|
5
|
+
# Initializes a new Client object
|
6
|
+
#
|
7
|
+
# @param options [Hash]
|
8
|
+
# @return [CloudConvert::Client]
|
9
|
+
def initialize(options = {})
|
10
|
+
schema = Schemacop::Schema.new do
|
11
|
+
req! :api_key, :string
|
12
|
+
opt! :sandbox, :boolean, default: false
|
13
|
+
end
|
14
|
+
|
15
|
+
schema.validate! options.reverse_merge!({
|
16
|
+
api_key: ENV["CLOUDCONVERT_API_KEY"],
|
17
|
+
sandbox: ENV["CLOUDCONVERT_SANDBOX"].to_s.downcase == "true",
|
18
|
+
})
|
19
|
+
|
20
|
+
@api_key = options[:api_key]
|
21
|
+
@sandbox = options[:sandbox]
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Resources::Jobs]
|
25
|
+
def jobs
|
26
|
+
@jobs ||= Resources::Jobs.new(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Resources::Tasks]
|
30
|
+
def tasks
|
31
|
+
@tasks ||= Resources::Tasks.new(self)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Resources::Users]
|
35
|
+
def users
|
36
|
+
@users ||= Resources::Users.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param method [Symbol]
|
40
|
+
# @param path [String]
|
41
|
+
# @param params [Hash]
|
42
|
+
# @return [OpenStruct]
|
43
|
+
def request(method, path, params = {}, &block)
|
44
|
+
response = connection.send(method, path, params, &block)
|
45
|
+
raise CloudConvert::Error.from_response(response) unless response.success?
|
46
|
+
response.body unless response.body.blank?
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param path [String]
|
50
|
+
# @param params [Hash]
|
51
|
+
# @return [OpenStruct]
|
52
|
+
def get(path, params = {}, &block)
|
53
|
+
request(:get, path, params, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param path [String]
|
57
|
+
# @param params [Hash]
|
58
|
+
# @return [OpenStruct]
|
59
|
+
def post(path, params = {}, &block)
|
60
|
+
request(:post, path, params, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param path [String]
|
64
|
+
# @param params [Hash]
|
65
|
+
# @return [OpenStruct]
|
66
|
+
def delete(path, params = {}, &block)
|
67
|
+
request(:delete, path, params, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param url [String]
|
71
|
+
# @return [Tempfile]
|
72
|
+
def download(url, *args, **options)
|
73
|
+
options[:headers] ||= {}
|
74
|
+
options[:headers]["User-Agent"] = USER_AGENT
|
75
|
+
Down.download(url, *args, **options)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# @return [String]
|
81
|
+
def api_host
|
82
|
+
@api_host ||= sandbox ? SANDBOX_URL : API_URL
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [Faraday::Client]
|
86
|
+
def connection
|
87
|
+
@connection ||= Faraday.new(url: api_host, headers: headers) do |f|
|
88
|
+
f.adapter Faraday.default_adapter
|
89
|
+
f.request :json
|
90
|
+
f.request :multipart
|
91
|
+
f.use CloudConvert::Middleware::ParseJson, content_type: /\bjson$/
|
92
|
+
f.use FaradayMiddleware::FollowRedirects, callback: lambda { |response, redirect|
|
93
|
+
redirect.request_headers.delete("Content-Length")
|
94
|
+
redirect.request_headers.delete("Content-Type")
|
95
|
+
}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# @return [Hash]
|
100
|
+
def headers
|
101
|
+
@headers ||= {
|
102
|
+
"Authorization": "Bearer #{api_key}",
|
103
|
+
"User-Agent": USER_AGENT,
|
104
|
+
}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CloudConvert
|
2
|
+
class Collection < Array
|
3
|
+
attr_reader :links, :meta
|
4
|
+
|
5
|
+
def initialize(items = [], links = {}, meta = {})
|
6
|
+
super(items)
|
7
|
+
@links = links
|
8
|
+
@meta = meta
|
9
|
+
end
|
10
|
+
|
11
|
+
def where(attrs)
|
12
|
+
self.class.new select { |item| attrs.map { |k, v| item.send(k) == v ? true : nil }.compact.length == attrs.length }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CloudConvert
|
2
|
+
class Entity < Base
|
3
|
+
attr_reader :id
|
4
|
+
|
5
|
+
include Equalizer.new(:id)
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def collection(response)
|
9
|
+
CloudConvert::Collection.new(
|
10
|
+
response.data.collect { |item| new(item) },
|
11
|
+
response.links,
|
12
|
+
response.meta,
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def result(response)
|
17
|
+
new response.data
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module CloudConvert
|
2
|
+
class Error < StandardError
|
3
|
+
# @return [Integer]
|
4
|
+
attr_reader :code
|
5
|
+
|
6
|
+
# @return [OpenStruct]
|
7
|
+
attr_reader :errors
|
8
|
+
|
9
|
+
# Raised when CloudConvert returns a 4xx HTTP status code
|
10
|
+
ClientError = Class.new(self)
|
11
|
+
|
12
|
+
# Raised when CloudConvert returns the HTTP status code 400
|
13
|
+
BadRequest = Class.new(ClientError)
|
14
|
+
|
15
|
+
# Raised when CloudConvert returns the HTTP status code 401
|
16
|
+
Unauthorized = Class.new(ClientError)
|
17
|
+
|
18
|
+
# Raised when CloudConvert returns the HTTP status code 402
|
19
|
+
PaymentRequired = Class.new(ClientError)
|
20
|
+
|
21
|
+
# Raised when CloudConvert returns the HTTP status code 403
|
22
|
+
Forbidden = Class.new(ClientError)
|
23
|
+
|
24
|
+
# Raised when CloudConvert returns the HTTP status code 413
|
25
|
+
RequestEntityTooLarge = Class.new(ClientError)
|
26
|
+
|
27
|
+
# Raised when CloudConvert returns the HTTP status code 404
|
28
|
+
NotFound = Class.new(ClientError)
|
29
|
+
|
30
|
+
# Raised when CloudConvert returns the HTTP status code 406
|
31
|
+
NotAcceptable = Class.new(ClientError)
|
32
|
+
|
33
|
+
# Raised when CloudConvert returns the HTTP status code 422
|
34
|
+
UnprocessableEntity = Class.new(ClientError)
|
35
|
+
|
36
|
+
# Raised when CloudConvert returns the HTTP status code 429
|
37
|
+
TooManyRequests = Class.new(ClientError)
|
38
|
+
|
39
|
+
# Raised when CloudConvert returns a 5xx HTTP status code
|
40
|
+
ServerError = Class.new(self)
|
41
|
+
|
42
|
+
# Raised when CloudConvert returns the HTTP status code 500
|
43
|
+
InternalServerError = Class.new(ServerError)
|
44
|
+
|
45
|
+
# Raised when CloudConvert returns the HTTP status code 502
|
46
|
+
BadGateway = Class.new(ServerError)
|
47
|
+
|
48
|
+
# Raised when CloudConvert returns the HTTP status code 503
|
49
|
+
ServiceUnavailable = Class.new(ServerError)
|
50
|
+
|
51
|
+
# Raised when CloudConvert returns the HTTP status code 504
|
52
|
+
GatewayTimeout = Class.new(ServerError)
|
53
|
+
|
54
|
+
# Raised when CloudConvert returns a media related error
|
55
|
+
MediaError = Class.new(self)
|
56
|
+
|
57
|
+
# Raised when CloudConvert returns an InvalidMedia error
|
58
|
+
InvalidMedia = Class.new(MediaError)
|
59
|
+
|
60
|
+
# Raised when CloudConvert returns a media InternalError error
|
61
|
+
MediaInternalError = Class.new(MediaError)
|
62
|
+
|
63
|
+
# Raised when CloudConvert returns an UnsupportedMedia error
|
64
|
+
UnsupportedMedia = Class.new(MediaError)
|
65
|
+
|
66
|
+
# Raised when an operation subject to timeout takes too long
|
67
|
+
TimeoutError = Class.new(self)
|
68
|
+
|
69
|
+
ERRORS = {
|
70
|
+
400 => CloudConvert::Error::BadRequest,
|
71
|
+
401 => CloudConvert::Error::Unauthorized,
|
72
|
+
402 => CloudConvert::Error::PaymentRequired,
|
73
|
+
403 => CloudConvert::Error::Forbidden,
|
74
|
+
404 => CloudConvert::Error::NotFound,
|
75
|
+
406 => CloudConvert::Error::NotAcceptable,
|
76
|
+
413 => CloudConvert::Error::RequestEntityTooLarge,
|
77
|
+
422 => CloudConvert::Error::UnprocessableEntity,
|
78
|
+
429 => CloudConvert::Error::TooManyRequests,
|
79
|
+
500 => CloudConvert::Error::InternalServerError,
|
80
|
+
502 => CloudConvert::Error::BadGateway,
|
81
|
+
503 => CloudConvert::Error::ServiceUnavailable,
|
82
|
+
504 => CloudConvert::Error::GatewayTimeout,
|
83
|
+
}.freeze
|
84
|
+
|
85
|
+
class << self
|
86
|
+
# Create a new error from an HTTP response
|
87
|
+
#
|
88
|
+
# @param response [Faraday::Response]
|
89
|
+
# @return [CloudConvert::Error]
|
90
|
+
def from_response(response)
|
91
|
+
klass = ERRORS[response.status] || self
|
92
|
+
klass.new(response.body.message, response.body.code, response.body.errors)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Initializes a new Error object
|
97
|
+
#
|
98
|
+
# @param message [Exception, String]
|
99
|
+
# @param code [Integer]
|
100
|
+
# @return [CloudConvert::Error]
|
101
|
+
def initialize(message = "", code = nil, errors = {})
|
102
|
+
super(message)
|
103
|
+
|
104
|
+
@code = code
|
105
|
+
@errors = errors
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module CloudConvert
|
2
|
+
class File < Faraday::FilePart
|
3
|
+
def initialize(file, content_type = nil, *parts)
|
4
|
+
content_type ||= "text/plain" if file.is_a? StringIO
|
5
|
+
content_type ||= MimeMagic.by_magic(file) || MimeMagic.by_path(file)
|
6
|
+
super(file, content_type, *parts)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|