chiark / gitweb /
Remove all the absolute imports, as they are unneeded.
[cura.git] / Cura / util / youmagine.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
2
3 import json
4 import httplib as httpclient
5 import urllib
6
7 class httpUploadDataStream(object):
8         def __init__(self, progressCallback):
9                 self._dataList = []
10                 self._totalLength = 0
11                 self._readPos = 0
12                 self._progressCallback = progressCallback
13
14         def write(self, data):
15                 size = len(data)
16                 if size < 1:
17                         return
18                 blocks = size / 2048
19                 for n in xrange(0, blocks):
20                         self._dataList.append(data[n*2048:n*2048+2048])
21                 self._dataList.append(data[blocks*2048:])
22                 self._totalLength += size
23
24         def read(self, size):
25                 if self._readPos >= len(self._dataList):
26                         return None
27                 ret = self._dataList[self._readPos]
28                 self._readPos += 1
29                 if self._progressCallback is not None:
30                         self._progressCallback(float(self._readPos / len(self._dataList)))
31                 return ret
32
33         def __len__(self):
34                 return self._totalLength
35
36 class Youmagine(object):
37         def __init__(self, authToken, progressCallback = None):
38                 self._hostUrl = 'api.youmagine.com'
39                 self._viewUrl = 'www.youmagine.com'
40                 self._authUrl = 'https://www.youmagine.com/integrations/cura/authorized_integrations/new'
41                 self._authToken = authToken
42                 self._userName = None
43                 self._userID = None
44                 self._http = None
45                 self._hostReachable = True
46                 self._progressCallback = progressCallback
47                 self._categories = [
48                         ('Art', 2),
49                         ('Fashion', 3),
50                         ('For your home', 4),
51                         ('Gadget', 5),
52                         ('Games', 6),
53                         ('Jewelry', 7),
54                         ('Maker/DIY', 8),
55                         ('Miniatures', 9),
56                         ('Toys', 10),
57                         ('3D printer parts and enhancements', 11),
58                         ('Other', 1),
59                 ]
60                 self._licenses = [
61                         ('Creative Commons - Attribution Share Alike', 'ccbysa'),
62                         ('Creative Commons - Attribution Non-Commercial ShareAlike', 'ccbyncsa'),
63                         ('Creative Commons - Attribution No Derivatives', 'ccbynd'),
64                         ('Creative Commons - Attribution Non-Commercial No Derivatives', 'ccbyncsa'),
65                         ('GPLv3', 'gplv3'),
66                 ]
67
68         def getAuthorizationUrl(self):
69                 return self._authUrl
70
71         def getCategories(self):
72                 return map(lambda n: n[0], self._categories)
73
74         def getLicenses(self):
75                 return map(lambda n: n[0], self._licenses)
76
77         def setAuthToken(self, token):
78                 self._authToken = token
79                 self._userName = None
80                 self._userID = None
81
82         def getAuthToken(self):
83                 return self._authToken
84
85         def isHostReachable(self):
86                 return self._hostReachable
87
88         def viewUrlForDesign(self, id):
89                 return 'https://%s/designs/%d' % (self._viewUrl, id)
90
91         def editUrlForDesign(self, id):
92                 return 'https://%s/designs/%d/edit' % (self._viewUrl, id)
93
94         def isAuthorized(self):
95                 if self._authToken is None:
96                         return False
97                 if self._userName is None:
98                         #No username yet, try to request the username to see if the authToken is valid.
99                         result = self._request('GET', '/authorized_integrations/%s/whoami.json' % (self._authToken))
100
101                         if 'error' in result:
102                                 self._authToken = None
103                                 return False
104                         self._userName = result['screen_name']
105                         self._userID = result['id']
106                 return True
107
108         def createDesign(self, name, description, category, license):
109                 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]})
110                 if 'id' in res:
111                         return res['id']
112                 print res
113                 return None
114
115         def publishDesign(self, id):
116                 res = self._request('PUT', '/designs/%d/mark_as/publish.json' % (id), {'ignore': 'me'})
117                 if res is not None:
118                         return False
119                 return True
120
121         def createDocument(self, designId, name, contents):
122                 res = self._request('POST', '/designs/%d/documents.json' % (designId), {'document[name]': name, 'document[description]': 'Uploaded from Cura'}, {'document[file]': (name, contents)})
123                 if 'id' in res:
124                         return res['id']
125                 print res
126                 return None
127
128         def createImage(self, designId, name, contents):
129                 res = self._request('POST', '/designs/%d/images.json' % (designId), {'image[name]': name, 'image[description]': 'Uploaded from Cura'}, {'image[file]': (name, contents)})
130                 if 'id' in res:
131                         return res['id']
132                 print res
133                 return None
134
135         def listDesigns(self):
136                 res = self._request('GET', '/users/%s/designs.json' % (self._userID))
137                 return res
138
139         def _request(self, method, url, postData = None, files = None):
140                 retryCount = 2
141                 if self._authToken is not None:
142                         url += '?auth_token=%s' % (self._authToken)
143                 error = 'Failed to connect to %s' % self._hostUrl
144                 for n in xrange(0, retryCount):
145                         if self._http is None:
146                                 self._http = httpclient.HTTPSConnection(self._hostUrl)
147                         try:
148                                 if files is not None:
149                                         boundary = 'wL36Yn8afVp8Ag7AmP8qZ0SA4n1v9T'
150                                         s = httpUploadDataStream(self._progressCallback)
151                                         for k, v in files.iteritems():
152                                                 filename = v[0]
153                                                 fileContents = v[1]
154                                                 s.write('--%s\r\n' % (boundary))
155                                                 s.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (k, filename))
156                                                 s.write('Content-Type: application/octet-stream\r\n')
157                                                 s.write('Content-Transfer-Encoding: binary\r\n')
158                                                 s.write('\r\n')
159                                                 s.write(fileContents)
160                                                 s.write('\r\n')
161
162                                         for k, v in postData.iteritems():
163                                                 s.write('--%s\r\n' % (boundary))
164                                                 s.write('Content-Disposition: form-data; name="%s"\r\n' % (k))
165                                                 s.write('\r\n')
166                                                 s.write(str(v))
167                                                 s.write('\r\n')
168                                         s.write('--%s--\r\n' % (boundary))
169
170                                         self._http.request(method, url, s, {"Content-type": "multipart/form-data; boundary=%s" % (boundary), "Content-Length": len(s)})
171                                 elif postData is not None:
172                                         self._http.request(method, url, urllib.urlencode(postData), {"Content-type": "application/x-www-form-urlencoded"})
173                                 else:
174                                         self._http.request(method, url)
175                         except IOError:
176                                 self._http.close()
177                                 continue
178                         try:
179                                 response = self._http.getresponse()
180                                 responseText = response.read()
181                         except:
182                                 self._http.close()
183                                 continue
184                         try:
185                                 if responseText == '':
186                                         return None
187                                 return json.loads(responseText)
188                         except ValueError:
189                                 print response.getheaders()
190                                 print responseText
191                                 error = 'Failed to decode JSON response'
192                 self._hostReachable = False
193                 return {'error': error}
194
195
196 #Fake Youmagine class to test without internet
197 class FakeYoumagine(Youmagine):
198         def __init__(self, authToken, callback):
199                 super(FakeYoumagine, self).__init__(authToken)
200                 self._authUrl = 'file:///C:/Models/output.html'
201                 self._authToken = None
202
203         def isAuthorized(self):
204                 if self._authToken is None:
205                         return False
206                 if self._userName is None:
207                         self._userName = 'FakeYoumagine'
208                         self._userID = '1'
209                 return True
210
211         def isHostReachable(self):
212                 return True
213
214         def createDesign(self, name, description, category, license):
215                 return 1
216
217         def publishDesign(self, id):
218                 pass
219
220         def createDocument(self, designId, name, contents):
221                 print "Create document: %s" % (name)
222                 f = open("C:/models/%s" % (name), "wb")
223                 f.write(contents)
224                 f.close()
225                 return 1
226
227         def createImage(self, designId, name, contents):
228                 print "Create image: %s" % (name)
229                 f = open("C:/models/%s" % (name), "wb")
230                 f.write(contents)
231                 f.close()
232                 return 1
233
234         def listDesigns(self):
235                 return []
236
237         def _request(self, method, url, postData = None, files = None):
238                 print "Err: Tried to do request: %s %s" % (method, url)