adobeshare 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2007-10-08
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 KATO Hideyuki
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,12 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ lib/adobeshare.rb
7
+ lib/adobeshare/version.rb
8
+ lib/adobeshare/client.rb
9
+ lib/adobeshare/node.rb
10
+ examples/sample.rb
11
+ examples/config.yaml.sample
12
+ setup.rb
data/README.txt ADDED
@@ -0,0 +1,70 @@
1
+ = AdobeShare::Client -- Adobe Share API for Ruby
2
+
3
+ AdobeShare::Client is a library for upload and download documents using REST APIs for Adobe Share.
4
+
5
+ * http://labs.adobe.com/technologies/share/
6
+ * http://labs.adobe.com/wiki/index.php/Share:API
7
+
8
+ == Example
9
+
10
+ === Create client class
11
+
12
+ client = AdobeShare::Client.new
13
+ if you want to access via proxy,
14
+ add proxy param Adobe::Client.new "http://your.proxy.server:8080/"
15
+
16
+ === Set credentials
17
+
18
+ client.apikey = Your API Key
19
+ client.secret = Your Shared Secret
20
+ client.username = Your Adobe ID
21
+ client.password = Your Adobe ID passowrd
22
+
23
+ === Login
24
+
25
+ client.login
26
+
27
+ === Access your Adobe Share Documents
28
+
29
+ ==== Upload
30
+
31
+ client.add_file `binary obj`, "test.pdf", "This is Test File"
32
+
33
+ ==== Download
34
+
35
+ client.get_source `nodeid`
36
+
37
+ ==== Delete
38
+
39
+ client.delete_node `nodeid`
40
+
41
+
42
+ # `nodeid` is the same as `docid` in the Flash web interface.
43
+ # `nodeid` indicates both the documents and the folders. Maybe.
44
+
45
+ === Logout
46
+ client.logout
47
+
48
+ For details, please see examples/sample.rb
49
+
50
+ == TODO
51
+
52
+ * Test::Unit !!!
53
+
54
+ and, these APIs are not implemented.
55
+ * Moving or renaming a file or folder
56
+ * Sharing a file
57
+ * Adding or removing recipients from a share
58
+
59
+ == Requirements
60
+
61
+ * httpclient
62
+ * rubygems
63
+
64
+ == Installation
65
+
66
+ * gem install adobeshare
67
+
68
+ == Author
69
+
70
+ * KATO Hideyuki <hideyuki at kato dot jp>
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -0,0 +1,5 @@
1
+ ---
2
+ apikey: Your API Key
3
+ secret: Your Shared Secret
4
+ username: Your Adobe ID
5
+ password: Your Adobe ID passowrd
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'adobeshare'
4
+ require 'yaml'
5
+ require 'pp'
6
+
7
+ class SampleClient
8
+ def initialize
9
+ config = YAML.load_file("config.yaml")
10
+ @client = AdobeShare::Client.new
11
+ @client.apikey = config["apikey"]
12
+ @client.secret = config["secret"]
13
+ @client.username = config["username"]
14
+ @client.password = config["password"]
15
+ end
16
+
17
+ def login
18
+ puts "=== Login ==="
19
+ @client.login
20
+ puts "sessionid : #{@client.sessionid}"
21
+ #puts "secret : #{@client.secret}"
22
+ puts "name : #{@client.name}"
23
+ end
24
+
25
+ def logout
26
+ puts "=== Logout ==="
27
+ @client.logout
28
+ end
29
+
30
+ def list nodeid=nil
31
+ puts "=== Contents List ==="
32
+ node = @client.get_node
33
+ children = node[:children]
34
+ children.each{|e|
35
+ puts "#{e[:nodeid]} : #{e[:name]}" if e[:hascontent]
36
+ }
37
+ puts ""
38
+ puts children.size.to_s + " documents(or folders)"
39
+ puts " in this folder (nodeid=#{node[:nodeid]})"
40
+ end
41
+
42
+ def info nodeid
43
+ puts "=== Content Info ==="
44
+ node = @client.get_node nodeid
45
+ pp node
46
+ end
47
+
48
+ def upload filename
49
+ list
50
+ puts "=== Upload ==="
51
+ return unless filename
52
+ node = @client.get_node
53
+ data = nil
54
+ File.open(filename, "rb"){|f|
55
+ data = f.read
56
+ }
57
+ puts "Uploading file `#{filename}` ..."
58
+ @client.add_file data, File.basename(filename), "Test File", node[:nodeid]
59
+ list
60
+ end
61
+
62
+ def download nodeid
63
+ puts "=== File Download ==="
64
+ node = @client.get_node nodeid
65
+ pp node
66
+
67
+ if node[:hascontent]
68
+ filename = node[:name]
69
+ puts "Downloading file `#{filename}` ..."
70
+ data = @client.get_source node[:nodeid]
71
+ File.open(filename, "wb"){|f|
72
+ f.write(data)
73
+ }
74
+ if node[:thumbnailstate] == "1"
75
+ thumbnail = node[:name] + ".thumb.jpg"
76
+ puts "Downloading file `#{thumbnail}` ..."
77
+ data = @client.get_thumbnail node[:nodeid]
78
+ File.open(thumbnail, "wb"){|f|
79
+ f.write(data)
80
+ }
81
+ end
82
+ end
83
+ end
84
+
85
+ def delete nodeid
86
+ node = info nodeid
87
+ puts "=== File Delete ==="
88
+ puts ""
89
+ print "Are you OK? [yN]"
90
+ ans = STDIN.getc.chr.downcase
91
+ return if ans != 'y'
92
+ @client.delete_node nodeid
93
+ list
94
+ end
95
+ end
96
+
97
+ if __FILE__ == $0
98
+ sample = SampleClient.new
99
+ if ARGV[0]
100
+ command = ARGV[0]
101
+ param = ARGV[1]
102
+ sample.login
103
+ sample.send(command, param)
104
+ sample.logout
105
+ else
106
+ puts "Usage: #{$0} command param"
107
+ puts "commands:"
108
+ puts " list"
109
+ puts " info `nodeid`"
110
+ puts " upload `filename`"
111
+ puts " download `nodeid`"
112
+ puts " delete `nodeid`"
113
+ end
114
+ end
data/lib/adobeshare.rb ADDED
@@ -0,0 +1,9 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'adobeshare/version'
4
+ require 'adobeshare/client'
5
+ require 'adobeshare/node'
6
+
7
+ module AdobeShare
8
+
9
+ end
@@ -0,0 +1,303 @@
1
+ #
2
+ # Adobe Share API for Ruby
3
+ #
4
+ # Copyright (c) KATO Hideyuki, 2007. All rights reserved.
5
+ #
6
+ require 'http-access2'
7
+ require 'rexml/document'
8
+
9
+ include REXML
10
+
11
+ module AdobeShare
12
+ DEFAULT_ENDPOINT = "https://api.share.adobe.com/webservices/api/v1/" # :nodoc:
13
+ ENDPOINT_AUTH = DEFAULT_ENDPOINT + "auth/" # :nodoc:
14
+ ENDPOINT_SESSIONS = DEFAULT_ENDPOINT + "sessions/" # :nodoc:
15
+ ENDPOINT_DC = DEFAULT_ENDPOINT + "dc/" # :nodoc:
16
+
17
+ #
18
+ # Client Access Class
19
+ #
20
+ class Client
21
+ # User-Agent
22
+ UA = "AdobeShare::Client-#{VERSION::STRING}" # :nodoc:
23
+
24
+ # User's API Key:
25
+ attr_accessor :apikey
26
+ # User's session shared secret
27
+ attr_accessor :secret
28
+ # User's Adobe ID
29
+ attr_accessor :username
30
+ # User's password
31
+ attr_accessor :password
32
+ # User's name
33
+ attr_reader :name
34
+ # User's session ID
35
+ attr_reader :sessionid
36
+
37
+ #
38
+ def initialize proxy=nil
39
+ @client = HTTPAccess2::Client.new(proxy)
40
+ end
41
+
42
+ # Login to use Adobe Share service
43
+ def login
44
+ authtoken = get_authtoken
45
+ start_sessions authtoken
46
+ end
47
+
48
+ # Logout from the servce
49
+ def logout
50
+ end_sessions
51
+ end
52
+
53
+ # Get a list of nodes (files and folders) in a user's account
54
+ def get_node(nodeid=nil)
55
+ if nodeid
56
+ uri = ENDPOINT_DC + nodeid + "/"
57
+ else
58
+ uri = ENDPOINT_DC
59
+ end
60
+ res = http_client_request("GET", uri)
61
+ node = Node.new res
62
+ node.to_hash
63
+ end
64
+
65
+ # Get the source of a document
66
+ def get_source nodeid
67
+ get_node_content nodeid, RENDITION_SOURCE
68
+ end
69
+
70
+ # Get the thumbnail of a document
71
+ def get_thumbnail nodeid
72
+ get_node_content nodeid, RENDITION_THUMBNAIL
73
+ end
74
+
75
+ # Get the specified rendition of a document
76
+ def get_node_content nodeid, rendition
77
+ uri = ENDPOINT_DC + nodeid + "/" + rendition + "/"
78
+ res = http_client_request("GET", uri)
79
+ end
80
+
81
+ # Delete a node
82
+ def delete_node nodeid
83
+ uri = ENDPOINT_DC + nodeid + "/"
84
+ res = http_client_request("DELETE", uri)
85
+ end
86
+
87
+ # Upload and add file
88
+ def add_file(data, filename, description, nodeid="", renditions=true)
89
+ uri = ENDPOINT_DC + nodeid + "/"
90
+
91
+ # request xml
92
+ req_xml = Element.new "request"
93
+ file = req_xml.add_element "file"
94
+ file.add_element "name"
95
+ file.add_element "description"
96
+ file.add_element "renditions"
97
+ file.elements["name"].text = filename
98
+ file.elements["description"].text = description
99
+ file.elements["renditions"].text = renditions
100
+ # FIXME
101
+ # XXX Is there any good library or something ???
102
+ # to make multipart/form-data ...
103
+ boundary = "mime-part-separator" + Time.new.to_i.to_s
104
+ req = "--#{boundary}\r\n"
105
+ req << "Content-Disposition: form-data; name=\"request\"\r\n"
106
+ req << "\r\n"
107
+ req << req_xml.to_s
108
+ req << "\r\n"
109
+ req << "--#{boundary}\r\n"
110
+ req << "Content-Disposition: form-data; name=\"file\"; filename=\"#{URI.encode(filename)}\"\r\n"
111
+ req << "Content-Type: application/octet-stream\r\n"
112
+ req << "Content-Transfer-Encoding: binary\r\n"
113
+ req << "\r\n"
114
+ req << data
115
+ req << "\r\n"
116
+ req << "--#{boundary}--\r\n"
117
+
118
+ headers = Hash.new
119
+ headers["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
120
+ res = http_client_request("POST", uri, req, headers)
121
+ end
122
+
123
+ private
124
+
125
+ # TODO this method is not tested
126
+ # Rename a node
127
+ def rename_node(nodeid, newname)
128
+ uri = ENDPOINT_DC + nodeid + "/?newname=" + newname
129
+ res = http_client_request("MOVE", uri)
130
+ end
131
+
132
+ # TODO this method is not tested
133
+ # Move a node
134
+ def move_node(nodeid, destnodeid, newname)
135
+ uri = ENDPOINT_DC + nodeid + "/?destnodeid=" + destnodeid + "&newname=" + URI.encode(newname)
136
+ res = http_client_request("MOVE", uri)
137
+ end
138
+
139
+ # TODO this method is not tested
140
+ # Replace file in an already existing node
141
+ def replace_file(file_name, description, nodeid, renditions=true)
142
+ add_file(file_name, description, nodeid, renditions)
143
+ end
144
+
145
+ # TODO this method is not tested
146
+ # Add new folder
147
+ def add_folder(name, description, nodeid)
148
+ if nodeid
149
+ uri = ENDPOINT_DC + nodeid + "/"
150
+ else
151
+ uri = ENDPOINT_DC
152
+ end
153
+ req = Element.new "request"
154
+ folder = req.add_element "folder"
155
+ folder.add_element "name"
156
+ folder.add_element "description"
157
+ folder.elements["name"].text = name
158
+ folder.elements["description"].text = description
159
+ res = http_client_request("POST", uri, req)
160
+ doc = Document.new res
161
+ end
162
+
163
+ # TODO this method is not tested
164
+ # Share a file
165
+ def share_file(nodeid, users, message, level)
166
+ uri = ENDPOINT_DC + nodeid + "/share/"
167
+ req = Element.new "request"
168
+ share = req.add_element "share"
169
+ users.each{|e|
170
+ user = Element.new "user"
171
+ user.text = e
172
+ share.add_element user
173
+ }
174
+ req.add_element "message"
175
+ req.add_element "level"
176
+ req.elements["message"].text = message
177
+ req.elements["level"].text = level
178
+ res = http_client_request("POST", uri, req)
179
+ doc = Document.new res
180
+ end
181
+
182
+ # TODO this method is not tested
183
+ # Unshare a file
184
+ def unshare_file(nodeid)
185
+ share_file(nodeid, nil, nil, 0)
186
+ end
187
+
188
+ # TODO this method is not tested
189
+ # Update a share file
190
+ def update_share(nodeid, users_to_add, users_to_remove, message)
191
+ uri = ENDPOINT_DC + nodeid + "/share/"
192
+ req = Element.new "request"
193
+ share = req.add_element "share"
194
+ users_to_add.each{|e|
195
+ user = Element.new "user"
196
+ user.text = e
197
+ share.add_element user
198
+ }
199
+ unshare = req.add_element "unshare"
200
+ users_to_remove.each{|e|
201
+ user = Element.new "user"
202
+ user.text = e
203
+ unshare.add_element user
204
+ }
205
+ req.add_element "message"
206
+ req.add_element "level"
207
+ req.elements["message"].text = message
208
+ res = http_client_request("POST", uri, req)
209
+ doc = Document.new res
210
+ end
211
+
212
+ private
213
+
214
+ # Requesting an authorization token
215
+ def get_authtoken
216
+ raise ParameterError unless @username && @password
217
+ uri = ENDPOINT_AUTH
218
+ req = Element.new "request"
219
+ req.add_element "username"
220
+ req.add_element "password"
221
+ req.elements["username"].text = username
222
+ req.elements["password"].text = password
223
+ res = http_client_request("POST", uri, req)
224
+ doc = Document.new res
225
+ authtoken = doc.elements['/response/authtoken/'].text
226
+ authtoken
227
+ end
228
+
229
+ # Starting a new session
230
+ def start_sessions authtoken
231
+ uri = ENDPOINT_SESSIONS
232
+ req = Element.new "request"
233
+ req.add_element "authtoken"
234
+ req.elements["authtoken"].text = authtoken
235
+ res = http_client_request("POST", uri, req)
236
+ doc = Document.new res
237
+ @sessionid = doc.elements['/response/sessionid/'].text
238
+ @secret = doc.elements['/response/secret'].text
239
+ @name = doc.elements['/response/name'].text
240
+ end
241
+
242
+ # Ending a session
243
+ def end_sessions
244
+ uri = ENDPOINT_SESSIONS + @sessionid +'/'
245
+ res = http_client_request("DELETE", uri)
246
+ @sessionid = nil
247
+ @secret = nil
248
+ end
249
+
250
+ # Make HTTP Headers (Authorization)
251
+ def make_headers(method, uri)
252
+ raise ParameterError unless @apikey && @secret
253
+ time = Time.new
254
+ calltime = time.to_i.to_s + sprintf("%06d", time.tv_usec)
255
+ data = "#{method} #{uri} #{calltime}"
256
+ sig = Digest::MD5.hexdigest(data + @secret)
257
+ headers = Hash.new
258
+ auth_string = "AdobeAuth "
259
+ auth_string << "sessionid=\"#{@sessionid}\"," if @sessionid
260
+ auth_string << "apikey=\"#{@apikey}\",data=\"#{data}\",sig=\"#{sig}\""
261
+ headers["Authorization"] = auth_string
262
+ headers["User-Agent"] = UA
263
+ headers
264
+ end
265
+
266
+ # Performs a generic HTTP request.
267
+ def http_client_request(method, uri_s, request=nil, header_add={})
268
+ uri_s << "?method=MOVE" if method == "MOVE"
269
+ uri = URI.parse uri_s
270
+ headers = make_headers method, uri
271
+ headers = headers.merge header_add
272
+ case method
273
+ when "GET"
274
+ res = @client.get(uri, nil, headers)
275
+ when "POST"
276
+ res = @client.post(uri, request, headers)
277
+ when "PUT"
278
+ res = @client.put(uri, request, headers)
279
+ when "DELETE"
280
+ res = @client.delete(uri, headers)
281
+ when "MOVE"
282
+ res = @client.post(uri, request, headers)
283
+ end
284
+ body = res.body.content
285
+ status_code = res.header.response_status_code
286
+ reason_phrase = res.header.reason_phrase
287
+ if status_code >= 500
288
+ raise ServerError, "#{status_code} #{reason_phrase}"
289
+ elsif status_code >= 400
290
+ body = res.body.content
291
+ raise RequestError, "#{status_code} #{reason_phrase} (#{body})"
292
+ end
293
+ body
294
+ end
295
+ end
296
+
297
+ class ServerError < RuntimeError
298
+ end
299
+ class RequestError < RuntimeError
300
+ end
301
+ class ParameterError < RuntimeError
302
+ end
303
+ end