Mercurial > libervia-backend
comparison sat/plugins/plugin_exp_invitation.py @ 2912:a3faf1c86596
plugin events: refactored invitation and personal lists logic:
- invitation logic has been moved to a new generic "plugin_exp_invitation" plugin
- plugin_misc_invitations has be rename "plugin_exp_email_invitation" to avoid confusion
- personal event list has be refactored to use a new experimental "list of interest", which regroup all interestings items, events or other ones
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 14 Apr 2019 08:21:51 +0200 |
parents | sat/plugins/plugin_exp_events.py@003b8b4b56a7 |
children | 672e6be3290f |
comparison
equal
deleted
inserted
replaced
2911:cd391ea847cb | 2912:a3faf1c86596 |
---|---|
1 #!/usr/bin/env python2 | |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # SAT plugin to detect language (experimental) | |
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) | |
6 | |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Affero General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Affero General Public License for more details. | |
16 | |
17 # You should have received a copy of the GNU Affero General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 from sat.core.i18n import _ | |
21 from sat.core import exceptions | |
22 from sat.core.constants import Const as C | |
23 from sat.core.log import getLogger | |
24 from twisted.internet import defer | |
25 from twisted.words.protocols.jabber import jid | |
26 from wokkel import disco, iwokkel | |
27 from zope.interface import implements | |
28 from twisted.words.protocols.jabber.xmlstream import XMPPHandler | |
29 | |
30 log = getLogger(__name__) | |
31 | |
32 | |
33 PLUGIN_INFO = { | |
34 C.PI_NAME: "Invitation", | |
35 C.PI_IMPORT_NAME: "INVITATION", | |
36 C.PI_TYPE: "EXP", | |
37 C.PI_PROTOCOLS: [], | |
38 C.PI_DEPENDENCIES: ["XEP-0060"], | |
39 C.PI_RECOMMENDATIONS: [], | |
40 C.PI_MAIN: "Invitation", | |
41 C.PI_HANDLER: "yes", | |
42 C.PI_DESCRIPTION: _(u"Experimental handling of invitations"), | |
43 } | |
44 | |
45 NS_INVITATION = u"https://salut-a-toi/protocol/invitation:0" | |
46 INVITATION = '/message/invitation[@xmlns="{ns_invit}"]'.format( | |
47 ns_invit=NS_INVITATION | |
48 ) | |
49 NS_INVITATION_LIST = NS_INVITATION + u"#list" | |
50 | |
51 | |
52 class Invitation(object): | |
53 | |
54 def __init__(self, host): | |
55 log.info(_(u"Invitation plugin initialization")) | |
56 self.host = host | |
57 self._p = self.host.plugins["XEP-0060"] | |
58 # map from namespace of the invitation to callback handling it | |
59 self._ns_cb = {} | |
60 | |
61 def getHandler(self, client): | |
62 return PubsubInvitationHandler(self) | |
63 | |
64 def registerNamespace(self, namespace, callback): | |
65 """Register a callback for a namespace | |
66 | |
67 @param namespace(unicode): namespace handled | |
68 @param callback(callbable): method handling the invitation | |
69 For pubsub invitation, it will be called with following arguments: | |
70 - client | |
71 - service(jid.JID): pubsub service jid | |
72 - node(unicode): pubsub node | |
73 - item_id(unicode, None): pubsub item id | |
74 - item_elt(domish.Element): item of the invitation | |
75 @raise exceptions.ConflictError: this namespace is already registered | |
76 """ | |
77 if namespace in self._ns_cb: | |
78 raise exceptions.ConflictError( | |
79 u"invitation namespace {namespace} is already register with {callback}" | |
80 .format(namespace=namespace, callback=self._ns_cb[namespace])) | |
81 self._ns_cb[namespace] = callback | |
82 | |
83 def sendPubsubInvitation(self, client, invitee_jid, service, node, | |
84 item_id): | |
85 """Send an invitation in a <message> stanza | |
86 | |
87 @param invitee_jid(jid.JID): entitee to send invitation to | |
88 @param service(jid.JID): pubsub service | |
89 @param node(unicode): pubsub node | |
90 @param item_id(unicode): pubsub id | |
91 """ | |
92 mess_data = { | |
93 "from": client.jid, | |
94 "to": invitee_jid, | |
95 "uid": "", | |
96 "message": {}, | |
97 "type": C.MESS_TYPE_CHAT, | |
98 "subject": {}, | |
99 "extra": {}, | |
100 } | |
101 client.generateMessageXML(mess_data) | |
102 invitation_elt = mess_data["xml"].addElement("invitation", NS_INVITATION) | |
103 pubsub_elt = invitation_elt.addElement(u"pubsub") | |
104 pubsub_elt[u"service"] = service.full() | |
105 pubsub_elt[u"node"] = node | |
106 pubsub_elt[u"item"] = item_id | |
107 client.send(mess_data[u"xml"]) | |
108 | |
109 @defer.inlineCallbacks | |
110 def _parsePubsubElt(self, client, pubsub_elt): | |
111 try: | |
112 service = jid.JID(pubsub_elt["service"]) | |
113 node = pubsub_elt["node"] | |
114 item_id = pubsub_elt.getAttribute("item") | |
115 except (RuntimeError, KeyError): | |
116 log.warning(_(u"Bad invitation, ignoring")) | |
117 raise exceptions.DataError | |
118 | |
119 try: | |
120 items, metadata = yield self._p.getItems(client, service, node, | |
121 item_ids=[item_id]) | |
122 except Exception as e: | |
123 log.warning(_(u"Can't get item linked with invitation: {reason}").format( | |
124 reason=e)) | |
125 try: | |
126 item_elt = items[0] | |
127 except IndexError: | |
128 log.warning(_(u"Invitation was linking to a non existing item")) | |
129 raise exceptions.DataError | |
130 | |
131 try: | |
132 namespace = item_elt.firstChildElement().uri | |
133 except Exception as e: | |
134 log.warning(_(u"Can't retrieve namespace of invitation: {reason}").format( | |
135 reason = e)) | |
136 raise exceptions.DataError | |
137 | |
138 args = [service, node, item_id, item_elt] | |
139 defer.returnValue((namespace, args)) | |
140 | |
141 @defer.inlineCallbacks | |
142 def onInvitation(self, message_elt, client): | |
143 invitation_elt = message_elt.invitation | |
144 for elt in invitation_elt.elements(): | |
145 if elt.uri != NS_INVITATION: | |
146 log.warning(u"unexpected element: {xml}".format(xml=elt.toXml())) | |
147 continue | |
148 if elt.name == u"pubsub": | |
149 method = self._parsePubsubElt | |
150 else: | |
151 log.warning(u"not implemented invitation element: {xml}".format( | |
152 xml = elt.toXml())) | |
153 continue | |
154 try: | |
155 namespace, args = yield method(client, elt) | |
156 except exceptions.DataError: | |
157 log.warning(u"Can't parse invitation element: {xml}".format( | |
158 xml = elt.toXml())) | |
159 continue | |
160 | |
161 try: | |
162 cb = self._ns_cb[namespace] | |
163 except KeyError: | |
164 log.warning(_(u'No handler for namespace "{namespace}", invitation ignored') | |
165 .format(namespace=namespace)) | |
166 else: | |
167 cb(client, *args) | |
168 | |
169 | |
170 class PubsubInvitationHandler(XMPPHandler): | |
171 implements(iwokkel.IDisco) | |
172 | |
173 def __init__(self, plugin_parent): | |
174 self.plugin_parent = plugin_parent | |
175 | |
176 def connectionInitialized(self): | |
177 self.xmlstream.addObserver( | |
178 INVITATION, self.plugin_parent.onInvitation, client=self.parent | |
179 ) | |
180 | |
181 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): | |
182 return [ | |
183 disco.DiscoFeature(NS_INVITATION), | |
184 ] | |
185 | |
186 def getDiscoItems(self, requestor, target, nodeIdentifier=""): | |
187 return [] |