cdnconnect-api 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b09f95fa8be041f1279b13ad5fc9d5964d8ad776
4
+ data.tar.gz: bb62899381127af7f009090327f9dc019d85ebb6
5
+ SHA512:
6
+ metadata.gz: 63abdcbb70be485314a599ba7a9f0a9f824e88714a31f673086db4774ed8179c367e0e4614410793a275d62085750c72a84cc8dc7ecf3e9bf4b3a32276adfc07
7
+ data.tar.gz: f8f45b12ca80ee4cb9ca1e57196addcc22cc34febe954b3830f739efa29bbcc5b32c1b84161575a7b8c3a8054e8987ebdedb700f2ce84dfbe974860df6adcea7
data/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # CDN Connect API Ruby Client, v0.0.1
2
+
3
+ ## Description
4
+
5
+ The CDN Connect API Ruby Client makes it easier to upload files and interact with
6
+ our API. Most interactions with CDN Connect APIs require users to authorize applications via OAuth 2.0. This library simplifies the communication with CDN Connect even further allowing you
7
+ to easily upload files and get information with only a few lines of code.
8
+
9
+ ## Install
10
+
11
+ $ sudo gem install cdnconnect-api
12
+
13
+ ## API Key
14
+
15
+ An API Key is can be created for a specific app within your CDN Connect's account. Sign into your account and go to the "API Key" tab for the app you want to interact with. Next click "Add API Key" and use this value when creating a new API client within the code. The API Key can be revoked
16
+ by you at any time and numerous keys can be created.
17
+
18
+ ## Example Usage
19
+
20
+ # Initialize the CDN Connect API client
21
+ require 'cdnconnect_api'
22
+ api_client = CDNConnect::APIClient.new(:api_key => YOUR_API_KEY)
23
+
24
+ # Upload to a folder in the app the API Key was created for
25
+ response = api_client.upload(:destination_folder_url => 'demo.cdnconnect.com/images',
26
+ :source_file_local_path => 'meowzers.jpg')
27
+
28
+ # Read the response
29
+ if response.is_success
30
+ # "Woot!"
31
+ end
32
+
33
+ ## Get Object Data
34
+
35
+ An object can be either a file or a folder. Pass the `get` method the `url` you want to receive data about.
36
+
37
+ # Get file information
38
+ response = api_client.get(:url => 'demo.cdnconnect.com/images/meowzers.jpg')
39
+ puts response.results['data']['name'] #=> "meowzers.jpg"
40
+
41
+ # Get folder information
42
+ response = api_client.get(:url => 'demo.cdnconnect.com/images')
43
+ puts response.results['data']['name'] #=> "images"
44
+
45
+
46
+ ## Response Object
47
+
48
+ All responses will be structured the same with both a `results` and `msgs` object at the root level, such as:
49
+
50
+ {
51
+ "results":
52
+ {
53
+ "data":
54
+ {
55
+ "id": "bU1SS1JyvF9I",
56
+ "status": 1,
57
+ "name": "images",
58
+ "created": "2013-03-12T17:02Z",
59
+ "parent_id": "iF637hnbwI4G",
60
+ "folder": true,
61
+ "files": [],
62
+ "folders": []
63
+ }
64
+ },
65
+ "msgs":[]
66
+ }
67
+
68
+ The `results` object contains the guts of the information your looking for, and the `msgs` object contains an array of messages which can represent errors, warnings and information. The `results` object can be null, or it can contain many objects within it. Each response can have different data within `results` object and `msgs` object. In the case above, the `results` object contains the key `data`, and within the `data` object it contains summary information of the images folder.
69
+
70
+ ## Support
71
+
72
+ Please [report any bugs](https://github.com/cdnconnect/cdnconnect-api-ruby/issues) on this project's issues page. Additionally, please don't hesitate to contact us and/or submit a pull request with any ideas you may have to improve the service. We will continue to improve upon and build out the API in order to bring more value to you and your projects.
73
+
@@ -0,0 +1,389 @@
1
+ # Copyright 2013 CDN Connect
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'faraday'
16
+ require 'faraday/utils'
17
+ require 'signet/oauth_2/client'
18
+ require 'cdnconnect_api/response'
19
+
20
+
21
+ module CDNConnect
22
+
23
+ class APIClient
24
+
25
+ @@application_name = 'cdnconnect-api-ruby'
26
+ @@application_version = '0.0.2'
27
+ @@api_host = 'https://api.cdnconnect.com'
28
+ @@user_agent = @@application_name + ' v' + @@application_version
29
+
30
+ ##
31
+ # Creates a client to authorize interactions with the API using the OAuth 2.0 protocol.
32
+ # This can be given a known API Key (access_token) or can use OAuth 2.0
33
+ # web application flow designed for 3rd party web sites (clients).
34
+ #
35
+ # @param [Hash] options
36
+ # The configuration parameters for the client.
37
+ # - <code>:api_key</code> -
38
+ # An API Key (commonly known as an access_token) which was previously
39
+ # created within CDN Connect's account for a specific app.
40
+ # - <code>:response_format</code> -
41
+ # How data should be formatted on the response. Possible values for
42
+ # include application/json, application/xml. JSON is the default.
43
+ # - <code>:client_id</code> -
44
+ # A unique identifier issued to the client to identify itself to CDN Connect's
45
+ # authorization server. This is issued by CDN Connect to individual clients.
46
+ # - <code>:client_secret</code> -
47
+ # A shared secret issued by the CDN Connect's authorization server,
48
+ # which is used to authenticate the client. Do not confuse this is an access_token
49
+ # or an api_key.
50
+ # - <code>:scope</code> -
51
+ # The scope of the access request, expressed either as an Array
52
+ # or as a space-delimited String.
53
+ # - <code>:state</code> -
54
+ # An unguessable random string designed to allow the client to maintain state
55
+ # to protect against cross-site request forgery attacks.
56
+ # - <code>:code</code> -
57
+ # The authorization code received from the authorization server.
58
+ # - <code>:redirect_uri</code> -
59
+ # The redirection URI used in the initial request.
60
+ # - <code>:access_token</code> -
61
+ # The current access token for this client, also known as the API Key.
62
+ def initialize(options={})
63
+ # Normalize key to String to allow indifferent access.
64
+ options = options.inject({}) { |accu, (k, v)| accu[k.to_s] = v; accu }
65
+
66
+ # Initialize all of the options
67
+ @client_id = options["client_id"]
68
+ @client_secret = options["client_secret"]
69
+ @scope = options["scope"]
70
+ @state = options["state"]
71
+ @code = options["code"]
72
+ @redirect_uri = options["redirect_uri"]
73
+ options["access_token"] = options["access_token"] || options["api_key"] # both work
74
+ @access_token = options["access_token"]
75
+ @response_format = options["response_format"] || 'application/json'
76
+ @prefetched_upload_urls = {}
77
+
78
+ # Create the OAuth2 client which will be used to authorize the requests
79
+ @client = Signet::OAuth2::Client.new(:client_id => client_id,
80
+ :client_secret => @client_secret,
81
+ :scope => @scope,
82
+ :state => @state,
83
+ :code => @code,
84
+ :redirect_uri => @redirect_uri,
85
+ :access_token => @access_token)
86
+ return self
87
+ end
88
+
89
+
90
+ ##
91
+ # Used to receive information about an object, which can be either a file or
92
+ # folder. This method requires either a CDN Connect URL, or both an
93
+ # app_id and obj_id.
94
+ #
95
+ # @param [Hash] options
96
+ # The configuration parameters for the client.
97
+ # - <code>:url</code> -
98
+ # The URL of the object to get data on. If the URL option is not provided
99
+ # then you must use the app_id and obj_id options.
100
+ # - <code>:app_id</code> -
101
+ # The app_id of the object to get data on. If the app_id or obj_id options
102
+ # are not provided then you must use the url option.
103
+ # - <code>:obj_id</code> -
104
+ # The obj_id of the object to get data on. If the app_id or obj_id options
105
+ # are not provided then you must use the url option.
106
+ def get(options={})
107
+ options[:path] = self.generate_obj_path(options)
108
+ return self.fetch(options)
109
+ end
110
+
111
+
112
+ ##
113
+ # Used to upload a file or files within a folder to a destination folder within
114
+ # a CDN Connect app. This method requires either a CDN Connect URL, or both an app_id
115
+ # and obj_id. If you are uploading many files be sure to use the same client instance.
116
+ #
117
+ # @param [Hash] options
118
+ # The configuration parameters for the client.
119
+ # - <code>:destination_folder_url</code> -
120
+ # The URL of the folder to upload to. If the destination folder URL option
121
+ # is not provided then you must use the app_id and obj_id options.
122
+ # - <code>:app_id</code> -
123
+ # The app_id of the app to upload to. If the app_id or obj_id options
124
+ # are not provided then you must use the url option.
125
+ # - <code>:obj_id</code> -
126
+ # The obj_id of the folder to upload to. If the app_id or obj_id options
127
+ # are not provided then you must use the url option.
128
+ # - <code>:source_file_local_path</code> -
129
+ # A string of a source file's local paths to upload.
130
+ def upload(options={})
131
+ # Make sure we've got good data before starting the upload
132
+ prepare_upload(options)
133
+
134
+ i = 1
135
+ begin
136
+
137
+ # Check if we have a prefetched upload url before requesting a new one
138
+ upload_url = get_prefetched_upload_url(options[:destination_folder_url],
139
+ options[:app_id],
140
+ options[:obj_id])
141
+ if upload_url == nil
142
+ # We do not already have an upload url created. The first upload request
143
+ # will need to make a request for an upload url. After the first upload
144
+ # each upload response will also include a new upload url which can be used
145
+ # for the next upload when uploading to the same folder.
146
+ upload_url_response = self.get_upload_url(options)
147
+ if upload_url_response.is_error
148
+ return upload_url_response
149
+ end
150
+ upload_url = upload_url_response.get_result('upload_url')
151
+ end
152
+
153
+ # Create the POST data that gets sent in the request
154
+ post_data = {}
155
+ post_data[:create_upload_url] = 'true' # have the API also create the next upload url
156
+ post_data[:file] = Faraday::UploadIO.new(options[:source_file_local_path], options[:mime_type])
157
+
158
+ # Build the request to the API
159
+ conn = Faraday.new() do |req|
160
+ # https://github.com/lostisland/faraday
161
+ req.headers['User-Agent'] = @@user_agent
162
+ req.headers['Authorization'] = 'Bearer ' + @access_token
163
+ req.request :multipart
164
+ req.adapter :net_http
165
+ end
166
+
167
+ # Kick it off!
168
+ api_response = conn.post upload_url, post_data
169
+
170
+ # Woot! Convert the response to our model and see what's up
171
+ response = APIResponse.new(api_response)
172
+
173
+ # an upload response also contains a new upload url. Save it for the next upload.
174
+ set_prefetched_upload_url(options[:destination_folder_url],
175
+ options[:app_id],
176
+ options[:obj_id],
177
+ response.get_result('upload_url'))
178
+
179
+ # Rettempt the upload a max of two times if there was a server error
180
+ # Otherwise return the response data
181
+ if not response.is_server_error or i > 2
182
+ return response
183
+ end
184
+ i += 1
185
+ end while i <= 3
186
+
187
+ end
188
+
189
+
190
+ ##
191
+ # This method should not be called directly, but is used by the upload method
192
+ # to get the options all ready to go and validated before uploading a file(s).
193
+ # @!visibility private
194
+ def prepare_upload(options={})
195
+ # Validate we've got a source file
196
+ source_file_local_path = options[:source_file_local_path]
197
+ if source_file_local_path == nil
198
+ raise ArgumentError, 'source_file_local_path required'
199
+ end
200
+
201
+ # Validate we've got a destination folder to upload to
202
+ destination_folder_url = options[:destination_folder_url]
203
+ app_id = options[:app_id]
204
+ obj_id = options[:obj_id]
205
+ if destination_folder_url == nil and (app_id == nil or obj_id == nil)
206
+ raise ArgumentError, 'destination_folder_url or app_id/obj_id required'
207
+ end
208
+
209
+ # Ideally it'd be awesome to already set what the mime type is, but getting that
210
+ # info accurately is a pain. If you do not send in the mime_type we will
211
+ # figure it out for you by the file extension (so ALWAYS have an extension)
212
+ # This will only work when using the source_file option, and will not
213
+ # work with the source_files or source_folder option.
214
+ if options[:mime_type] == nil
215
+ options[:mime_type] = 'application/octet-stream'
216
+ end
217
+
218
+ options
219
+ end
220
+
221
+
222
+ ##
223
+ # This method should not be called directly, but is used to check if we
224
+ # already have an upload url ready to go for the folder we're uploading to.
225
+ # @!visibility private
226
+ def get_prefetched_upload_url(destination_url, app_id, obj_id)
227
+ # Build a unique key for the folder which was used to save an new upload url
228
+ key = destination_url || ''
229
+ key += app_id || ''
230
+ key += obj_id || ''
231
+ rtn_url = @prefetched_upload_urls[key]
232
+ @prefetched_upload_urls[key] = nil
233
+ return rtn_url
234
+ end
235
+
236
+
237
+ ##
238
+ # This method should not be called directly, but is used to remember an upload url
239
+ # for the next upload to this folder.
240
+ # @!visibility private
241
+ def set_prefetched_upload_url(destination_url, app_id, obj_id, upload_url)
242
+ # Build a unique key for the folder to save an new upload url value to
243
+ key = destination_url || ''
244
+ key += app_id || ''
245
+ key += obj_id || ''
246
+ @prefetched_upload_urls[key] = upload_url
247
+ end
248
+
249
+
250
+ ##
251
+ # An upload url must be optained first before uploading a file. After the first
252
+ # upload url is received, all upload responses contain another upload which can be
253
+ # used to eliminate the need to do seperate requests for an upload url.
254
+ # @!visibility private
255
+ def get_upload_url(options={})
256
+ destination_folder_url = options[:destination_folder_url]
257
+
258
+ path = nil
259
+ if destination_folder_url != nil
260
+ path = '/v1/' + destination_folder_url + '/upload'
261
+ else
262
+ path = generate_obj_path(options) + '/upload'
263
+ end
264
+
265
+ i = 1
266
+ begin
267
+ response = self.fetch(:path => path)
268
+ if not response.is_server_error or i > 2
269
+ return response
270
+ end
271
+ i += 1
272
+ end while i <= 3
273
+ end
274
+
275
+
276
+ ##
277
+ # This method should not be called directly, but is used to build the api
278
+ # path common needed by a few methods.
279
+ # @!visibility private
280
+ def generate_obj_path(options={})
281
+ app_id = options[:app_id]
282
+ obj_id = options[:obj_id]
283
+ uri = options[:uri] || options[:url]
284
+ path = nil
285
+
286
+ # An object's path can either be made up of an app_id and an obj_id
287
+ # Or it can be made up of the entire URI
288
+ if app_id != nil and obj_id != nil
289
+ path = 'apps/' + app_id + '/objects/' + obj_id
290
+ elsif uri != nil
291
+ path = uri
292
+ end
293
+
294
+ if path == nil
295
+ raise ArgumentError, "missing url or both app_id and obj_id"
296
+ end
297
+
298
+ return '/v1/' + path
299
+ end
300
+
301
+
302
+ ##
303
+ # This method should not be called directly, but is used to validate data
304
+ # and make it all pretty before firing off the request to the API.
305
+ # @!visibility private
306
+ def prepare(options={})
307
+ if options[:path] == nil
308
+ raise ArgumentError, 'missing api path'
309
+ end
310
+
311
+ options[:response_format] = options[:response_format] || @response_format
312
+
313
+ headers = { 'User-Agent' => @@user_agent }
314
+
315
+ # There are three possible response content-types: JSON, XML
316
+ # Default Content-Type is application/json with a .json extension
317
+ if options[:response_format] == 'application/xml'
318
+ headers['Content-Type'] = 'application/xml'
319
+ response_extension = 'xml'
320
+ else
321
+ options[:response_format] = 'application/json'
322
+ headers['Content-Type'] = 'application/json'
323
+ response_extension = 'json'
324
+ end
325
+ options[:headers] = headers
326
+
327
+ options[:uri] = @@api_host + options[:path] + '.' + response_extension
328
+ options[:url] = options[:uri]
329
+ options[:method] = options[:method] || 'GET'
330
+
331
+ return options
332
+ end
333
+
334
+
335
+ ##
336
+ # Guts of an authorized request. Do not call this directly.
337
+ # @!visibility private
338
+ def fetch(options={})
339
+ # Prepare the data to be shipped in the request
340
+ options = self.prepare(options)
341
+
342
+ begin
343
+ # Send the request and get the response
344
+ response = @client.fetch_protected_resource(options)
345
+
346
+ # Return the API response
347
+ return APIResponse.new(response)
348
+ rescue Signet::AuthorizationError => detail
349
+ return APIResponse.new(detail.response)
350
+ end
351
+
352
+ end
353
+
354
+
355
+ def client_id
356
+ @client_id
357
+ end
358
+
359
+ def client_secret
360
+ @client_secret
361
+ end
362
+
363
+ def scope
364
+ @scope
365
+ end
366
+
367
+ def state
368
+ @state
369
+ end
370
+
371
+ def code
372
+ @code
373
+ end
374
+
375
+ def redirect_uri
376
+ @redirect_uri
377
+ end
378
+
379
+ def access_token
380
+ @access_token
381
+ end
382
+
383
+ def response_format
384
+ @response_format
385
+ end
386
+
387
+ end
388
+
389
+ end
@@ -0,0 +1,129 @@
1
+ # Copyright 2013 CDN Connect
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module CDNConnect
16
+
17
+ ##
18
+ # Used to simpilfy things by creating easy to use helper functions to read
19
+ # response data. Responses from the API are all structured the same way,
20
+ # and this class is used as a small wrapper to make it easier to get data.
21
+ class APIResponse
22
+
23
+ def initialize(response)
24
+ @response = response
25
+ @data = nil
26
+ return self
27
+ end
28
+
29
+ def body()
30
+ @response.body
31
+ end
32
+
33
+ def data()
34
+ # Convert the response body depending on the response format
35
+ # Keep the parsed data in an instance variable so we
36
+ # don't keep parsing it every time we reference data()
37
+ if @data == nil
38
+ if format.include? 'application/json'
39
+ @data = ActiveSupport::JSON.decode(body)
40
+ elsif format.include? 'application/xml'
41
+ @data = ActiveSupport::XML.decode(body)
42
+ else
43
+ raise "invalid data format"
44
+ end
45
+ end
46
+ @data
47
+ end
48
+
49
+ def results()
50
+ # this is just double checking the results data
51
+ # exists and is built with the correct structure
52
+ d = data
53
+ if d.has_key?('results')
54
+ return d['results']
55
+ end
56
+ nil
57
+ end
58
+
59
+ def get_result(key)
60
+ # A helper method so you don't have to do any nil checking
61
+ # as you dig through the response results
62
+ r = results
63
+ if r != nil
64
+ return results[key]
65
+ end
66
+ nil
67
+ end
68
+
69
+ def msgs()
70
+ # this is just double checking the msgs data
71
+ # exists and is built with the correct structure
72
+ d = data
73
+ if d.has_key?('msgs')
74
+ return d['msgs']
75
+ end
76
+ nil
77
+ end
78
+
79
+ def format()
80
+ @response.headers['content-type']
81
+ end
82
+
83
+ def status()
84
+ @response.status
85
+ end
86
+
87
+ def is_success()
88
+ (status >= 200 and status < 300)
89
+ end
90
+
91
+ def is_error()
92
+ (status >= 400)
93
+ end
94
+
95
+ def is_bad_request()
96
+ (status == 400)
97
+ end
98
+
99
+ def is_unauthorized()
100
+ (status == 401)
101
+ end
102
+
103
+ def is_forbidden()
104
+ (status == 403)
105
+ end
106
+
107
+ def is_not_found()
108
+ (status == 404)
109
+ end
110
+
111
+ def is_method_not_allowed()
112
+ (status == 405)
113
+ end
114
+
115
+ def is_server_error()
116
+ (status >= 500)
117
+ end
118
+
119
+ def is_bad_gateway()
120
+ (status >= 502)
121
+ end
122
+
123
+ def is_service_unavailable()
124
+ (status >= 503)
125
+ end
126
+
127
+ end
128
+
129
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cdnconnect-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Adam Bradley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: signet
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.4.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.4.5
41
+ description: CDN Connect API Ruby Client which makes it easier to interact with api.cdnconnect.com.
42
+ email: developer@cdnconnect.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files:
46
+ - README.md
47
+ files:
48
+ - lib/cdnconnect_api.rb
49
+ - lib/cdnconnect_api/response.rb
50
+ - LICENSE
51
+ - README.md
52
+ homepage: http://www.cdnconnect.com/
53
+ licenses: []
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubyforge_project:
71
+ rubygems_version: 2.0.0
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: Package Summary
75
+ test_files: []
76
+ has_rdoc: