plugin invitation: pubsub invitations:
- new Pubsub invitation plugin, to have a generic way to manage invitation on Pubsub based features - `invitePreflight` and `onInvitationPreflight` method can be implemented to customise invitation for a namespace - refactored events invitations to use the new plugin - a Pubsub invitation can now be for a whole node instead of a specific item - if invitation is for a node, a namespace can be specified to indicate what this node is about. It is then added in `extra` data - an element (domish.Element) can be added in `extra` data, it will then be added in the invitation - some code modernisation
This commit is contained in:
parent
eabf3d536a
commit
795931373a
1 changed files with 353 additions and 138 deletions
|
|
@ -16,15 +16,18 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Optional
|
||||
from zope.interface import implementer
|
||||
from twisted.internet import defer
|
||||
from twisted.words.protocols.jabber import jid
|
||||
from twisted.words.protocols.jabber.xmlstream import XMPPHandler
|
||||
from wokkel import disco, iwokkel
|
||||
from sat.core.i18n import _
|
||||
from sat.core import exceptions
|
||||
from sat.core.constants import Const as C
|
||||
from sat.core.log import getLogger
|
||||
from twisted.internet import defer
|
||||
from twisted.words.protocols.jabber import jid
|
||||
from wokkel import disco, iwokkel
|
||||
from zope.interface import implementer
|
||||
from twisted.words.protocols.jabber.xmlstream import XMPPHandler
|
||||
from sat.core.xmpp import SatXMPPEntity
|
||||
from sat.tools import utils
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
|
@ -123,16 +126,25 @@ class Invitation(object):
|
|||
invitation_elt['thumb_url'] = thumb_url
|
||||
return mess_data, invitation_elt
|
||||
|
||||
def sendPubsubInvitation(self, client, invitee_jid, service, node,
|
||||
item_id, name, extra):
|
||||
def sendPubsubInvitation(
|
||||
self,
|
||||
client: SatXMPPEntity,
|
||||
invitee_jid: jid.JID,
|
||||
service: jid.JID,
|
||||
node: str,
|
||||
item_id: Optional[str],
|
||||
name: Optional[str],
|
||||
extra: Optional[dict]
|
||||
) -> None:
|
||||
"""Send an pubsub invitation in a <message> stanza
|
||||
|
||||
@param invitee_jid(jid.JID): entitee to send invitation to
|
||||
@param service(jid.JID): pubsub service
|
||||
@param node(unicode): pubsub node
|
||||
@param item_id(unicode): pubsub id
|
||||
@param name(unicode, None): see [_generateBaseInvitation]
|
||||
@param extra(dict, None): see [_generateBaseInvitation]
|
||||
@param invitee_jid: entitee to send invitation to
|
||||
@param service: pubsub service
|
||||
@param node: pubsub node
|
||||
@param item_id: pubsub id
|
||||
None when the invitation is for a whole node
|
||||
@param name: see [_generateBaseInvitation]
|
||||
@param extra: see [_generateBaseInvitation]
|
||||
"""
|
||||
if extra is None:
|
||||
extra = {}
|
||||
|
|
@ -141,8 +153,22 @@ class Invitation(object):
|
|||
pubsub_elt = invitation_elt.addElement("pubsub")
|
||||
pubsub_elt["service"] = service.full()
|
||||
pubsub_elt["node"] = node
|
||||
pubsub_elt["item"] = item_id
|
||||
return client.send(mess_data["xml"])
|
||||
if item_id is None:
|
||||
try:
|
||||
namespace = extra.pop("namespace")
|
||||
except KeyError:
|
||||
raise exceptions.DataError('"namespace" key is missing in "extra" data')
|
||||
node_data_elt = pubsub_elt.addElement("node_data")
|
||||
node_data_elt["namespace"] = namespace
|
||||
try:
|
||||
node_data_elt.addChild(extra["element"])
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
pubsub_elt["item"] = item_id
|
||||
if "element" in extra:
|
||||
invitation_elt.addChild(extra.pop("element"))
|
||||
client.send(mess_data["xml"])
|
||||
|
||||
async def sendFileSharingInvitation(
|
||||
self, client, invitee_jid, service, repos_type=None, namespace=None, path=None,
|
||||
|
|
@ -207,53 +233,61 @@ class Invitation(object):
|
|||
file_sharing_elt["path"] = path
|
||||
client.send(mess_data["xml"])
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _parsePubsubElt(self, client, pubsub_elt):
|
||||
async def _parsePubsubElt(self, client, pubsub_elt):
|
||||
try:
|
||||
service = jid.JID(pubsub_elt["service"])
|
||||
node = pubsub_elt["node"]
|
||||
item_id = pubsub_elt.getAttribute("item")
|
||||
except (RuntimeError, KeyError):
|
||||
log.warning(_("Bad invitation, ignoring"))
|
||||
raise exceptions.DataError
|
||||
raise exceptions.DataError("Bad invitation, ignoring")
|
||||
|
||||
try:
|
||||
items, metadata = yield self._p.getItems(client, service, node,
|
||||
item_ids=[item_id])
|
||||
except Exception as e:
|
||||
log.warning(_("Can't get item linked with invitation: {reason}").format(
|
||||
reason=e))
|
||||
try:
|
||||
item_elt = items[0]
|
||||
except IndexError:
|
||||
log.warning(_("Invitation was linking to a non existing item"))
|
||||
raise exceptions.DataError
|
||||
item_id = pubsub_elt.getAttribute("item")
|
||||
|
||||
try:
|
||||
namespace = item_elt.firstChildElement().uri
|
||||
except Exception as e:
|
||||
log.warning(_("Can't retrieve namespace of invitation: {reason}").format(
|
||||
reason = e))
|
||||
raise exceptions.DataError
|
||||
if item_id is not None:
|
||||
try:
|
||||
items, metadata = await self._p.getItems(
|
||||
client, service, node, item_ids=[item_id]
|
||||
)
|
||||
except Exception as e:
|
||||
log.warning(_("Can't get item linked with invitation: {reason}").format(
|
||||
reason=e))
|
||||
try:
|
||||
item_elt = items[0]
|
||||
except IndexError:
|
||||
log.warning(_("Invitation was linking to a non existing item"))
|
||||
raise exceptions.DataError
|
||||
|
||||
args = [service, node, item_id, item_elt]
|
||||
defer.returnValue((namespace, args))
|
||||
try:
|
||||
namespace = item_elt.firstChildElement().uri
|
||||
except Exception as e:
|
||||
log.warning(_("Can't retrieve namespace of invitation: {reason}").format(
|
||||
reason = e))
|
||||
raise exceptions.DataError
|
||||
|
||||
def _parseFileSharingElt(self, client, file_sharing_elt):
|
||||
args = [service, node, item_id, item_elt]
|
||||
else:
|
||||
try:
|
||||
node_data_elt = next(pubsub_elt.elements((NS_INVITATION, "node_data")))
|
||||
except StopIteration:
|
||||
raise exceptions.DataError("Bad invitation, ignoring")
|
||||
namespace = node_data_elt['namespace']
|
||||
args = [service, node, None, node_data_elt]
|
||||
|
||||
return namespace, args
|
||||
|
||||
async def _parseFileSharingElt(self, client, file_sharing_elt):
|
||||
try:
|
||||
service = jid.JID(file_sharing_elt["service"])
|
||||
except (RuntimeError, KeyError):
|
||||
log.warning(_("Bad invitation, ignoring"))
|
||||
raise exceptions.DataError
|
||||
repos_type = file_sharing_elt.getAttribute("type", "files")
|
||||
namespace = file_sharing_elt.getAttribute("namespace")
|
||||
sharing_ns = file_sharing_elt.getAttribute("namespace")
|
||||
path = file_sharing_elt.getAttribute("path")
|
||||
args = [service, repos_type, namespace, path]
|
||||
args = [service, repos_type, sharing_ns, path]
|
||||
ns_fis = self.host.getNamespace("fis")
|
||||
return ns_fis, args
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def onInvitation(self, message_elt, client):
|
||||
async def onInvitation(self, message_elt, client):
|
||||
log.debug("invitation received [{profile}]".format(profile=client.profile))
|
||||
invitation_elt = message_elt.invitation
|
||||
|
||||
|
|
@ -275,7 +309,7 @@ class Invitation(object):
|
|||
xml = elt.toXml()))
|
||||
continue
|
||||
try:
|
||||
namespace, args = yield method(client, elt)
|
||||
namespace, args = await method(client, elt)
|
||||
except exceptions.DataError:
|
||||
log.warning("Can't parse invitation element: {xml}".format(
|
||||
xml = elt.toXml()))
|
||||
|
|
@ -288,7 +322,7 @@ class Invitation(object):
|
|||
'No handler for namespace "{namespace}", invitation ignored')
|
||||
.format(namespace=namespace))
|
||||
else:
|
||||
cb(client, name, extra, *args)
|
||||
await utils.asDeferred(cb, client, namespace, name, extra, *args)
|
||||
|
||||
|
||||
@implementer(iwokkel.IDisco)
|
||||
|
|
@ -299,7 +333,10 @@ class PubsubInvitationHandler(XMPPHandler):
|
|||
|
||||
def connectionInitialized(self):
|
||||
self.xmlstream.addObserver(
|
||||
INVITATION, self.plugin_parent.onInvitation, client=self.parent
|
||||
INVITATION,
|
||||
lambda message_elt: defer.ensureDeferred(
|
||||
self.plugin_parent.onInvitation(message_elt, client=self.parent)
|
||||
),
|
||||
)
|
||||
|
||||
def getDiscoInfo(self, requestor, target, nodeIdentifier=""):
|
||||
|
|
|
|||
Loading…
Reference in a new issue