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