import json
+import re
-class Post:
+"""This module is only imported in other diaspy modules and
+MUST NOT import anything.
+"""
+
+
+class Aspect():
+ """This class represents an aspect.
+ """
+ def __init__(self, connection, id=-1):
+ self._connection = connection
+ self.id = id
+ self.name = ''
+
+ def getUsers(self):
+ """Returns list of users who are listed in this aspect.
+ """
+ return []
+
+ def addUser(self, user_id):
+ """Add user to current aspect.
+
+ :param user_id: user to add to aspect
+ :type user: int
+ """
+ data = {'authenticity_token': self._connection.get_token(),
+ 'aspect_id': self.id,
+ 'person_id': user_id}
+
+ request = self._connection.post('aspect_memberships.json', data=data)
+
+ if request.status_code != 201:
+ raise Exception('wrong status code: {0}'.format(request.status_code))
+ return request.json()
+
+ def removeUser(self, user_id):
+ """Remove user from current aspect.
+
+ :param user_id: user to remove from aspect
+ :type user: int
+ """
+ data = {'authenticity_token': self._connection.get_token(),
+ 'aspect_id': self.id,
+ 'person_id': user_id}
+
+ request = self.connection.delete('aspect_memberships/{0}.json'.format(self.id), data=data)
+
+ if request.status_code != 200:
+ raise Exception('wrong status code: {0}'.format(request.status_code))
+ return request.json()
+
+
+class Notification():
+ """This class represents single notification.
+ """
+ _who_regexp = re.compile(r'/people/[0-9a-z]+" class=\'hovercardable')
+ _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')
+
+ def __init__(self, connection, data):
+ self._connection = connection
+ self.type = list(data.keys())[0]
+ self.data = data[self.type]
+ self.id = self.data['id']
+ self.unread = self.data['unread']
+
+ def __getitem__(self, key):
+ """Returns a key from notification data.
+ """
+ return self.data[key]
+
+ def __str__(self):
+ """Returns notification note.
+ """
+ string = re.sub('</?[a-z]+( *[a-z_-]+=["\'][\w():.,!?#/\- ]*["\'])* */?>', '', self.data['note_html'])
+ string = string.strip().split('\n')[0]
+ while ' ' in string: string = string.replace(' ', ' ')
+ return string
+
+ def __repr__(self):
+ """Returns notification note with more details.
+ """
+ return '{0}: {1}'.format(self.when(), str(self))
+
+ def who(self):
+ """Returns list of guids of the users who caused you to get the notification.
+ """
+ return [who[8:24] for who in self._who_regexp.findall(self.data['note_html'])]
+
+ def when(self):
+ """Returns UTC time as found in note_html.
+ """
+ return self._when_regexp.search(self.data['note_html']).group(0)
+
+ def mark(self, unread=False):
+ """Marks notification to read/unread.
+ Marks notification to read if `unread` is False.
+ Marks notification to unread if `unread` is True.
+
+ :param unread: which state set for notification
+ :type unread: bool
+ """
+ headers = {'x-csrf-token': self._connection.get_token()}
+ params = {'set_unread': json.dumps(unread)}
+ self._connection.put('notifications/{0}'.format(self['id']), params=params, headers=headers)
+ self.data['unread'] = unread
+
+
+class Post():
"""This class represents a post.
.. note::
Remember that you need to have access to the post.
- Remember that you also need to be logged in.
"""
def __init__(self, post_id, connection):
"""
self._connection = connection
self.post_id = post_id
+ def __repr__(self):
+ """Returns string containing more information then str().
+ """
+ data = self.get_data()
+ return '{0} ({1}): {2}'.format(data['author']['name'], data['author']['diaspora_id'], data['text'])
+
+ def __str__(self):
+ """Returns text of a post.
+ """
+ return self.get_data()['text']
+
def get_data(self):
"""This function retrieves data of the post.
"""
- r = self._connection.get('posts/{1}.json'.format(self.post_id))
- if r.status_code == 200:
- return r.json()
- else:
+ r = self._connection.get('posts/{0}.json'.format(self.post_id))
+ if r.status_code != 200:
raise Exception('wrong status code: {0}'.format(r.status_code))
+ return r.json()
def like(self):
"""This function likes a post.
:returns: dict -- json formatted like object.
"""
- data = {'authenticity_token': self._connection.getToken()}
+ data = {'authenticity_token': self._connection.get_token()}
r = self._connection.post('posts/{0}/likes'.format(self.post_id),
data=data,
def delete_like(self):
"""This function removes a like from a post
"""
- data = {'authenticity_token': self._connection.getToken()}
+ data = {'authenticity_token': self._connection.get_token()}
post_data = self.get_data()
post_data = self.get_data()
data = {'root_guid': post_data['guid'],
- 'authenticity_token': self._connection.getToken()}
+ 'authenticity_token': self._connection.get_token()}
r = self._connection.post('reshares',
data=data,
:param text: text to comment.
:type text: str
-
"""
data = {'text': text,
- 'authenticity_token': self._connection.getToken()}
+ 'authenticity_token': self._connection.get_token()}
r = self._connection.post('posts/{0}/comments'.format(self.post_id),
data=data,
:param comment_id: id of the comment to remove.
:type comment_id: str
-
"""
- data = {'authenticity_token': self._connection.getToken()}
+ data = {'authenticity_token': self._connection.get_token()}
r = self._connection.delete('posts/{0}/comments/{1}'
.format(self.post_id,
def delete(self):
""" This function deletes this post
"""
- data = {'authenticity_token': self._connection.getToken()}
+ data = {'authenticity_token': self._connection.get_token()}
r = self._connection.delete('posts/{0}'.format(self.post_id),
data=data,
headers={'accept': 'application/json'})
if r.status_code != 204:
raise Exception('{0}: Post could not be deleted'.format(r.status_code))
-
-
-class Stream:
- """Object representing user's stream.
- """
- def __init__(self, connection):
- """
- :param connection: Connection() object
- :param type: diaspy.connection.Connection
- """
- self._connection = connection
- self._stream = []
- self.fill()
-
- def __contains__(self, post):
- """Returns True if stream contains given post.
- """
- if type(post) is not Post:
- raise TypeError('stream can contain only posts: checked for {0}'.format(type(post)))
- return post in self._stream
-
- def __iter__(self):
- """Provides iterable interface for stream.
- """
- return iter(self._stream)
-
- def __getitem__(self, n):
- """Returns n-th item in Stream.
- """
- return self._stream[n]
-
- def __len__(self):
- """Returns length of the Stream.
- """
- return len(self._stream)
-
- def _obtain(self):
- """Obtains stream from pod.
- """
- request = self._connection.get('stream.json')
- if request.status_code != 200:
- raise Exception('wrong status code: {0}'.format(request.status_code))
- return [Post(str(post['id']), self._connection) for post in request.json()]
-
- def clear(self):
- """Removes all posts from stream.
- """
- self._stream = []
-
- def update(self):
- """Updates stream.
- """
- stream = self._obtain()
- _stream = self._stream
- for i in range(len(stream)):
- if stream[-i] not in _stream:
- _stream = [stream[-i]] + _stream
- self._stream = _stream
-
- def fill(self):
- """Fills the stream with posts.
- """
- self._stream = self._obtain()
-
- def post(self, text, aspect_ids='public', photos=None):
- """This function sends a post to an aspect
-
- :param text: Text to post.
- :type text: str
- :param aspect_ids: Aspect ids to send post to.
- :type aspect_ids: str
-
- :returns: diaspy.models.Post -- the Post which has been created
- """
- data = {}
- data['aspect_ids'] = aspect_ids
- data['status_message'] = {'text': text}
- if photos: data['photos'] = photos
- request = self._connection.post('status_messages',
- data=json.dumps(data),
- headers={'content-type': 'application/json',
- 'accept': 'application/json',
- 'x-csrf-token': self._connection.getToken()})
- if request.status_code != 201:
- raise Exception('{0}: Post could not be posted.'.format(
- request.status_code))
-
- post = Post(str(request.json()['id']), self._connection)
- self.update()
- return post
-
- def post_picture(self, filename):
- """This method posts a picture to D*.
-
- :param filename: Path to picture file.
- :type filename: str
- """
- aspects = self._connection.getUserInfo()['aspects']
- params = {}
- params['photo[pending]'] = 'true'
- params['set_profile_image'] = ''
- params['qqfile'] = filename
- for i, aspect in enumerate(aspects):
- params['photo[aspect_ids][%d]' % (i)] = aspect['id']
-
- data = open(filename, 'rb')
-
- headers = {'content-type': 'application/octet-stream',
- 'x-csrf-token': self._connection.getToken(),
- 'x-file-name': filename}
- request = self._connection.post('photos', params=params, data=data, headers=headers)
- data.close()
- self.update()
- return request