Skip to content
This repository has been archived by the owner on Jan 14, 2024. It is now read-only.

Commit

Permalink
Merge branch 'feature/private-xml-and-bookmarks' into devel
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastianriese committed Apr 8, 2017
2 parents bd51522 + ba317f6 commit eeb44f0
Show file tree
Hide file tree
Showing 17 changed files with 1,075 additions and 0 deletions.
82 changes: 82 additions & 0 deletions aioxmpp/bookmarks/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
########################################################################
# File name: __init__.py
# This file is part of: aioxmpp
#
# LICENSE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
#
########################################################################
""":mod:`~aioxmpp.bookmarks` – Bookmark support (:xep:`0048`)
##########################################################
This module provides support for storing and retrieving bookmarks on
the server as per :xep:`Bookmarks <48>`.
Service
=======
.. autoclass:: BookmarkClient
XSOs
====
The following XSOs are used to represent an manipulate bookmark lists.
.. autoclass:: Storage
.. autoclass:: Conference
.. autoclass:: URL
Notes on usage
==============
It is important to use this class carefully to prevent race conditions
with other clients modifying the bookmark data (unfortunately, this is
not entirely preventable due to the design of the bookmark protocol).
The recommended practice is to modify the bookmarks in a get, modify,
set fashion, where the modify step should be as short as possible
(that is, should not depend on user input).
The individual bookmark classes support comparison by value. This
allows useful manipulation of the bookmark list in agreement with
the get-modify-set pattern. Where we reference the objects to operate
on by with the value retrieved in an earlier get.
Removal::
storage = bookmark_client.get_bookmarks()
storage.bookmarks.remove(old_bookmark)
bookmark_client.set_bookmarks(storage)
Modifying::
storage = bookmark_client.get_bookmarks()
i = storage.bookmarks.index(old_bookmark)
storage.bookmarks[i].name = "New Shiny Name"
storage.bookmarks[i].nick = "new_nick"
bookmark_client.set_bookmarks(storage)
Adding::
storage = bookmark_client.get_bookmarks()
storage.bookmarks.append(new_bookmark)
bookmark_client.set_bookmarks(storage)
"""

from .xso import (Storage, Conference, URL) # NOQA
from .service import BookmarkClient # NOQA
85 changes: 85 additions & 0 deletions aioxmpp/bookmarks/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
########################################################################
# File name: service.py
# This file is part of: aioxmpp
#
# LICENSE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
#
########################################################################
import asyncio

import aioxmpp
import aioxmpp.callbacks as callbacks
import aioxmpp.service as service
import aioxmpp.disco as disco
import aioxmpp.pubsub as pubsub
import aioxmpp.private_xml as private_xml

from . import xso as bookmark_xso


# TODO: use private storage in pubsub where available.
# TODO: sync bookmarks between pubsub and private xml storage
class BookmarkClient(service.Service):
"""
Supports retrieval and storage of bookmarks on the server.
It currently only supports :xep:`Private XML Storage <49>` as
backend.
.. automethod:: get_bookmarks
.. automethod:: set_bookmarks
.. note:: The bookmark protocol is prone to race conditions if
several clients access it concurrently. Be careful to
use a get-modify-set pattern.
.. note:: Some other clients extend the bookmark format. For now
those extensions are silently dropped by our XSOs, and
therefore are lost, when changing the bookmarks with
aioxmpp. This is considered a bug to be fixed in the future.
"""

ORDER_AFTER = [
private_xml.PrivateXMLService,
]

def __init__(self, client, **kwargs):
super().__init__(client, **kwargs)
self._private_xml = self.dependencies[private_xml.PrivateXMLService]

@asyncio.coroutine
def get_bookmarks(self):
"""
Get the stored bookmarks from the server.
:returns: the bookmarks as a :class:`~bookmark_xso.Storage` object
"""
res = yield from self._private_xml.get_private_xml(
bookmark_xso.Storage()
)
return res

@asyncio.coroutine
def set_bookmarks(self, bookmarks):
"""
Set the bookmarks stored on the server.
"""
if not isinstance(bookmarks, bookmark_xso.Storage):
raise TypeError(
"set_bookmarks only accepts bookmark.Storage objects"
)
yield from self._private_xml.set_private_xml(bookmarks)
129 changes: 129 additions & 0 deletions aioxmpp/bookmarks/xso.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
########################################################################
# File name: xso.py
# This file is part of: aioxmpp
#
# LICENSE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
#
########################################################################
import aioxmpp
import aioxmpp.private_xml as private_xml
import aioxmpp.xso as xso


from aioxmpp.utils import namespaces


namespaces.xep0048 = "storage:bookmarks"


class Conference(xso.XSO):
"""
An bookmark for a groupchat.
.. attribute:: name
The name of the bookmark.
.. attribute:: jid
The jid under which the groupchat is accessible.
.. attribute:: autojoin
Whether to join automatically, when the client starts.
.. attribute:: nick
The nick to use in the groupchat.
.. attribute:: password
The password used to access the groupchat.
"""

TAG = (namespaces.xep0048, "conference")

autojoin = xso.Attr(tag="autojoin", type_=xso.Bool(), default=False)
jid = xso.Attr(tag="jid", type_=xso.JID())
name = xso.Attr(tag="name", type_=xso.String(), default=None)

nick = xso.ChildText(
(namespaces.xep0048, "nick"),
default=None
)
password = xso.ChildText(
(namespaces.xep0048, "password"),
default=None
)

def __init__(self, name, jid, *, autojoin=False, nick=None, password=None):
self.autojoin = autojoin
self.jid = jid
self.name = name
self.nick = nick
self.password = password

def __eq__(self, other):
return (isinstance(other, Conference) and
other.name == self.name and
other.jid == self.jid and
other.autojoin == self.autojoin and
other.name == self.name and
other.password == self.password)


class URL(xso.XSO):
"""
An URL bookmark.
.. attribute:: name
The name of the bookmark.
.. attribute:: url
The URL the bookmark saves.
"""
TAG = (namespaces.xep0048, "url")

name = xso.Attr(tag="name", type_=xso.String(), default=None)
# XXX: we might want to use a URL type once we have one
url = xso.Attr(tag="url", type_=xso.String())

def __init__(self, name, url):
self.name = name
self.url = url

def __eq__(self, other):
return (isinstance(other, URL) and
other.name == self.name and
other.url == self.url)


@private_xml.Query.as_payload_class
class Storage(xso.XSO):
"""
The container for storing bookmarks.
.. attribute:: bookmarks
A :class:`~xso.XSOList` of bookmarks.
"""
TAG = (namespaces.xep0048, "storage")

bookmarks = xso.ChildList([URL, Conference])
39 changes: 39 additions & 0 deletions aioxmpp/private_xml/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
########################################################################
# File name: __init__.py
# This file is part of: aioxmpp
#
# LICENSE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
#
########################################################################
"""
:mod:`~aioxmpp.private_xml` – Private XML Storage support (:xep:`0049`)
#######################################################################
This module provides support for storing and retrieving private XML data on
the server as per :xep:`Private XML Storage <49>`.
.. autoclass:: PrivateXMLService
To register payload XSOs for private storage :class:`Query` is
exposed:
.. autoclass:: Query
"""

from .xso import Query # NOQA
from .service import PrivateXMLService # NOQA
Loading

0 comments on commit eeb44f0

Please sign in to comment.