1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
5 import httplib as httpclient
8 class httpUploadDataStream(object):
9 def __init__(self, progressCallback):
13 self._progressCallback = progressCallback
15 def write(self, data):
20 for n in xrange(0, blocks):
21 self._dataList.append(data[n*2048:n*2048+2048])
22 self._dataList.append(data[blocks*2048:])
23 self._totalLength += size
26 if self._readPos >= len(self._dataList):
28 ret = self._dataList[self._readPos]
30 if self._progressCallback is not None:
31 self._progressCallback(float(self._readPos / len(self._dataList)))
35 return self._totalLength
37 class Youmagine(object):
38 def __init__(self, authToken, progressCallback = None):
39 self._hostUrl = 'api.youmagine.com'
40 self._viewUrl = 'www.youmagine.com'
41 self._authUrl = 'https://www.youmagine.com/integrations/cura/authorized_integrations/new'
42 self._authToken = authToken
46 self._hostReachable = True
47 self._progressCallback = progressCallback
60 ('Creative Commons - Share Alike', 'cc'),
61 ('Creative Commons - Attribution-NonCommercial-ShareAlike', 'ccnc'),
65 def getAuthorizationUrl(self):
68 def getCategories(self):
69 return map(lambda n: n[0], self._categories)
71 def getLicenses(self):
72 return map(lambda n: n[0], self._licenses)
74 def setAuthToken(self, token):
75 self._authToken = token
79 def getAuthToken(self):
80 return self._authToken
82 def isHostReachable(self):
83 return self._hostReachable
85 def viewUrlForDesign(self, id):
86 return 'https://%s/designs/%d' % (self._viewUrl, id)
88 def editUrlForDesign(self, id):
89 return 'https://%s/designs/%d/edit' % (self._viewUrl, id)
91 def isAuthorized(self):
92 if self._authToken is None:
94 if self._userName is None:
95 #No username yet, try to request the username to see if the authToken is valid.
96 result = self._request('GET', '/authorized_integrations/%s/whoami.json' % (self._authToken))
99 self._authToken = None
101 self._userName = result['screen_name']
102 self._userID = result['id']
105 def createDesign(self, name, description, category, license):
106 res = self._request('POST', '/designs.json', {'design[name]': name, 'design[excerpt]': description, 'design[design_category_id]': filter(lambda n: n[0] == category, self._categories)[0][1], 'design[license]': filter(lambda n: n[0] == license, self._licenses)[0][1]})
112 def publishDesign(self, id):
113 res = self._request('PUT', '/designs/%d/mark_as/publish.json' % (id), {'ignore': 'me'})
119 def createDocument(self, designId, name, contents):
120 res = self._request('POST', '/designs/%d/documents.json' % (designId), {'document[name]': name, 'document[description]': 'Uploaded from Cura'}, {'document[file]': (name, contents)})
126 def createImage(self, designId, name, contents):
127 res = self._request('POST', '/designs/%d/images.json' % (designId), {'image[name]': name, 'image[description]': 'Uploaded from Cura'}, {'image[file]': (name, contents)})
133 def listDesigns(self):
134 res = self._request('GET', '/users/%s/designs.json' % (self._userID))
137 def _request(self, method, url, postData = None, files = None):
139 if self._authToken is not None:
140 url += '?auth_token=%s' % (self._authToken)
141 error = 'Failed to connect to %s' % self._hostUrl
142 for n in xrange(0, retryCount):
143 if self._http is None:
144 self._http = httpclient.HTTPSConnection(self._hostUrl)
146 if files is not None:
147 boundary = 'wL36Yn8afVp8Ag7AmP8qZ0SA4n1v9T'
148 s = httpUploadDataStream(self._progressCallback)
149 for k, v in files.iteritems():
152 s.write('--%s\r\n' % (boundary))
153 s.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (k, filename))
154 s.write('Content-Type: application/octet-stream\r\n')
155 s.write('Content-Transfer-Encoding: binary\r\n')
157 s.write(fileContents)
160 for k, v in postData.iteritems():
161 s.write('--%s\r\n' % (boundary))
162 s.write('Content-Disposition: form-data; name="%s"\r\n' % (k))
166 s.write('--%s--\r\n' % (boundary))
168 self._http.request(method, url, s, {"Content-type": "multipart/form-data; boundary=%s" % (boundary), "Content-Length": len(s)})
169 elif postData is not None:
170 self._http.request(method, url, urllib.urlencode(postData), {"Content-type": "application/x-www-form-urlencoded"})
172 self._http.request(method, url)
177 response = self._http.getresponse()
178 responseText = response.read()
183 if responseText == '':
185 return json.loads(responseText)
187 print response.getheaders()
189 error = 'Failed to decode JSON response'
190 self._hostReachable = False
191 return {'error': error}
194 #Fake Youmagine class to test without internet
195 class FakeYoumagine(Youmagine):
196 def __init__(self, authToken):
197 super(FakeYoumagine, self).__init__(authToken)
198 self._authUrl = 'file:///C:/Models/output.html'
199 self._authToken = None
201 def isAuthorized(self):
202 if self._authToken is None:
204 if self._userName is None:
205 self._userName = 'FakeYoumagine'
209 def isHostReachable(self):
212 def createDesign(self, name, description, category, license):
215 def publishDesign(self, id):
218 def createDocument(self, designId, name, contents):
219 print "Create document: %s" % (name)
220 f = open("C:/models/%s" % (name), "wb")
225 def createImage(self, designId, name, contents):
226 print "Create image: %s" % (name)
227 f = open("C:/models/%s" % (name), "wb")
232 def listDesigns(self):
235 def _request(self, method, url, postData = None, files = None):
236 print "Err: Tried to do request: %s %s" % (method, url)
239 ym = Youmagine('j3rY9kQF62ptuZF7vqbR')
240 if not ym.isAuthorized():
241 print "Failed to authorize"
243 for design in ym.listDesigns():