Allow attaching of images to a post
[diaspy.git] / diaspy / client.py
1 import requests
2 import re
3 import json
4 import diaspy.models
5 from requests.adapters import HTTPAdapter
6 from requests import Session
7 import logging
8
9 class Interceptor(HTTPAdapter):
10 def send(self, request, stream=False, timeout=None, verify=True,
11 cert=None, proxies=None):
12 print('{0.method} {0.url} {0.body}'.format(request))
13 return super(Interceptor, self).send(request, stream, timeout, verify,
14 cert, proxies)
15
16 class Client:
17 """This is the client class to connect to diaspora.
18
19 """
20
21 def __init__(self, pod, username, password):
22 """
23 :param pod: The complete url of the diaspora pod to use.
24 :type pod: str
25 :param username: The username used to log in.
26 :type username: str
27 :param password: The password used to log in.
28 :type password: str
29
30 """
31 self._token_regex = re.compile(r'content="(.*?)"\s+name="csrf-token')
32 self.pod = pod
33 self.session = requests.Session()
34 self.session.mount('https://', Interceptor())
35 self._login(username, password)
36
37 def get_token(self):
38 """This function gets a token needed for authentication in most cases
39
40 :returns: string -- token used to authenticate
41
42 """
43
44 r = self.session.get(self.pod + '/stream')
45 token = self._token_regex.search(r.text).group(1)
46 return token
47
48 def _login(self, username, password):
49 """This function is used to connect to the pod and log in.
50 .. note::
51 This function shouldn't be called manually.
52 """
53 self._username = username
54 self._password = password
55 r = self.session.get(self.pod + '/users/sign_in')
56 token = self._token_regex.search(r.text).group(1)
57
58 data = {'user[username]': self._username,
59 'user[password]': self._password,
60 'authenticity_token': token,
61 'commit': ''}
62
63 r = self.session.post(self.pod +
64 '/users/sign_in',
65 data=data,
66 headers={'accept': 'application/json'})
67
68 if r.status_code != 201:
69 raise Exception(str(r.status_code) + ': Login failed.')
70
71 def post(self, text, aspect_id='public', photos=None):
72 """This function sends a post to an aspect
73
74 :param text: Text to post.
75 :type text: str
76 :param aspect_id: Aspect id to send post to.
77 :type aspect_id: str
78
79 :returns: diaspy.models.Post -- the Post which has been created
80
81 """
82 data = {'aspect_ids': aspect_id,
83 'status_message': {'text': text}}
84
85 if photos:
86 data['photos'] = photos
87 r = self.session.post(self.pod +
88 "/status_messages",
89 data=json.dumps(data),
90 headers={'content-type': 'application/json',
91 'accept': 'application/json',
92 'x-csrf-token': self.get_token()})
93 if r.status_code != 201:
94 raise Exception(str(r.status_code) + ': Post could not be posted.')
95
96 return diaspy.models.Post(str(r.json()['id']), self)
97
98 def get_user_info(self):
99 """This function returns the current user's attributes.
100
101 :returns: dict -- json formatted user info.
102
103 """
104 r = self.session.get(self.pod + '/bookmarklet')
105 regex = re.compile(r'window.current_user_attributes = ({.*})')
106 userdata = json.loads(regex.search(r.text).group(1))
107 return userdata
108
109 def post_picture(self, filename):
110 aspects = self.get_user_info()['aspects']
111 params = {}
112 params['photo[pending]'] = 'true'
113 params['set_profile_image'] = ''
114 params['qqfile'] = filename
115 for i, aspect in enumerate(aspects):
116 params['photo[aspect_ids][%d]' % (i)] = aspect['id']
117
118 data = open(filename, 'rb')
119
120 headers = {'content-type': 'application/octet-stream',
121 'x-csrf-token': self.get_token(),
122 'x-file-name': filename}
123
124 r = self.session.post(self.pod + '/photos', params=params, data=data, headers=headers)
125
126 return r
127
128
129
130 def get_stream(self):
131 """This functions returns a list of posts found in the stream.
132
133 :returns: list -- list of Post objects.
134
135 """
136
137 data = {'authenticity_token': self.get_token()}
138 r = self.session.get(self.pod + "/stream.json")
139
140 if r.status_code != 200:
141 raise Exception('wrong status code: ' + str(r.status_code))
142
143 stream = r.json()
144
145 posts = []
146
147 for post in stream:
148 posts.append(diaspy.models.Post(str(post['id']), self))
149
150 return posts
151
152 def get_notifications(self):
153 """This functions returns a list of notifications.
154
155 :returns: list -- list of json formatted notifications
156
157 """
158
159
160 data = {'authenticity_token': self.get_token()}
161 r = self.session.get(self.pod + "/notifications.json")
162
163 if r.status_code != 200:
164 raise Exception('wrong status code: ' + str(r.status_code))
165
166 notifications = r.json()
167 return notifications
168
169
170 def get_mentions(self):
171 """This functions returns a list of posts the current user is being mentioned in.
172
173 :returns: list -- list of Post objects
174
175 """
176
177
178 data = {'authenticity_token': self.get_token()}
179 r = self.session.get(self.pod + "/mentions.json")
180
181 if r.status_code != 200:
182 raise Exception('wrong status code: ' + str(r.status_code))
183
184 mentions = r.json()
185
186 posts = []
187
188 for post in mentions:
189 posts.append(diaspy.models.Post(str(post['id']), self))
190
191 return posts