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