`Connection()` object works, `diaply/client.py` partialy ported
[diaspy.git] / diaspy / client.py
1 import requests
2 import re
3 import json
4 import diaspy.models
5 import diaspy.connection
6
7
8 class Client:
9 """This is the client class to connect to Diaspora.
10 """
11 def __init__(self, pod, username, password):
12 """
13 :param pod: The complete url of the diaspora pod to use.
14 :type pod: str
15 :param username: The username used to log in.
16 :type username: str
17 :param password: The password used to log in.
18 :type password: str
19 """
20 self.connection = diaspy.connection.Connection(pod, username, password)
21 self.connection.login()
22 self.pod = pod
23 self._post_data = {}
24
25 def _sessionget(self, string):
26 """This method gets data from session.
27 Performs additional checks if needed.
28
29 Example:
30 To obtain 'foo' from pod one should call `_sessionget('foo')`.
31
32 :param string: URL to get without the pod's URL and slash eg. 'stream'.
33 :type string: str
34 """
35 request = self.connection.get(string)
36 return request
37
38 def _sessionpost(self, string, data, headers={}, params={}):
39 """This method posts data to session.
40 Performs additional checks if needed.
41
42 Example:
43 To post to 'foo' one should call `_sessionpost('foo', data={})`.
44
45 :param string: URL to post without the pod's URL and slash eg. 'status_messages'.
46 :type string: str
47 :param data: Data to post.
48 :param headers: Headers (optional).
49 :type headers: dict
50 :param params: Parameters (optional).
51 :type params: dict
52 """
53 request = self.connection.post(string, data, headers, params)
54 return request
55
56 def _sessiondelete(self, string, data, headers={}):
57 """This method lets you send delete request to session.
58 Performs additional checks if needed.
59
60 :param string: URL to use.
61 :type string: str
62 :param data: Data to use.
63 :param headers: Headers to use (optional).
64 :type headers: dict
65 """
66 request = self.connection.delete(string, data, headers)
67 return request
68
69 def get_token(self):
70 """This function gets a token needed for authentication in most cases
71
72 :returns: string -- token used to authenticate
73 """
74 r = self.connect.get('stream')
75 token = self._token_regex.search(r.text).group(1)
76 return token
77
78 def _setlogindata(self, username, password):
79 """This function is used to set data for login.
80 .. note::
81 It should be called before _login() function.
82 """
83 self._username, self._password = username, password
84 self._login_data = {'user[username]': self._username,
85 'user[password]': self._password,
86 'authenticity_token': self.get_token()}
87
88 def _login(self):
89 """This function is used to connect to the pod and log in.
90 """
91 r = self._sessionpost('users/sign_in',
92 data=self._login_data,
93 headers={'accept': 'application/json'})
94 if r.status_code != 201:
95 raise Exception('{0}: Login failed.'.format(r.status_code))
96
97 def _setpostdata(self, text, aspect_ids, photos):
98 """This function prepares data for posting.
99
100 :param text: Text to post.
101 :type text: str
102 :param aspect_ids: Aspect ids to send post to.
103 :type aspect_ids: str
104 """
105 data = {}
106 data['aspect_ids'] = aspect_ids
107 data['status_message'] = {'text': text}
108 if photos:
109 data['photos'] = photos
110 self._post_data = data
111
112 def _post(self):
113 """Sends post to an aspect.
114
115 :returns: diaspy.models.Post -- the Post which has been created
116 """
117 r = self._sessionpost('status_messages',
118 data=json.dumps(self._post_data),
119 headers={'content-type': 'application/json',
120 'accept': 'application/json',
121 'x-csrf-token': self.get_token()})
122 if r.status_code != 201:
123 raise Exception('{0}: Post could not be posted.'.format(
124 r.status_code))
125
126 return diaspy.models.Post(str(r.json()['id']), self)
127
128 def post(self, text, aspect_ids='public', photos=None):
129 """This function sends a post to an aspect
130
131 :param text: Text to post.
132 :type text: str
133 :param aspect_ids: Aspect ids to send post to.
134 :type aspect_ids: str
135
136 :returns: diaspy.models.Post -- the Post which has been created
137 """
138 self._setpostdata(text, aspect_ids, photos)
139 post = self._post()
140 self._post_data = {}
141 return post
142
143 def get_user_info(self):
144 """This function returns the current user's attributes.
145
146 :returns: dict -- json formatted user info.
147 """
148 r = self.connection.get('bookmarklet')
149 regex = re.compile(r'window.current_user_attributes = ({.*})')
150 userdata = json.loads(regex.search(r.text).group(1))
151 return userdata
152
153 def post_picture(self, filename):
154 """This method posts a picture to D*.
155
156 :param filename: Path to picture file.
157 :type filename: str
158 """
159 aspects = self.get_user_info()['aspects']
160 params = {}
161 params['photo[pending]'] = 'true'
162 params['set_profile_image'] = ''
163 params['qqfile'] = filename
164 for i, aspect in enumerate(aspects):
165 params['photo[aspect_ids][%d]' % (i)] = aspect['id']
166
167 data = open(filename, 'rb')
168
169 headers = {'content-type': 'application/octet-stream',
170 'x-csrf-token': self.get_token(),
171 'x-file-name': filename}
172
173 r = self._sessionpost('photos', params=params, data=data, headers=headers)
174 return r
175
176 def get_stream(self):
177 """This functions returns a list of posts found in the stream.
178
179 :returns: list -- list of Post objects.
180 """
181 request = self.connection.get('stream.json')
182
183 if request.status_code != 200:
184 raise Exception('wrong status code: {0}'.format(request.status_code))
185
186 stream = request.json()
187 return [diaspy.models.Post(str(post['id']), self) for post in stream]
188
189 def get_notifications(self):
190 """This functions returns a list of notifications.
191
192 :returns: list -- list of json formatted notifications
193 """
194 r = self._sessionget('notifications.json')
195
196 if r.status_code != 200:
197 raise Exception('wrong status code: {0}'.format(r.status_code))
198
199 notifications = r.json()
200 return notifications
201
202 def get_mentions(self):
203 """This functions returns a list of
204 posts the current user is being mentioned in.
205
206 :returns: list -- list of Post objects
207 """
208 r = self._sessionget('mentions.json')
209
210 if r.status_code != 200:
211 raise Exception('wrong status code: {0}'.format(r.status_code))
212
213 mentions = r.json()
214 return [diaspy.models.Post(str(post['id']), self) for post in mentions]
215
216 def get_tag(self, tag):
217 """This functions returns a list of posts containing the tag.
218 :param tag: Name of the tag
219 :type tag: str
220
221 :returns: list -- list of Post objects
222 """
223 r = self._sessionget('tags/{0}.json'.format(tag))
224
225 if r.status_code != 200:
226 raise Exception('wrong status code: {0}'.format(r.status_code))
227
228 tagged_posts = r.json()
229 return [diaspy.models.Post(str(post['id']), self) for post in tagged_posts]
230
231 def get_mailbox(self):
232 """This functions returns a list of messages found in the conversation.
233
234 :returns: list -- list of Conversation objects.
235 """
236 r = self._sessionget('conversations.json')
237
238 if r.status_code != 200:
239 raise Exception('wrong status code: {0}'.format(r.status_code))
240
241 mailbox = r.json()
242 return [diaspy.conversations.Conversation(str(conversation['conversation']['id']), self)
243 for conversation in mailbox]
244
245 def add_user_to_aspect(self, user_id, aspect_id):
246 """ this function adds a user to an aspect.
247
248 :param user_id: User ID
249 :type user_id: str
250 :param aspect_id: Aspect ID
251 :type aspect_id: str
252
253 """
254 data = {'authenticity_token': self.get_token(),
255 'aspect_id': aspect_id,
256 'person_id': user_id}
257
258 r = self._sessionpost('aspect_memberships.json', data=data)
259
260 if r.status_code != 201:
261 raise Exception('wrong status code: {0}'.format(r.status_code))
262 return r.json()
263
264 def add_aspect(self, aspect_name, visible=0):
265 """ This function adds a new aspect.
266 """
267
268 data = {'authenticity_token': self.get_token(),
269 'aspect[name]': aspect_name,
270 'aspect[contacts_visible]': visible}
271
272 r = self._sessionpost('aspects', data=data)
273
274 if r.status_code != 200:
275 raise Exception('wrong status code: {0}'.format(r.status_code))
276
277 def remove_user_from_aspect(self, user_id, aspect_id):
278 """ this function removes a user from an aspect.
279
280 :param user_id: User ID
281 :type user_id: str
282 :param aspect_id: Aspect ID
283 :type aspect_id: str
284
285 """
286 data = {'authenticity_token': self.get_token(),
287 'aspect_id': aspect_id,
288 'person_id': user_id}
289
290 r = self._sessiondelete('aspect_memberships/42.json',
291 data=data)
292
293 if r.status_code != 200:
294 raise Exception('wrong status code: {0}'.format(r.status_code))
295
296 return r.json()
297
298 def remove_aspect(self, aspect_id):
299 """ This function adds a new aspect.
300 """
301 data = {'authenticity_token': self.get_token()}
302
303 r = self._sessiondelete('aspects/{}'.format(aspect_id),
304 data=data)
305
306 if r.status_code != 404:
307 raise Exception('wrong status code: {0}'.format(r.status_code))
308
309 def new_conversation(self, contacts, subject, text):
310 """Start a new conversation.
311
312 :param contacts: recipients ids, no guids, comma sperated.
313 :type contacts: str
314 :param subject: subject of the message.
315 :type subject: str
316 :param text: text of the message.
317 :type text: str
318 """
319 data = {'contact_ids': contacts,
320 'conversation[subject]': subject,
321 'conversation[text]': text,
322 'utf8': '✓',
323 'authenticity_token': self.get_token()}
324
325 r = self._sessionpost('conversations/',
326 data=data,
327 headers={'accept': 'application/json'})
328 if r.status_code != 200:
329 raise Exception('{0}: Conversation could not be started.'
330 .format(r.status_code))
331 return r.json()