rmb 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+
3
+ # TODO have this generated from gem spec or vice versa
4
+
5
+ gem "mime-types"
6
+ gem "json"
7
+ gem "httparty", "0.6.1"
8
+ gem "multipart-post"
9
+ gem "activesupport", "2.3.9"
10
+
11
+ group :development, :test do
12
+ gem "echoe"
13
+ gem "rake"
14
+ gem "rspec", "1.3.0"
15
+ gem "diff-lcs"
16
+ gem "fakeweb"
17
+ end
data/History.rdoc ADDED
@@ -0,0 +1,32 @@
1
+ === 3.0 / 2010-09-21
2
+
3
+ * Bump httparty requirement to 0.6.
4
+ * Remove methods referencing deprecated 3.0 API calls
5
+ * Add conversion API methods
6
+
7
+ === 1.7 / 2010-02-08
8
+
9
+ * Added 0.5.2 as a requirement for httparty
10
+ * Added debug mode in Dropio::Config
11
+
12
+ === 1.0.1 - 1.0.6=7 / 2009-10-08
13
+
14
+ * Final button ups.
15
+ * Addition of pingback urls and convert to parameters.
16
+ * Pagination of comments and subscriptions
17
+
18
+ === 1.0.0 / 2009-10-02
19
+
20
+ * Moved to API version 2.0
21
+
22
+ === 0.9.6 / 2009-10-01
23
+
24
+ * Removed original file attribute from gem.
25
+
26
+ === 0.9.5 / 2009-09-09
27
+
28
+ * Move gem to github.
29
+
30
+ === 0.9.0 / 2008-11-10
31
+
32
+ * First gem release.
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Drop.io, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
20
+
data/Manifest ADDED
@@ -0,0 +1,25 @@
1
+ Gemfile
2
+ History.rdoc
3
+ LICENSE.txt
4
+ Manifest
5
+ Rakefile
6
+ Readme.rdoc
7
+ Todo.rdoc
8
+ dropio.gemspec
9
+ lib/dropio.rb
10
+ lib/dropio/api.rb
11
+ lib/dropio/asset.rb
12
+ lib/dropio/client.rb
13
+ lib/dropio/drop.rb
14
+ lib/dropio/job.rb
15
+ lib/dropio/resource.rb
16
+ lib/dropio/subscription.rb
17
+ lib/dropio/version.rb
18
+ spec/dropio/api_spec.rb
19
+ spec/dropio/asset_spec.rb
20
+ spec/dropio/client_spec.rb
21
+ spec/dropio/drop_spec.rb
22
+ spec/dropio/subscription_spec.rb
23
+ spec/dropio_spec.rb
24
+ spec/spec.opts
25
+ spec/spec_helper.rb
data/Rakefile ADDED
@@ -0,0 +1,71 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup :development, :test
4
+
5
+ $: << File.expand_path('./lib')
6
+ require 'rmb/version'
7
+
8
+ ### Echoe
9
+ begin
10
+ require 'echoe'
11
+
12
+ Echoe.new('rmb', Rmb::VERSION) do |echoe|
13
+ echoe.summary = "A Ruby client library for the Rich Media Backbone (RMB) API (http://rmb.io)"
14
+ echoe.author = ["Jake Good", "Eric Skiff", "Kunal Shah", "Seth Thomas Rasmussen", "Bryan Woods"]
15
+ echoe.email = ["jake@dropio.com", "eric@dropio.com", "kunal@dropio.com", "seth@dropio.com", "bryan@dropio.com"]
16
+ echoe.url = "http://github.com/dropio/rmb"
17
+ echoe.retain_gemspec = true
18
+ echoe.changelog = "History.rdoc"
19
+
20
+ # TODO have this generated from Gemfile or vice versa
21
+ echoe.runtime_dependencies = ["mime-types", "json", "httparty 0.6.1", "multipart-post 1.0.1", "activesupport 2.3.9"]
22
+ echoe.development_dependencies = ["rspec", "diff-lcs", "fakeweb"]
23
+
24
+ echoe.ignore_pattern = "tmtags"
25
+ # Use this rdoc_pattern when building docs locally or publishing docs.
26
+ # echoe.rdoc_pattern = Regexp.union(echoe.rdoc_pattern, /\.rdoc$/)
27
+ echoe.rdoc_pattern = /\.rdoc$/
28
+ end
29
+
30
+ # Until we find a way to undefine rake tasks...
31
+ # %w{coverage clobber_coverage}.each { |name| Rake::Task[name].comment = "(don't use)" }
32
+
33
+ # default depends on test, but we don't have a test task. Define a trivial one.
34
+ task :test
35
+ rescue LoadError
36
+ puts "(Note: Echoe not found. Install echoe gem for package management tasks.)"
37
+ end
38
+
39
+
40
+ ### RSpec
41
+ require 'spec/rake/spectask'
42
+
43
+ task :default => :spec
44
+ Spec::Rake::SpecTask.new(:spec)
45
+
46
+ namespace :spec do
47
+ Spec::Rake::SpecTask.new(:rcov) do |t|
48
+ t.rcov = true
49
+ t.rcov_opts = %w{ --exclude ^/ --exclude ^spec/ --sort coverage }
50
+ end
51
+
52
+ namespace :rcov do
53
+ desc "Generate and view RCov report"
54
+ task :view => :rcov do
55
+ coverage_index = File.expand_path(File.join(File.dirname(__FILE__), 'coverage', 'index.html'))
56
+ sh "open file://#{coverage_index}"
57
+ end
58
+ end
59
+ end
60
+
61
+
62
+ ### RDoc
63
+ require 'rake/rdoctask'
64
+
65
+ namespace :docs do
66
+ desc "Generate and view RDoc documentation"
67
+ task :view => :docs do
68
+ doc_index = File.expand_path(File.join(File.dirname(__FILE__), 'doc', 'index.html'))
69
+ sh "open file://#{doc_index}"
70
+ end
71
+ end
data/Readme.rdoc ADDED
@@ -0,0 +1,23 @@
1
+ (Note: This is very beta. The code is mostly functional. The docs are mostly not. The tests are somewhere in between. Have fun, be safe, and stay tuned.)
2
+
3
+ = RMB API library for Ruby
4
+
5
+ Documentation for this library is available here: http://backbonedocs.drop.io/Ruby-API-Client-Library
6
+
7
+ Before using the Rmb library, the application must set an API key. This key will be used for all requests to the server. To get an API key, go to http://backbone.drop.io. Then make sure you set the API key before you use the API:
8
+
9
+ Rmb::Config.api_key = "83a05513ddddb73e75c9d8146c115f7fd8e90de6"
10
+
11
+ You can also get debug information through STDERR by doing:
12
+
13
+ Rmb::Config.debug = true
14
+
15
+
16
+ == The Drop object
17
+
18
+ There are two ways to get a +Drop+ object. The first is to access an existing drop:
19
+
20
+ drop = Rmb::Drop.find("mystuff")
21
+ auth_drop = Rmb::Drop.find("mystuff", "b9b2c8f2b8e655679d2fb62b83f8efec4fb4c8af")
22
+
23
+ <tt>Drop#find</tt> takes two arguments: the name of the drop to get, and a credential token. This can be an admin token, a user token, an admin password, or a guest password. The drop's capabilities will be limited by the token, and the token is optional. If the drop is authenticated with the admin token, it will be able to do anything. If the drop is not authenticated with a token, it will have the same capabilities as any user visiting the drop. If the drop is not found or the token is not accepted, <tt>#find</tt> will return +nil+.
data/lib/rmb/api.rb ADDED
@@ -0,0 +1,272 @@
1
+ require 'rbconfig'
2
+ require 'mime/types'
3
+ require 'httparty'
4
+ require 'net/http/post/multipart'
5
+ require 'json'
6
+ require 'active_support/ordered_hash'
7
+
8
+ class Rmb::Api
9
+ include HTTParty
10
+ format :json
11
+
12
+ RUBY_VERSION = %w{MAJOR MINOR TEENY}.map { |k| Config::CONFIG[k] }.join(".")
13
+ USER_AGENT_STRING = "RmbAPI-Ruby/#{Rmb::VERSION} (Ruby #{RUBY_VERSION} #{Config::CONFIG["host"]}; +http://github.com/dropio/rmb/tree/)"
14
+ headers 'Accept' => 'application/json', 'User-Agent' => USER_AGENT_STRING, "Content-Type" => 'application/json'
15
+ def initialize
16
+ self.class.debug_output $stderr if Rmb::Config.debug
17
+ self.class.base_uri Rmb::Config.api_url
18
+ self.class.default_options[:timeout] = Rmb::Config.timeout
19
+ end
20
+
21
+ def drop(drop_name)
22
+ rmb_get("/drops/#{drop_name}", {})
23
+ end
24
+
25
+ def all_drops(page = 1)
26
+ rmb_get("/accounts/drops", {:page => page})
27
+ end
28
+
29
+ def generate_drop_url(drop_name)
30
+ signed_url(drop_name)
31
+ end
32
+
33
+ def create_drop(params = {})
34
+ rmb_post("/drops",params)
35
+ end
36
+
37
+ def update_drop(drop_name, params = {})
38
+ rmb_put("/drops/#{drop_name}", params)
39
+ end
40
+
41
+ def change_drop_name(drop_name, new_name)
42
+ params = {:name => new_name}
43
+ rmb_put("/drops/#{drop_name}", params)
44
+ end
45
+
46
+ def empty_drop(drop_name)
47
+ rmb_put("/drops/#{drop_name}/empty", {})
48
+ end
49
+
50
+ def delete_drop(drop_name)
51
+ rmb_delete("/drops/#{drop_name}", {})
52
+ end
53
+
54
+ def promote_nick(drop_name, nick)
55
+ rmb_post("/drops/#{drop_name}", {:nick => nick})
56
+ end
57
+
58
+ def drop_upload_code(drop_name)
59
+ rmb_get("/drops/#{drop_name}/upload_code", {})
60
+ end
61
+
62
+ def create_link(drop_name, url, title = nil, description = nil)
63
+ rmb_post("/drops/#{drop_name}/assets", {:url => url, :title => title, :description => description})
64
+ end
65
+
66
+ def create_note(drop_name, contents, title = nil, description = nil)
67
+ params = {:contents => contents, :title => title, :description => description}
68
+ rmb_post("/drops/#{drop_name}/assets", params)
69
+ end
70
+
71
+ def add_file(drop_name, file_path, description = nil, conversion = nil, pingback_url = nil, output_locations = nil)
72
+ url = URI.parse(Rmb::Config.upload_url)
73
+ locs = output_locations.is_a?(Array) ? output_locations.join(',') : output_locations
74
+ r = nil
75
+
76
+ File.open(file_path) do |file|
77
+ mime_type = (MIME::Types.type_for(file_path)[0] || MIME::Types["application/octet-stream"][0])
78
+
79
+ params = {
80
+ :api_key => Rmb::Config.api_key.to_s,
81
+ :format => 'json',
82
+ :version => Rmb::Config.version
83
+ }
84
+
85
+ # stuff passed in by a user. Done like this as if you pass a parameter without a value it can cause an issue (with the output_locations anyway)
86
+ # although this will be fixed in the API, we shouldn't be doing it anyway.
87
+ params[:drop_name] = drop_name if drop_name
88
+ params[:description] = description if description
89
+ params[:pingback_url] = pingback_url if pingback_url
90
+ params[:output_locations] = locs if locs
91
+ params[:conversion] = conversion if conversion
92
+ params[:signature_mode] = "STRICT"
93
+ #sign the params at this point
94
+ params = sign_if_needed(params)
95
+ params[:file] = UploadIO.new(file, mime_type, file_path)
96
+
97
+ req = Net::HTTP::Post::Multipart.new(url.path, params)
98
+ http = Net::HTTP.new(url.host, url.port)
99
+ http.set_debug_output $stderr if Rmb::Config.debug
100
+ r = http.start{|http| http.request(req)}
101
+ end
102
+
103
+ (r.nil? or r.body.nil? or r.body.empty?) ? r : HTTParty::Response.new(r,Crack::JSON.parse(r.body))
104
+ end
105
+
106
+ def add_file_from_url(drop_name, url, description = nil, convert_to = nil, pingback_url = nil)
107
+ rmb_post("/drops/#{drop_name}/assets", {:file_url => url, :description => description, :convert_to => convert_to, :pingback_url => pingback_url})
108
+ end
109
+
110
+ def assets(drop_name, page = 1, order = :oldest)
111
+ rmb_get("/drops/#{drop_name}/assets", {:page => page, :order => order.to_s, :show_pagination_details => true})
112
+ end
113
+
114
+ def asset(drop_name, asset_name)
115
+ rmb_get("/drops/#{drop_name}/assets/#{asset_name}", {})
116
+ end
117
+
118
+ def generate_asset_url(drop_name, asset_name)
119
+ signed_url(drop_name, asset_name)
120
+ end
121
+
122
+ def generate_original_file_url(drop_name, asset_id, time_to_live = 600)
123
+ #TODO - signed download URLs
124
+ #this is now available via the API response itself
125
+ download_url = Rmb::Config.api_url + "/drops/#{drop_name}/assets/#{asset_id}/download/original?"
126
+ params = {:version => Rmb::Config.version, :api_key=>Rmb::Config.api_key.to_s, :format=>'json'}
127
+ params = sign_if_needed(params)
128
+ paramstring = ''
129
+ params.each do |k, v|
130
+ paramstring << "#{k}=#{v}&"
131
+ end
132
+ paramstring.chop!
133
+ download_url += paramstring
134
+ end
135
+
136
+ def update_asset(drop_name, asset_name, params = {})
137
+ rmb_put("/drops/#{drop_name}/assets/#{asset_name}", params)
138
+ end
139
+
140
+ def change_asset_name(drop_name, asset_name, new_name)
141
+ params = {:name => new_name}
142
+ rmb_put("/drops/#{drop_name}/assets/#{asset_name}", params)
143
+ end
144
+
145
+ def delete_asset(drop_name, asset_id)
146
+ rmb_delete("/drops/#{drop_name}/assets/#{asset_id}", {})
147
+ end
148
+
149
+ def delete_role(drop_name, asset_id, role, location=nil)
150
+ rmb_delete("/drops/#{drop_name}/assets/#{asset_id}", {:role => role, :output_location => location})
151
+ end
152
+
153
+ def send_asset_to_drop(drop_name, asset_name, target_drop)
154
+ rmb_post("/drops/#{drop_name}/assets/#{asset_name}/send_to", {:medium => "drop", :drop_name => target_drop})
155
+ end
156
+
157
+ def copy_asset(drop_name, asset_name, target_drop)
158
+ params = {:drop_name => target_drop}
159
+ rmb_post("/drops/#{drop_name}/assets/#{asset_name}/copy", params)
160
+ end
161
+
162
+ def move_asset(drop_name, asset_name, target_drop)
163
+ params = {:drop_name => target_drop}
164
+ rmb_post("/drops/#{drop_name}/assets/#{asset_name}/move", params)
165
+ end
166
+
167
+ def create_pingback_subscription(drop_name, url, events = {})
168
+ rmb_post("/drops/#{drop_name}/subscriptions", :body => {:type => "pingback", :url => url}.merge(events))
169
+ end
170
+
171
+ def subscriptions(drop_name, page)
172
+ rmb_get("/drops/#{drop_name}/subscriptions", :query => {:page => page, :show_pagination_details => true})
173
+ end
174
+
175
+ def delete_subscription(drop_name, subscription_id)
176
+ rmb_delete("/drops/#{drop_name}/subscriptions/#{subscription_id}", {})
177
+ end
178
+
179
+ def get_signature(params={})
180
+ #returns a signature for the passed params, without any modifcation to the params
181
+ params = sign_request(params)
182
+ params[:signature]
183
+ end
184
+
185
+ def job(id, drop_name, asset_name_or_id)
186
+ rmb_get("/drops/#{drop_name}/assets/#{asset_name_or_id}/jobs/#{id}", {})
187
+ end
188
+
189
+ def create_job(job = {})
190
+ rmb_post("/jobs",job)
191
+ end
192
+ alias_method :convert, :create_job
193
+
194
+ private
195
+
196
+ def sign_request(params={}, request="POST")
197
+ #returns all params, including signature and any required params for signing (currently only timestamp)
198
+ params_for_sig = params.clone
199
+ params_for_sig[:api_key] = Rmb::Config.api_key.to_s
200
+ params_for_sig[:version] = Rmb::Config.version.to_s
201
+
202
+ if params[:signature_mode] != "OPEN"
203
+ #RPC always includes format here, so in NORMAL and STRICT mode we need to include it in our sig if not specified
204
+ params_for_sig[:format] ||= 'json'
205
+ params[:format] ||= 'json'
206
+ end
207
+
208
+ #Sort the clean params and put them into an ordered hash for to_json
209
+ orderedparams = sort_hash_recursively(params_for_sig)
210
+ #compute the expected signature
211
+ puts "\r\nSigning this string: " + orderedparams.to_json + "\r\n" if Rmb::Config.debug
212
+ params[:signature] = Digest::SHA1.hexdigest(orderedparams.to_json + Rmb::Config.api_secret)
213
+ params
214
+ end
215
+
216
+ def sign_if_needed(params = {}, method="POST")
217
+ if Rmb::Config.api_secret
218
+ params = add_required_signing_params(params)
219
+ params = sign_request(params, method)
220
+ params
221
+ else
222
+ params
223
+ end
224
+ end
225
+
226
+ def add_required_signing_params(params = {})
227
+ #10 minute window
228
+ params[:timestamp] = (Time.now.to_i + 600).to_s
229
+ params
230
+ end
231
+
232
+ def add_default_params(params = {})
233
+ default_params = {:api_key => Rmb::Config.api_key.to_s, :version => Rmb::Config.version.to_s, :format => "json" }
234
+ params = params.merge(default_params)
235
+ params
236
+ end
237
+
238
+ def rmb_get(action, params={})
239
+ self.class.get(action, :query => add_default_params(sign_if_needed(params, "GET")))
240
+ end
241
+
242
+ def rmb_post(action, params={})
243
+ self.class.post(action, :body => add_default_params(sign_if_needed(params, "POST")).to_json)
244
+ end
245
+
246
+ def rmb_put(action, params={})
247
+ self.class.put(action, :body => add_default_params(sign_if_needed(params, "PUT")).to_json)
248
+ end
249
+
250
+ def rmb_delete(action,params={})
251
+ self.class.delete(action, :body => add_default_params(sign_if_needed(params, "DELETE")).to_json)
252
+ end
253
+
254
+ def sort_hash_recursively(oldhash = {}, depth = 0)
255
+ return false if depth > 4
256
+ sortedhash = ActiveSupport::OrderedHash.new
257
+ oldhash.keys.sort_by {|s| s.to_s}.each {|key|
258
+ if oldhash[key].is_a? Hash
259
+ sortedhash[key] = sort_hash_recursively(oldhash[key], depth + 1)
260
+ elsif oldhash[key].is_a? Array
261
+ oldhash[key].map! do |element|
262
+ element = sort_hash_recursively(element, depth + 1)
263
+ end
264
+ sortedhash[key] = oldhash[key]
265
+ else
266
+ sortedhash[key] = oldhash[key].to_s
267
+ end
268
+ }
269
+ return sortedhash
270
+ end
271
+
272
+ end
data/lib/rmb/asset.rb ADDED
@@ -0,0 +1,65 @@
1
+ class Rmb::Asset < Rmb::Resource
2
+
3
+ attr_accessor :id, :drop, :name, :type, :title, :description, :filesize, :created_at, :status,
4
+ :pages, :duration, :artist, :track_title, :height, :width, :contents, :url,
5
+ :roles, :locations
6
+
7
+ # Finds a particular Asset by drop and asset name.
8
+ def self.find(drop, id)
9
+ Rmb::Resource.client.asset(drop, id)
10
+ end
11
+
12
+ # Changes the name of an asset.
13
+ def change_name(new_name)
14
+ Rmb::Resource.client.change_asset_name(self,new_name)
15
+ end
16
+
17
+ # Saves the Asset back to the RMB
18
+ def save
19
+ Rmb::Resource.client.update_asset(self)
20
+ end
21
+
22
+ # Destroys the Asset on the RMB Don't try to use an Asset after destroying it.
23
+ def destroy!
24
+ Rmb::Resource.client.delete_asset(self)
25
+ return nil
26
+ end
27
+
28
+ # Destroys the given role on an Asset
29
+ def destroy_role!(role)
30
+ Rmb::Resource.client.delete_role(self, role)
31
+ return nil
32
+ end
33
+
34
+ # Destroys the given role at the specified location on an Asset
35
+ def destroy_location!(role, location)
36
+ Rmb::Resource.client.delete_role(self, role, location)
37
+ return nil
38
+ end
39
+
40
+ # Copies the Asset to the given drop.
41
+ def copy_to(target_drop)
42
+ Rmb::Resource.client.copy_asset(self, target_drop)
43
+ end
44
+
45
+ # Moves the Asset to the given drop.
46
+ def move_to(target_drop)
47
+ Rmb::Resource.client.move_asset(self, target_drop)
48
+ end
49
+
50
+ # Sends the Asset to a Drop by +drop_name+
51
+ def send_to_drop(drop)
52
+ Rmb::Resource.client.copy_asset(self, drop)
53
+ end
54
+
55
+ # Generates an authenticated URL that will bypass any login action.
56
+ def generate_url
57
+ Rmb::Resource.client.generate_asset_url(self)
58
+ end
59
+
60
+ # Generates a url if there's access to the original file.
61
+ def original_file_url(time_to_live = 600)
62
+ Rmb::Resource.client.generate_original_file_url(self)
63
+ end
64
+
65
+ end