* __upd__: Delete `Comment()` from `diaspy.models.Post.comments` on `diaspy.models.Post.delete_comment()`
* __upd__: Update `diaspy.models.Post._data["poll"]["participation_count"]` and `diaspy.models.Post._data["poll_participation_answer_id"]` after `diaspy.models.Post.vote_poll()`
* __upd__: Update `diaspy.models.Post._data["participation"]` on `diaspy.models.Post.subscribe()` and `diaspy.models.Post.unsubscribe()`
* __upd__: Removed `verify` keyword from `diaspy.connection.Connection` it's methods, it's now done through `**requestKwargs`. Default is still `True`.
* __upd__: `diaspy.streams.Stream._photoupload()` to more public method `diaspy.streams.Stream.photoupload()`
* __upd__: Update `diaspy.models.Notification.unread` and `diaspy.models.Notification._data['unread']` on `diasply.models.Notification.mark()`
* __fix__: Don't update `diaspy.notifications.Notifications` it's `unread_count_by_type` and `unread_count` on `diaspy.notifications.Notifications._expand()` and `diaspy.notifications.Notifications._update()` since it's already done in `diaspy.notifications.Notifications._finalize()`
* __new__: `diaspy.streams.Generic.deletePostGuid()` deletes `Post` with given `guid` from the local stream object. (If you manualy update a post and find that it's been deleted, call this with the `guid` of the deleted `Post`)
* __new__: `diaspy.streams.Stream.deletephoto()`
* __new__: `diaspy.notifications.Notifications.__len__()`
* __new__: `diaspy.notifications.Notifications.data()`
* __new__: `diaspy.models.Comments.delete()` deletes comment by `id`.
* __new__: `diaspy.errors.NotificationError`
Note: the current Camo check will be removed and replaced by nodeInfo soon.
#### Version `0.6.1.dev` (not final changelog for this version, still in development)
* __upd__: `diaspy.models.Post.like()`, `diaspy.models.Post.delete_like()`, `diaspy.models.Post.reshare()` will now update data (count and likes/reshares) without doing another request.
+* __upd__: Add `Comment()` to `diaspy.models.Post.comments` on `diaspy.models.Post.comment()`
+* __upd__: Delete `Comment()` from `diaspy.models.Post.comments` on `diaspy.models.Post.delete_comment()`
+* __upd__: Update `diaspy.models.Post._data["poll"]["participation_count"]` and `diaspy.models.Post._data["poll_participation_answer_id"]` after `diaspy.models.Post.vote_poll()`
+* __upd__: Update `diaspy.models.Post._data["participation"]` on `diaspy.models.Post.subscribe()` and `diaspy.models.Post.unsubscribe()`
+* __upd__: Removed `verify` keyword from `diaspy.connection.Connection` it's methods, it's now done through `**requestKwargs`. Default is still `True`.
+* __upd__: `diaspy.streams.Stream._photoupload()` to more public method `diaspy.streams.Stream.photoupload()`
+* __upd__: Update `diaspy.models.Notification.unread` and `diaspy.models.Notification._data['unread']` on `diasply.models.Notification.mark()`
+
* __fix__: `diaspy.models.Post.__init__()` checking on different fetch states was a mess.
* __fix__: `diaspy.streams.Asepcts.filter()` location fix.
+* __fix__: Don't update `diaspy.notifications.Notifications` it's `unread_count_by_type` and `unread_count` on `diaspy.notifications.Notifications._expand()` and `diaspy.notifications.Notifications._update()` since it's already done in `diaspy.notifications.Notifications._finalize()`
+
* __new__: `diaspy.tagFollowings.TagFollowings()` which represents the tags followed by the user.
* __new__: `diaspy.models.FollowedTag()` which represents a tag followed by the user. It is used by `diaspy.tagFollowings.TagFollowings()`.
* __new__: `diaspy.streams.Public()`
* __new__: `diaspy.models.Post.fetchlikes()`.
* __new__: `diaspy.models.Post.fetchreshares()`
+* __new__: `diaspy.streams.Generic.deletePostGuid()` deletes `Post` with given `guid` from the local stream object. (If you manualy update a post and find that it's been deleted, call this with the `guid` of the deleted `Post`)
+* __new__: `diaspy.streams.Stream.deletephoto()`
+* __new__: `diaspy.notifications.Notifications.__len__()`
+* __new__: `diaspy.notifications.Notifications.data()`
+* __new__: `diaspy.models.Comments.delete()` deletes comment by `id`.
+* __new__: `diaspy.errors.NotificationError`
* __rem__: `diaspy.streams.FollowedTags.get()` since it wasn’t doing anything usefull.
self._token = ''
self._diaspora_session = ''
self._fetch_token_from = 'stream'
- self._requests_kwargs = requestsKwargs
+ self._requests_kwargs = {'verify':self._verify_SSL}
+ if requestsKwargs: self._requests_kwargs.update(requestsKwargs)
+
self._camo_enabled = False
try: self._setlogin(username, password)
except requests.exceptions.MissingSchema:
if not direct: url = '{0}/{1}'.format(self.pod, string)
else: url = string
if not kwargs: kwargs = self._requests_kwargs
- return self._session.get(url, params=params, headers=headers, verify=self._verify_SSL, **kwargs)
+ return self._session.get(url, params=params, headers=headers, **kwargs)
def tokenFrom(self, location):
"""Sets location for the *next* fetch of CSRF token.
if 'X-CSRF-Token' not in headers:
headers['X-CSRF-Token'] = self.get_token()
if not kwargs: kwargs = self._requests_kwargs
- request = self._session.post(string, data, headers=headers, params=params, verify=self._verify_SSL, **kwargs)
+ request = self._session.post(string, data, headers=headers, params=params, **kwargs)
return request
def put(self, string, data=None, headers={}, params={}, **kwargs):
headers['X-CSRF-Token'] = self.get_token()
if not kwargs: kwargs = self._requests_kwargs
if data is not None: request = self._session.put(string, data, headers=headers, params=params, **kwargs)
- else: request = self._session.put(string, headers=headers, params=params, verify=self._verify_SSL, **kwargs)
+ else: request = self._session.put(string, headers=headers, params=params, **kwargs)
return request
def delete(self, string, data = None, headers={}, **kwargs):
if 'X-CSRF-Token' not in headers:
headers['X-CSRF-Token'] = self.get_token()
if not kwargs: kwargs = self._requests_kwargs
- request = self._session.delete(string, data=data, headers=headers, verify=self._verify_SSL, **kwargs)
+ request = self._session.delete(string, data=data, headers=headers, **kwargs)
return request
def _checkCamo(self):
"""
self.get('users/sign_out')
self.token = ''
+ self._userdata = {}
+ self._diaspora_session = ''
+ self._camo_enabled = False
def podswitch(self, pod, username, password, login=True):
"""Switches pod from current to another one.
"""Sets whether there should be an error if a SSL-Certificate could not be verified.
"""
self._verify_SSL = verify
+ self._requests_kwargs.update({'verify':verify})
"""
pass
+class NotificationError(DiaspyError):
+ """Exception raised when something related to notifications goes wrong.
+ """
+ pass
class ConversationError(DiaspyError):
"""Exception raised when something related to conversations goes wrong.
"""
headers = {'x-csrf-token': repr(self._connection)}
params = {'set_unread': json.dumps(unread)}
- self._connection.put('notifications/{0}'.format(self['id']), params=params, headers=headers)
+ response = self._connection.put('notifications/{0}'.format(self['id']), params=params, headers=headers)
+ if response.status_code != 200:
+ raise errors.NotificationError('Cannot mark notification: {0}'.format(response.status_code))
self._data['unread'] = unread
+ self.unread = unread
class Conversation():
def ids(self):
return [c.id for c in self._comments]
+ def delete(self, comment_id):
+ for index, comment in enumerate(self._comments):
+ if comment.id == comment_id:
+ self._comments.pop(index);
+ break;
+
def add(self, comment):
""" Expects Comment() object
if request.status_code != 201:
raise Exception('{0}: Comment could not be posted.'
.format(request.status_code))
- return Comment(request.json())
+ comment = Comment(request.json())
+ self.comments.add(comment);
+ return comment
def vote_poll(self, poll_answer_id):
"""This function votes on a post's poll
if request.status_code != 201:
raise Exception('{0}: Vote on poll failed.'
.format(request.status_code))
- return request.json()
+
+ data = request.json()
+ self._data["poll"]["participation_count"] += 1
+ self._data["poll_participation_answer_id"] = data["poll_participation"]["poll_answer_id"]
+
+ for answer in self._data["poll"]["poll_answers"]:
+ if answer["id"] == poll_answer_id:
+ answer["vote_count"] +=1;
+ break;
+ return data
def hide(self):
"""
raise Exception('{0}: Failed to subscribe to post'
.format(request.status_code))
+ self._data.update({"participation" : True})
+
def unsubscribe(self):
"""
-> POST /posts/123/participation HTTP/1.1
raise Exception('{0}: Failed to unsubscribe to post'
.format(request.status_code))
+ self._data.update({"participation" : False})
+
def report(self):
"""
TODO
raise errors.PostError('{0}: Comment could not be deleted'
.format(request.status_code))
+ self.comments.delete(comment_id)
+
def delete_like(self):
"""This function removes a like from a post
"""
self._notifications = self.get()
self.page = 1
+ def __len__(self): return len(self._notifications);
+
def __iter__(self):
return iter(self._notifications)
self._data['unread_count_by_type'] = notifications['unread_count_by_type']
return [Notification(self._connection, n) for n in notifications.get('notification_list', [])]
+ def data(self): return self._data;
+
def last(self):
"""Returns list of most recent notifications.
"""
data = self._data
for n in new_notifications:
if n.id not in ids:
- if n.unread:
- data['unread_count'] +=1
- data['unread_count_by_type'][n.type] +=1
notifications.append(n)
ids.append(n.id)
self._notifications = notifications
- self._data = data
+ self._data.update(data);
def _update(self, new_notifications):
ids = [notification.id for notification in self._notifications]
for i in range(len(new_notifications)):
if new_notifications[-i].id not in ids:
- if new_notifications[-i].unread:
- data['unread_count'] +=1
- data['unread_count_by_type'][new_notifications[-i].type] +=1
notifications = [new_notifications[-i]] + notifications
ids.append(new_notifications[-i].id)
self._notifications = notifications
if not page: page = self.page + 1
self.page = page
result = self.get(per_page=per_page, page=page)
- if result:
- self._expand( result )
+ if result: self._expand( result )
def get(self, per_page=5, page=1):
"""Returns list of notifications.
"""
self._stream = []
+ def deletePostGuid(self, guid):
+ """Deleted post from stream by guid
+
+ :param guid: guid of the post to delete
+ :type guid: str
+
+ NOTE: This affects local object only! So no request will be made to a
+ pod. This can be used if you tried to update a Post() and it failed then
+ you know the post is deleted.
+ """
+ for index, post in enumerate(self._stream):
+ if post.guid == guid:
+ self._stream.pop(index);
+ break;
+
def purge(self):
"""Removes all unexistent posts from stream.
"""
:param photo: filename of photo to post
:type photo: str
- :param photos: id of photo to post (obtained from _photoupload())
+ :param photos: id of photo to post (obtained from photoupload())
:type photos: int
:param provider_display_name: name of provider displayed under the post
data['aspect_ids'] = aspect_ids
data['status_message'] = ({'text': text,
'provider_display_name': provider_display_name})
- if photo: data['photos'] = self._photoupload(photo)
+ if photo: data['photos'] = self.photoupload(photo)
if photos: data['photos'] = photos
if poll_question and poll_answers:
data['poll_question'] = poll_question
post_json = request.json()
post = Post(self._connection, id=post_json['id'],
guid=post_json['guid'], post_data=post_json)
+ self._stream.insert(0, post);
return post
- def _photoupload(self, filename, aspects=[]):
+ def deletephoto(self, id):
+ """Remove photo from the pod (if decided not needed anymore).
+
+ :param id: photo id to delete
+ :type id: int
+ """
+ data = {'authenticity_token': repr(self._connection)}
+ request = self._connection.delete('photos/{0}'.format(id),
+ data=data,
+ headers={'accept': 'application/json'})
+ if request.status_code != 204:
+ raise errors.StreamError('{0}: Photo could not be deleted'.format(request.status_code))
+
+ def photoupload(self, filename, aspects=[]):
"""Uploads picture to the pod.
:param filename: path to picture file