dropio 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ === 0.9.0 / 2008-11-10
2
+
3
+ * First gem release.
data/LICENSE.txt ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008 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.
data/Manifest ADDED
@@ -0,0 +1,22 @@
1
+ History.rdoc
2
+ lib/dropio/asset.rb
3
+ lib/dropio/client/mapper.rb
4
+ lib/dropio/client/multipart_post.rb
5
+ lib/dropio/client.rb
6
+ lib/dropio/comment.rb
7
+ lib/dropio/drop.rb
8
+ lib/dropio/resource.rb
9
+ lib/dropio.rb
10
+ LICENSE.txt
11
+ Manifest
12
+ Rakefile
13
+ Readme.rdoc
14
+ spec/dropio/asset_spec.rb
15
+ spec/dropio/client/mapper_spec.rb
16
+ spec/dropio/client_spec.rb
17
+ spec/dropio/comment_spec.rb
18
+ spec/dropio/drop_spec.rb
19
+ spec/dropio_spec.rb
20
+ spec/spec.opts
21
+ spec/spec_helper.rb
22
+ Todo.rdoc
data/Rakefile ADDED
@@ -0,0 +1,62 @@
1
+ $: << 'lib'
2
+ require 'dropio'
3
+
4
+ ### Echoe
5
+ begin
6
+ require 'echoe'
7
+
8
+ Echoe.new('dropio', Dropio::VERSION) do |echoe|
9
+ echoe.summary = "A Ruby client library for the Drop.io API (http://api.drop.io)"
10
+ echoe.author = ["Jake Good", "Peter Jaros"]
11
+ echoe.email = ["jake@dropio.com", "peeja@dropio.com"]
12
+ echoe.url = "http://github.com/whoisjake/dropio_api_ruby"
13
+ echoe.changelog = "History.txt"
14
+ echoe.ignore_pattern = "tmtags"
15
+
16
+ # Comment out this line when building docs locally or publishing docs.
17
+ echoe.rdoc_pattern = "*.rdoc"
18
+ end
19
+
20
+ # Until we find a way to undefine rake tasks...
21
+ %w{coverage clobber_coverage}.each { |name| Rake::Task[name].comment = "(don't use)" }
22
+
23
+ # default depends on test, but we don't have a test task. Define a trivial one.
24
+ task :test
25
+ rescue LoadError
26
+ puts "(Note: Echoe not found. Install echoe gem for package management tasks.)"
27
+ end
28
+
29
+
30
+ ### RSpec
31
+ require 'spec/rake/spectask'
32
+
33
+ task :default => :spec
34
+ Spec::Rake::SpecTask.new(:spec)
35
+
36
+ namespace :spec do
37
+ Spec::Rake::SpecTask.new(:rcov) do |t|
38
+ t.rcov = true
39
+ t.rcov_opts = %w{ --exclude ^/ --exclude ^spec/ --sort coverage }
40
+ end
41
+
42
+ namespace :rcov do
43
+ desc "Generate and view RCov report"
44
+ task :view => :rcov do
45
+ coverage_index = File.expand_path(File.join(File.dirname(__FILE__), 'coverage', 'index.html'))
46
+ sh "open file://#{coverage_index}"
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ ### RDoc
53
+ require 'rake/rdoctask'
54
+
55
+ namespace :docs do
56
+ desc "Generate and view RDoc documentation"
57
+ task :view => :docs do
58
+ doc_index = File.expand_path(File.join(File.dirname(__FILE__), 'doc', 'index.html'))
59
+ sh "open file://#{doc_index}"
60
+ end
61
+ end
62
+
data/Readme.rdoc ADDED
@@ -0,0 +1,17 @@
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
+ = drop.io API library for Ruby
4
+
5
+ Before using the Dropio 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://api.drop.io. Then make sure you set the API key before you use the API:
6
+
7
+ Dropio.api_key = "83a05513ddddb73e75c9d8146c115f7fd8e90de6"
8
+
9
+
10
+ == The Drop object
11
+
12
+ There are two ways to get a +Drop+ object. The first is to access an existing drop:
13
+
14
+ drop = Dropio::Drop.find("mystuff")
15
+ auth_drop = Dropio::Drop.find("mystuff", "b9b2c8f2b8e655679d2fb62b83f8efec4fb4c8af")
16
+
17
+ <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/Todo.rdoc ADDED
@@ -0,0 +1,5 @@
1
+ == For 1.0
2
+ * Bring spec coverage up to 100%.
3
+
4
+ == Beyond
5
+ * Provide subclasses of Asset?
data/dropio.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{dropio}
5
+ s.version = "0.9.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Jake Good, Peter Jaros"]
9
+ s.date = %q{2008-11-10}
10
+ s.description = %q{A Ruby client library for the Drop.io API (http://api.drop.io)}
11
+ s.email = ["jake@dropio.com", "peeja@dropio.com"]
12
+ s.extra_rdoc_files = ["History.rdoc", "Readme.rdoc", "Todo.rdoc"]
13
+ s.files = ["History.rdoc", "lib/dropio/asset.rb", "lib/dropio/client/mapper.rb", "lib/dropio/client/multipart_post.rb", "lib/dropio/client.rb", "lib/dropio/comment.rb", "lib/dropio/drop.rb", "lib/dropio/resource.rb", "lib/dropio.rb", "LICENSE.txt", "Manifest", "Rakefile", "Readme.rdoc", "spec/dropio/asset_spec.rb", "spec/dropio/client/mapper_spec.rb", "spec/dropio/client_spec.rb", "spec/dropio/comment_spec.rb", "spec/dropio/drop_spec.rb", "spec/dropio_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "Todo.rdoc", "dropio.gemspec"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://github.com/whoisjake/dropio_api_ruby}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Dropio", "--main", "Readme.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{dropio}
19
+ s.rubygems_version = %q{1.3.0}
20
+ s.summary = %q{A Ruby client library for the Drop.io API (http://api.drop.io)}
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 2
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_development_dependency(%q<echoe>, [">= 0"])
28
+ else
29
+ s.add_dependency(%q<echoe>, [">= 0"])
30
+ end
31
+ else
32
+ s.add_dependency(%q<echoe>, [">= 0"])
33
+ end
34
+ end
@@ -0,0 +1,60 @@
1
+ class Dropio::Asset < Dropio::Resource
2
+
3
+ attr_accessor :drop, :name, :type, :title, :description, :filesize, :created_at,
4
+ :thumbnail, :status, :file, :converted, :hidden_url, :pages,
5
+ :duration, :artist, :track_title, :height, :width, :contents, :url
6
+
7
+ # Returns the comments on this asset. Comments are loaded lazily. The first
8
+ # call to +comments+ will fetch the comments from the server. They are then
9
+ # cached until the asset is reloaded.
10
+ def comments
11
+ @comments = Dropio::Client.instance.find_comments(self) if @comments.nil?
12
+ @comments ||= []
13
+ end
14
+
15
+ # Adds a comment to the asset with the given +contents+. Returns the
16
+ # new +Comment+.
17
+ def create_comment(contents)
18
+ Dropio::Client.instance.create_comment(self, contents)
19
+ end
20
+
21
+ # Saves the asset back to drop.io.
22
+ def save
23
+ Dropio::Client.instance.save_asset(self)
24
+ end
25
+
26
+ # Destroys the asset on drop.io. Don't try to use an Asset after destroying it.
27
+ def destroy!
28
+ Dropio::Client.instance.destroy_asset(self)
29
+ nil
30
+ end
31
+
32
+ # Returns true if the Asset can be faxed.
33
+ def faxable?
34
+ return type == "Document"
35
+ end
36
+
37
+ # Fax the asset to the given +fax_number+. Make sure the Asset is +faxable?+
38
+ # first, or +send_to_fax+ will raise an error.
39
+ def send_to_fax(fax_number)
40
+ raise "Can't fax Asset: #{self.inspect} is not faxable" unless faxable?
41
+ Dropio::Client.instance.send_to_fax(self, fax_number)
42
+ nil
43
+ end
44
+
45
+ # Sends the asset to the given +emails+ with an optional +message+.
46
+ def send_to_emails(emails = [], message = nil)
47
+ Dropio::Client.instance.send_to_emails(self, emails, message)
48
+ end
49
+
50
+ # Sends the asset to a Drop by +drop_name+
51
+ def send_to_drop(drop_name)
52
+ Dropio::Client.instance.send_to_drop(self, drop_name)
53
+ end
54
+
55
+ # Generates an authenticated URL that will bypass any login action.
56
+ def generate_url
57
+ Dropio::Client.instance.generate_asset_url(self)
58
+ end
59
+
60
+ end
@@ -0,0 +1,47 @@
1
+ class Dropio::Client::Mapper
2
+
3
+ def self.map_drops(response_body)
4
+ return parse_and_map(Dropio::Drop, response_body)
5
+ end
6
+
7
+ def self.map_assets(drop, response_body)
8
+ assets = parse_and_map(Dropio::Asset, response_body)
9
+
10
+ assets.drop = drop if assets.is_a?(Dropio::Asset)
11
+ assets.each{ |a| a.drop = drop } if assets.is_a?(Array)
12
+
13
+ return assets
14
+ end
15
+
16
+ def self.map_comments(asset, response_body)
17
+ comments = parse_and_map(Dropio::Comment, response_body)
18
+
19
+ comments.asset = asset if comments.is_a?(Dropio::Comment)
20
+ comments.each{ |c| c.asset = asset } if comments.is_a?(Array)
21
+
22
+ return comments
23
+ end
24
+
25
+ private
26
+
27
+ def self.parse_and_map(model_class, response_body)
28
+ h = JSON.parse(response_body)
29
+
30
+ # single model
31
+ return model_class.new(h) if h.is_a?(Hash)
32
+
33
+ # multiple models
34
+ models = []
35
+
36
+ h.each do |model_hash|
37
+ if model_hash.is_a?(Hash)
38
+ model = model_class.new(model_hash)
39
+ models << model
40
+ end
41
+ end if h.is_a?(Array)
42
+
43
+ return models
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,35 @@
1
+ module Dropio::Client::MultipartPost
2
+ def multipart_params=(param_hash={})
3
+ boundary_token = [Array.new(8) {rand(256)}].join
4
+ self.content_type = "multipart/form-data; boundary=#{boundary_token}"
5
+ boundary_marker = "--#{boundary_token}\r\n"
6
+ self.body = param_hash.map { |param_name, param_value|
7
+ unless param_value.nil?
8
+ boundary_marker + case param_value
9
+ when String
10
+ text_to_multipart(param_name, param_value.to_s)
11
+ when File
12
+ file_to_multipart(param_name, param_value)
13
+ end
14
+ end
15
+ }.join('') + "--#{boundary_token}--\r\n"
16
+ end
17
+
18
+ protected
19
+ def file_to_multipart(key,file)
20
+ filename = File.basename(file.path)
21
+ mime_types = MIME::Types.of(filename)
22
+ mime_type = mime_types.empty? ? "application/octet-stream" : mime_types.first.content_type
23
+ part = "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{filename}\"\r\n"
24
+ part += "Content-Transfer-Encoding: binary\r\n"
25
+ part += "Content-Type: #{mime_type}\r\n\r\n#{file.read}\r\n"
26
+ end
27
+
28
+ def text_to_multipart(key,value)
29
+ "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n#{value}\r\n"
30
+ end
31
+ end
32
+
33
+ class Net::HTTP::Post
34
+ include Dropio::Client::MultipartPost
35
+ end
@@ -0,0 +1,321 @@
1
+ require 'rbconfig'
2
+
3
+ class Dropio::Client
4
+ include Singleton
5
+
6
+ # Generates a user agent string.
7
+ def self.user_agent_string
8
+ ruby_version = %w{MAJOR MINOR TEENY}.map { |k| Config::CONFIG[k] }.join(".")
9
+ "DropioAPI-Ruby/#{Dropio::VERSION} (Ruby #{ruby_version} #{Config::CONFIG["host"]}; +http://dropio.rubyforge.org/)"
10
+ end
11
+
12
+ # The default set of headers for each request.
13
+ DEFAULT_HEADER = {
14
+ 'User-Agent' => user_agent_string,
15
+ 'Accept' => 'application/json'
16
+ }
17
+
18
+ # Takes a drop name and optional token and returns a +Drop+ or errors.
19
+ def find_drop(drop_name, token = nil)
20
+ uri = URI::HTTP.build({:path => drop_path(drop_name), :query => get_request_tokens(token)})
21
+ req = Net::HTTP::Get.new(uri.request_uri, DEFAULT_HEADER)
22
+ drop = nil
23
+ complete_request(req) { |body| drop = Mapper.map_drops(body) }
24
+ drop
25
+ end
26
+
27
+ # Finds a collection of +Asset+ objects for a given +Drop+.
28
+ def find_assets(drop, page = 1)
29
+ token = get_default_token(drop)
30
+ uri = URI::HTTP.build({:path => asset_path(drop), :query => get_request_tokens(token) + "&page=#{page}"})
31
+ req = Net::HTTP::Get.new(uri.request_uri, DEFAULT_HEADER)
32
+ assets = nil
33
+ complete_request(req) { |body| assets = Mapper.map_assets(drop, body) }
34
+ assets
35
+ end
36
+
37
+ # Finds a collection of +Comment+ objects for a given +Asset+.
38
+ def find_comments(asset)
39
+ token = get_default_token(asset.drop)
40
+ uri = URI::HTTP.build({:path => comment_path(asset.drop, asset), :query => get_request_tokens(token)})
41
+ req = Net::HTTP::Get.new(uri.request_uri, DEFAULT_HEADER)
42
+ comments = nil
43
+ complete_request(req) { |body| comments = Mapper.map_comments(asset, body) }
44
+ comments
45
+ end
46
+
47
+ # Creates a drop with an +attributes+ hash.
48
+ # Valid attributes: name (string), guests_can_comment (boolean), guests_can_add (boolean), guests_can_delete (boolean), expiration_length (string), password (string), admin_password (string), and premium_code (string)
49
+ # Descriptions can be found here: http://groups.google.com/group/dropio-api/web/full-api-documentation
50
+ def create_drop(attributes = {})
51
+ uri = URI::HTTP.build({:path => drop_path})
52
+ form = create_form(attributes)
53
+ req = Net::HTTP::Post.new(uri.request_uri, DEFAULT_HEADER)
54
+ req.set_form_data(form)
55
+ drop = nil
56
+ complete_request(req) { |body| drop = Mapper.map_drops(body) }
57
+ drop
58
+ end
59
+
60
+ # Saves a +Drop+ back to drop.io
61
+ def save_drop(drop)
62
+ uri = URI::HTTP.build({:path => drop_path(drop) })
63
+ token = get_admin_token(drop)
64
+ form = create_form :token => token,
65
+ :expiration_length => drop.expiration_length,
66
+ :guests_can_comment => drop.guests_can_comment,
67
+ :premium_code => drop.premium_code,
68
+ :guests_can_add => drop.guests_can_add,
69
+ :guests_can_delete => drop.guests_can_delete,
70
+ :password => drop.password,
71
+ :admin_password => drop.admin_password
72
+ req = Net::HTTP::Put.new(uri.request_uri, DEFAULT_HEADER)
73
+ req.set_form_data(form)
74
+ drop = nil
75
+ complete_request(req) { |body| drop = Mapper.map_drops(body) }
76
+ drop
77
+ end
78
+
79
+ # Destroys a +Drop+
80
+ def destroy_drop(drop)
81
+ token = get_admin_token(drop)
82
+ uri = URI::HTTP.build({:path => drop_path(drop)})
83
+ form = create_form( { :token => token })
84
+ req = Net::HTTP::Delete.new(uri.request_uri, DEFAULT_HEADER)
85
+ req.set_form_data(form)
86
+ complete_request(req)
87
+ true
88
+ end
89
+
90
+ # Adds a file to a +Drop+
91
+ def add_file(drop, file_path)
92
+ token = get_default_token(drop)
93
+ asset = nil
94
+
95
+ File.open(file_path, 'r') do |file|
96
+ uri = URI.parse(Dropio.upload_url)
97
+ req = Net::HTTP::Post.new(uri.path, DEFAULT_HEADER)
98
+ form = create_form( { :drop_name => drop.name, :token => token , :file => file } )
99
+ req.multipart_params = form
100
+ complete_request(req, uri.host) { |body| asset = Mapper.map_assets(drop, body) }
101
+ end
102
+
103
+ asset
104
+ end
105
+
106
+ # Creates a note +Asset+
107
+ def create_note(drop, title, contents)
108
+ token = get_default_token(drop)
109
+ uri = URI::HTTP.build({:path => asset_path(drop)})
110
+ form = create_form( { :token => token, :title => title, :contents => contents })
111
+ req = Net::HTTP::Post.new(uri.request_uri, DEFAULT_HEADER)
112
+ req.set_form_data(form)
113
+ asset = nil
114
+ complete_request(req) { |body| asset = Mapper.map_assets(drop, body) }
115
+ asset
116
+ end
117
+
118
+ # Creates a link +Asset+
119
+ def create_link(drop, url, title = nil, description = nil)
120
+ token = get_default_token(drop)
121
+ uri = URI::HTTP.build({:path => asset_path(drop)})
122
+ form = create_form( { :token => token, :url => url, :title => title, :description => description })
123
+ req = Net::HTTP::Post.new(uri.request_uri, DEFAULT_HEADER)
124
+ req.set_form_data(form)
125
+ asset = nil
126
+ complete_request(req) { |body| asset = Mapper.map_assets(drop, body) }
127
+ asset
128
+ end
129
+
130
+ # Saves a +Comment+, requires admin token.
131
+ def save_comment(comment)
132
+ token = get_default_token(comment.asset.drop)
133
+ uri = URI::HTTP.build({:path => comment_path(comment.asset.drop, comment.asset, comment)})
134
+ form = create_form( { :token => token, :contents => comment.contents })
135
+ req = Net::HTTP::Put.new(uri.request_uri, DEFAULT_HEADER)
136
+ req.set_form_data(form)
137
+ complete_request(req) { |body| comment = Mapper.map_comments(comment.asset, body) }
138
+ comment
139
+ end
140
+
141
+ # Destroys a +Comment+, requires admin token.
142
+ def destroy_comment(comment)
143
+ token = get_admin_token(comment.asset.drop)
144
+ uri = URI::HTTP.build({:path => comment_path(comment.asset.drop, comment.asset, comment)})
145
+ form = create_form( { :token => token })
146
+ req = Net::HTTP::Delete.new(uri.request_uri, DEFAULT_HEADER)
147
+ req.set_form_data(form)
148
+ complete_request(req)
149
+ true
150
+ end
151
+
152
+ # Creates a +Comment+
153
+ def create_comment(asset, contents)
154
+ token = get_default_token(asset.drop)
155
+ uri = URI::HTTP.build({:path => comment_path(asset.drop, asset)})
156
+ form = create_form( { :token => token, :contents => contents })
157
+ req = Net::HTTP::Post.new(uri.request_uri, DEFAULT_HEADER)
158
+ req.set_form_data(form)
159
+ comment = nil
160
+ complete_request(req) { |body| comment = Mapper.map_comments(asset, body) }
161
+ comment
162
+ end
163
+
164
+ # Sends an +Asset+ (of type Document) to a +fax_number+
165
+ def send_to_fax(asset, fax_number)
166
+ params = { :medium => "fax", :fax_number => fax_number }
167
+ send_asset(asset,params)
168
+ end
169
+
170
+ # Sends an email +message+, containing the +asset+ to a list of +emails+
171
+ def send_to_emails(asset, emails = [], message = nil)
172
+ params = { :medium => "email", :emails => emails.join(","), :message => message }
173
+ send_asset(asset,params)
174
+ end
175
+
176
+ # Sends an +Asset+ to a given +Drop+ with +drop_name+
177
+ def send_to_drop(asset, drop_name)
178
+ params = { :medium => "drop", :drop_name => drop_name }
179
+ send_asset(asset,params)
180
+ end
181
+
182
+ # Saves an +Asset+ back to drop.io
183
+ def save_asset(asset)
184
+ token = get_default_token(asset.drop)
185
+ uri = URI::HTTP.build({:path => asset_path(asset.drop, asset)})
186
+ form = create_form({ :token => token,
187
+ :title => asset.title,
188
+ :url => asset.url,
189
+ :description => asset.description,
190
+ :contents => asset.contents })
191
+ req = Net::HTTP::Put.new(uri.request_uri, DEFAULT_HEADER)
192
+ req.set_form_data(form)
193
+ complete_request(req) { |body| asset = Mapper.map_assets(asset.drop, body)}
194
+ asset
195
+ end
196
+
197
+ # Destroys an +Asset+
198
+ def destroy_asset(asset)
199
+ token = get_default_token(asset.drop)
200
+ uri = URI::HTTP.build({:path => asset_path(asset.drop, asset)})
201
+ form = create_form( { :token => token })
202
+ req = Net::HTTP::Delete.new(uri.request_uri, DEFAULT_HEADER)
203
+ req.set_form_data(form)
204
+ complete_request(req)
205
+ true
206
+ end
207
+
208
+ # Generates the authenticated +Drop+ url.
209
+ def generate_drop_url(drop)
210
+ signed_url(drop)
211
+ end
212
+
213
+ # Generates the authenticated +Asset+ url.
214
+ def generate_asset_url(asset)
215
+ signed_url(asset.drop, asset)
216
+ end
217
+
218
+
219
+ protected
220
+
221
+ def signed_url(drop, asset = nil)
222
+ # 10 minute window.
223
+ expires = (Time.now.utc + 10*60).to_i
224
+ token = get_default_token(drop)
225
+ path = Dropio.base_url + "/#{drop.name}"
226
+ path += "/asset/#{asset.name}" if asset
227
+ path += "/from_api"
228
+ sig = Digest::SHA1.hexdigest("#{expires}+#{token}+#{drop.name}")
229
+ path + "?expires=#{expires}&signature=#{sig}"
230
+ end
231
+
232
+ def create_form(options = {})
233
+ { :api_key => Dropio.api_key, :format => 'json', :version => '1.0' }.merge(options)
234
+ end
235
+
236
+ def send_asset(asset, params = {})
237
+ token = get_default_token(asset.drop)
238
+ uri = URI::HTTP.build({:path => send_to_path(asset.drop, asset)})
239
+ form = create_form( { :token => token }.merge(params) )
240
+ req = Net::HTTP::Post.new(uri.request_uri, DEFAULT_HEADER)
241
+ req.set_form_data(form)
242
+ complete_request(req)
243
+ true
244
+ end
245
+
246
+ def get_default_token(drop)
247
+ drop.admin_token || drop.guest_token
248
+ end
249
+
250
+ def get_admin_token(drop)
251
+ drop ? drop.admin_token : nil
252
+ end
253
+
254
+ def get_request_tokens(token = '')
255
+ "api_key=#{Dropio.api_key}&token=#{token}&version=1.0&format=json"
256
+ end
257
+
258
+ # Creates a path directly to a comment resource or a collection of comments.
259
+ def comment_path(drop, asset, comment = nil)
260
+ comment_id = (comment) ? comment.id.to_s : ''
261
+ return asset_path(drop,asset) + "/comments/" + comment_id
262
+ end
263
+
264
+ # Creates a path directly to an asset resource or collection of assets.
265
+ def asset_path(drop, asset = nil)
266
+ asset_name = (asset) ? asset.name : ''
267
+ return drop_path(drop) + "/assets/" + asset_name
268
+ end
269
+
270
+ # Creates a path directly to a drop resource or collection of drops.
271
+ def drop_path(drop = nil)
272
+ drop_name = case drop
273
+ when Dropio::Drop
274
+ drop.name
275
+ when String
276
+ drop
277
+ when nil
278
+ ''
279
+ else
280
+ raise ArgumentError, "Client#drop_path takes a Drop or a String, got #{drop.inspect}"
281
+ end
282
+
283
+ return "/drops/" + drop_name
284
+ end
285
+
286
+ # Creates a path for sending an +Asset+
287
+ def send_to_path(drop, asset)
288
+ return asset_path(drop, asset) + "/send_to"
289
+ end
290
+
291
+ # Starts and completes the given request. Returns or yields the response body.
292
+ def complete_request(request, host = URI.parse(Dropio.api_url).host)
293
+ http = Net::HTTP.new(host)
294
+ # Set to debug http output.
295
+ # http.set_debug_output $stderr
296
+ response = http.start { |http| http.request(request) }
297
+
298
+ case response
299
+ when Net::HTTPSuccess then yield response.body if block_given?
300
+ when Net::HTTPBadRequest then raise Dropio::RequestError, parse_error_message(response)
301
+ when Net::HTTPForbidden then raise Dropio::AuthorizationError, parse_error_message(response)
302
+ when Net::HTTPNotFound then raise Dropio::MissingResourceError, parse_error_message(response)
303
+ when Net::HTTPServerError then raise Dropio::ServerError, "There was a problem connecting to Drop.io."
304
+ else raise "Received an unexpected HTTP response: #{response}"
305
+ end
306
+
307
+ response.body
308
+ end
309
+
310
+ # Extracts the error message from the response for the exception.
311
+ def parse_error_message(response)
312
+ error_hash = JSON.parse(response.body) rescue nil
313
+
314
+ if (error_hash && error_hash.is_a?(Hash) && error_hash["response"] && error_hash["response"]["message"])
315
+ return error_hash["response"]["message"]
316
+ else
317
+ return "There was a problem connecting to Drop.io."
318
+ end
319
+ end
320
+
321
+ end
@@ -0,0 +1,15 @@
1
+ class Dropio::Comment < Dropio::Resource
2
+
3
+ attr_accessor :id, :contents, :created_at, :asset
4
+
5
+ # Saves the comment back to drop.io
6
+ def save
7
+ Dropio::Client.instance.save_comment(self)
8
+ end
9
+
10
+ # Destroys the comment on drop.io. Don't try to use an Comment after destroying it.
11
+ def destroy
12
+ Dropio::Client.instance.destroy_comment(self)
13
+ end
14
+
15
+ end