-
Notifications
You must be signed in to change notification settings - Fork 7
/
boxdotnet.py
260 lines (199 loc) · 8.46 KB
/
boxdotnet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
"""
Python bindings for the Box.net API
Copyright (c) 2007 Thomas Van Machelen <thomas dot vanmachelen at gmail dot com>
Copyright (c) 2007 John Stowers <john dot stowers at gmail dot com>
Upload, handler and XMLNode code adapted from flickrapi:
Copyright (c) 2007 Brian "Beej Jorgensen" Hall
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import urllib
import urllib2
import mimetools
import mimetypes
import os
import sys
from xml.dom.minidom import parseString
import xml.dom
def get_content_type(filename):
return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
########################################################################
# XML functionality
########################################################################
#-----------------------------------------------------------------------
class XMLNode:
"""XMLNode -- generic class for holding an XML node
xmlStr = \"\"\"<xml foo="32">
<name bar="10">Name0</name>
<name bar="11" baz="12">Name1</name>
</xml>\"\"\"
f = XMLNode.parseXML(xmlStr)
print f.elementName # xml
print f['foo'] # 32
print f.name # [<name XMLNode>, <name XMLNode>]
print f.name[0].elementName # name
print f.name[0]["bar"] # 10
print f.name[0].elementText # Name0
print f.name[1].elementName # name
print f.name[1]["bar"] # 11
print f.name[1]["baz"] # 12
"""
def __init__(self):
"""Construct an empty XML node."""
self.elementName=""
self.elementText=""
self.attrib={}
self.xml=""
def __setitem__(self, key, item):
"""Store a node's attribute in the attrib hash."""
self.attrib[key] = item
def __getitem__(self, key):
"""Retrieve a node's attribute from the attrib hash."""
return self.attrib[key]
#-----------------------------------------------------------------------
@classmethod
def parseXML(cls, xmlStr, storeXML=False):
"""Convert an XML string into a nice instance tree of XMLNodes.
xmlStr -- the XML to parse
storeXML -- if True, stores the XML string in the root XMLNode.xml
"""
def __parseXMLElement(element, thisNode):
"""Recursive call to process this XMLNode."""
thisNode.elementName = element.nodeName
#print element.nodeName
# add element attributes as attributes to this node
for i in range(element.attributes.length):
an = element.attributes.item(i)
thisNode[an.name] = an.nodeValue
for a in element.childNodes:
if a.nodeType == xml.dom.Node.ELEMENT_NODE:
child = XMLNode()
try:
list = getattr(thisNode, a.nodeName)
except AttributeError:
setattr(thisNode, a.nodeName, [])
# add the child node as an attrib to this node
list = getattr(thisNode, a.nodeName);
#print "appending child: %s to %s" % (a.nodeName, thisNode.elementName)
list.append(child);
__parseXMLElement(a, child)
elif a.nodeType == xml.dom.Node.TEXT_NODE:
thisNode.elementText += a.nodeValue
return thisNode
dom = parseString(xmlStr)
# get the root
rootNode = XMLNode()
if storeXML: rootNode.xml = xmlStr
return __parseXMLElement(dom.firstChild, rootNode)
class BoxDotNetError(Exception):
"""Exception class for errors received from Facebook."""
pass
class BoxDotNet(object):
END_POINT = 'http://www.box.net/api/1.0/rest?'
#The box.net return status codes are all over the show
# method_name : return_value_that_is_ok
RETURN_CODES = {
'get_ticket' : 'get_ticket_ok',
'get_auth_token' : 'get_auth_token_ok',
'get_account_tree' : 'listing_ok',
'logout' : 'logout_ok',
'create_folder' : 'create_ok',
'upload' : 'upload_ok',
'delete' : 's_delete_node'
}
def __init__(self, browser="firefox"):
self.browser = browser
self.__handlerCache={}
#encodes the args and handles params[] supplied in a list
@classmethod
def __url_encode_params(cls, params={}):
if not isinstance(params, dict):
raise Exception("You must pass a dictionary!")
params_list = []
for k,v in params.items():
if isinstance(v, list): params_list.extend([(k+'[]',x) for x in v])
else: params_list.append((k, v))
return urllib.urlencode(params_list)
@classmethod
def check_errors(cls, method, xml):
status = xml.status[0].elementText
if status == cls.RETURN_CODES[method]:
return
raise BoxDotNetError ("Box.net returned [%s] for action [%s]" % (status, method))
def login(self, api_key):
# get ticket
rsp = self.get_ticket (api_key=api_key)
ticket = rsp.ticket[0].elementText
# open url
url = "http://www.box.net/api/1.0/auth/%s" % ticket
os.system('%s "%s"' % (self.browser, url))
# get token
rsp = self.get_auth_token(api_key=api_key, ticket=ticket)
return rsp
def __getattr__(self, method, **arg):
"""
Handle all box.net calls
"""
if not self.__handlerCache.has_key(method):
def handler(_self = self, _method = method, **arg):
url = _self.END_POINT
arg["action"] = _method
postData = _self.__url_encode_params(params=arg)
# print "--url---------------------------------------------"
# print url
# print "--postData----------------------------------------"
# print postData
f = urllib.urlopen(url + postData)
data = f.read()
# print "--response----------------------------------------"
# print data
f.close()
xml = XMLNode.parseXML(data, True)
_self.check_errors(_method, xml)
return xml
self.__handlerCache[method] = handler;
return self.__handlerCache[method]
#-------------------------------------------------------------------
#-------------------------------------------------------------------
def upload(self, filename, **arg):
"""
Upload a file to box.net.
"""
if filename == None:
raise UploadException("filename OR jpegData must be specified")
# verify key names
for a in arg.keys():
if a != "api_key" and a != "auth_token" and a != "folder_id" and a != 'share':
sys.stderr.write("Box.net api: warning: unknown parameter \"%s\" sent to Box.net.upload\n" % (a))
url = 'http://upload.box.net/api/1.0/upload/%s/%s' % (arg['auth_token'], arg['folder_id'])
# construct POST data
boundary = mimetools.choose_boundary()
body = ""
# filename
body += "--%s\r\n" % (boundary)
body += 'Content-Disposition: form-data; name="share"\r\n\r\n'
body += "%s\r\n" % (arg['share'])
body += "--%s\r\n" % (boundary)
body += "Content-Disposition: form-data; name=\"file\";"
body += " filename=\"%s\"\r\n" % filename
body += "Content-Type: %s\r\n\r\n" % get_content_type(filename)
#print body
fp = file(filename, "rb")
data = fp.read()
fp.close()
postData = body.encode("utf_8") + data + \
("\r\n--%s--" % (boundary)).encode("utf_8")
request = urllib2.Request(url)
request.add_data(postData)
request.add_header("Content-Type", \
"multipart/form-data; boundary=%s" % boundary)
response = urllib2.urlopen(request)
rspXML = response.read()
return XMLNode.parseXML(rspXML)