8 """This module is only imported in other diaspy modules and
9 MUST NOT import anything.
14 """This class represents an aspect.
16 Class can be initialized by passing either an id and/or name as
18 If both are missing, an exception will be raised.
20 def __init__(self
, connection
, id=None, name
=None):
21 self
._connection
= connection
22 self
.id, self
.name
= id, name
24 self
.name
= self
._findname
()
26 self
.id = self
._findid
()
27 elif not id and not name
:
28 raise Exception("Aspect must be initialized with either an id or name")
31 """Finds name for aspect.
34 aspects
= self
._connection
.getUserInfo()['aspects']
36 if a
['id'] == self
.id:
42 """Finds id for aspect.
45 aspects
= self
._connection
.getUserInfo()['aspects']
47 if a
['name'] == self
.name
:
53 """Returns list of GUIDs of users who are listed in this aspect.
55 start_regexp
= re
.compile('<ul +class=["\']contacts["\'] *>')
56 userline_regexp
= re
.compile('<a href=["\']/people/[a-z0-9]{16,16}["\']>[a-zA-Z0-9()@. _-]+</a>')
57 personid_regexp
= 'alt=["\']{0}["\'] class=["\']avatar["\'] data-person_id=["\'][0-9]+["\']'
58 method_regexp
= 'data-method="delete" data-person_id="{0}"'
60 ajax
= self
._connection
.get('aspects/{0}/edit'.format(self
.id)).text
64 begin
= ajax
.find(start_regexp
.search(ajax
).group(0))
66 end
= ajax
.find('</ul>')
67 ajax
= ajax
[begin
:end
]
71 usernames
= [(line
[17:33], line
[35:-4]) for line
in userline_regexp
.findall(ajax
)]
72 for guid
, name
in usernames
:
74 personids
= [re
.compile(personid_regexp
.format(name
)).search(ajax
).group(0) for guid
, name
in usernames
]
75 for n
, line
in enumerate(personids
):
77 while line
[i
].isdigit():
80 personids
[n
] = (usernames
[n
][1], id)
83 for name
, id in personids
:
84 if re
.compile(method_regexp
.format(id, self
.id)).search(ajax
): users_in_aspect
.append(name
)
87 for i
, user
in enumerate(usernames
):
89 if name
in users_in_aspect
:
93 def addUser(self
, user_id
):
94 """Add user to current aspect.
96 :param user_id: user to add to aspect
99 data
= {'authenticity_token': self
._connection
.get_token(),
100 'aspect_id': self
.id,
101 'person_id': user_id
}
103 request
= self
._connection
.post('aspect_memberships.json', data
=data
)
105 if request
.status_code
== 400:
106 raise Exception('duplicate record, user already exists in aspect: {0}'.format(request
.status_code
))
107 elif request
.status_code
== 404:
108 raise Exception('user not found from this pod: {0}'.format(request
.status_code
))
109 elif request
.status_code
!= 200:
110 raise Exception('wrong status code: {0}'.format(request
.status_code
))
111 return request
.json()
113 def removeUser(self
, user_id
):
114 """Remove user from current aspect.
116 :param user_id: user to remove from aspect
119 data
= {'authenticity_token': self
._connection
.get_token(),
120 'aspect_id': self
.id,
121 'person_id': user_id
}
123 request
= self
.connection
.delete('aspect_memberships/{0}.json'.format(self
.id), data
=data
)
125 if request
.status_code
!= 200:
126 raise Exception('wrong status code: {0}'.format(request
.status_code
))
127 return request
.json()
130 class Notification():
131 """This class represents single notification.
133 _who_regexp
= re
.compile(r
'/people/[0-9a-z]+" class=\'hovercardable
')
134 _when_regexp = re.compile(r'[0-9]{4,4}(-[0-9]{2,2}){2,2} [0-9]{2,2}(:[0-9]{2,2}){2,2} UTC
')
136 def __init__(self, connection, data):
137 self._connection = connection
138 self.type = list(data.keys())[0]
139 self.data = data[self.type]
140 self.id = self.data['id']
141 self.unread = self.data['unread
']
143 def __getitem__(self, key):
144 """Returns a key from notification data.
146 return self.data[key]
149 """Returns notification note.
151 string = re.sub('</?
[a
-z
]+( *[a
-z_
-]+=["\'][\w():.,!?#/\- ]*["\'])* */?
>', '', self.data['note_html
'])
152 string = string.strip().split('\n')[0]
153 while ' ' in string: string = string.replace(' ', ' ')
157 """Returns notification note with more details.
159 return '{0}
: {1}
'.format(self.when(), str(self))
162 """Returns list of guids of the users who caused you to get the notification.
164 return [who[8:24] for who in self._who_regexp.findall(self.data['note_html
'])]
167 """Returns UTC time as found in note_html.
169 return self._when_regexp.search(self.data['note_html
']).group(0)
171 def mark(self, unread=False):
172 """Marks notification to read/unread.
173 Marks notification to read if `unread` is False.
174 Marks notification to unread if `unread` is True.
176 :param unread: which state set for notification
179 headers = {'x
-csrf
-token
': self._connection.get_token()}
180 params = {'set_unread
': json.dumps(unread)}
181 self._connection.put('notifications
/{0}
'.format(self['id']), params=params, headers=headers)
182 self.data['unread
'] = unread
186 """This class represents a post.
189 Remember that you need to have access to the post.
191 def __init__(self, post_id, connection):
193 :param post_id: id or guid of the post
195 :param connection: connection object used to authenticate
196 :type connection: connection.Connection
198 self._connection = connection
199 self.post_id = post_id
202 """Returns string containing more information then str().
204 data = self.get_data()
205 return '{0}
({1}
): {2}
'.format(data['author
']['name
'], data['author
']['diaspora_id
'], data['text
'])
208 """Returns text of a post.
210 return self.get_data()['text
']
213 """This function retrieves data of the post.
215 r = self._connection.get('posts
/{0}
.json
'.format(self.post_id))
216 if r.status_code != 200:
217 raise Exception('wrong status code
: {0}
'.format(r.status_code))
221 """This function likes a post.
222 It abstracts the 'Like
' functionality.
224 :returns: dict -- json formatted like object.
226 data = {'authenticity_token
': self._connection.get_token()}
228 r = self._connection.post('posts
/{0}
/likes
'.format(self.post_id),
230 headers={'accept
': 'application
/json
'})
232 if r.status_code != 201:
233 raise Exception('{0}
: Post could
not be liked
.'
234 .format(r.status_code))
238 def delete_like(self):
239 """This function removes a like from a post
241 data = {'authenticity_token
': self._connection.get_token()}
243 post_data = self.get_data()
245 r = self._connection.delete('posts
/{0}
/likes
/{1}
'
246 .format(self.post_id,
247 post_data['interactions
']
251 if r.status_code != 204:
252 raise Exception('{0}
: Like could
not be removed
.'
253 .format(r.status_code))
256 """This function reshares a post
259 post_data = self.get_data()
261 data = {'root_guid
': post_data['guid
'],
262 'authenticity_token
': self._connection.get_token()}
264 r = self._connection.post('reshares
',
266 headers={'accept
': 'application
/json
'})
268 if r.status_code != 201:
269 raise Exception('{0}
: Post could
not be reshared
.'
270 .format(r.status_code))
274 def comment(self, text):
275 """This function comments on a post
277 :param text: text to comment.
280 data = {'text
': text,
281 'authenticity_token
': self._connection.get_token()}
283 r = self._connection.post('posts
/{0}
/comments
'.format(self.post_id),
285 headers={'accept
': 'application
/json
'})
287 if r.status_code != 201:
288 raise Exception('{0}
: Comment could
not be posted
.'
289 .format(r.status_code))
293 def delete_comment(self, comment_id):
294 """This function removes a comment from a post
296 :param comment_id: id of the comment to remove.
297 :type comment_id: str
299 data = {'authenticity_token
': self._connection.get_token()}
301 r = self._connection.delete('posts
/{0}
/comments
/{1}
'
302 .format(self.post_id,
305 headers={'accept
': 'application
/json
'})
307 if r.status_code != 204:
308 raise Exception('{0}
: Comment could
not be deleted
.'
309 .format(r.status_code))
312 """ This function deletes this post
314 data = {'authenticity_token
': self._connection.get_token()}
315 r = self._connection.delete('posts
/{0}
'.format(self.post_id),
317 headers={'accept
': 'application
/json
'})
318 if r.status_code != 204:
319 raise Exception('{0}
: Post could
not be deleted
'.format(r.status_code))