annotate sat/plugins/plugin_misc_forums.py @ 3011:93da7c6f8e0c

plugin XEP-0198: retrieve missing messages + send buffered ones on hot reconnection: Missing one2one messages are now retrieved with MAM on hot reconnection, and buffered ones (which have most probably not been received by the server) are resent at the end of the reconnection workflow. IQ results are not re-sent on hot reconnection, as they don't make sense anymore with a new session. fix 330
author Goffi <goffi@goffi.org>
date Wed, 17 Jul 2019 09:28:35 +0200
parents 989b622faff6
children ab2696e34d29
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2484
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/env python2
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
3
2959
989b622faff6 plugins schema, tickets, merge_requests: use serialised data for extra dict + some cosmetic changes
Goffi <goffi@goffi.org>
parents: 2771
diff changeset
4 # SAT plugin for pubsub forums
2771
003b8b4b56a7 date update
Goffi <goffi@goffi.org>
parents: 2562
diff changeset
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org)
2484
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
6
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # This program is free software: you can redistribute it and/or modify
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # it under the terms of the GNU Affero General Public License as published by
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # the Free Software Foundation, either version 3 of the License, or
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
10 # (at your option) any later version.
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
11
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # This program is distributed in the hope that it will be useful,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
15 # GNU Affero General Public License for more details.
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
16
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # You should have received a copy of the GNU Affero General Public License
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
19
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 from sat.core.i18n import _
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 from sat.core.constants import Const as C
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
22 from sat.core import exceptions
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 from sat.core.log import getLogger
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from sat.tools.common import uri
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 from twisted.words.protocols.jabber import jid
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 from twisted.words.xish import domish
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
27 from twisted.internet import defer
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 import shortuuid
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
29 import json
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 log = getLogger(__name__)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
31
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
32 NS_FORUMS = u'org.salut-a-toi.forums:0'
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
33 NS_FORUMS_TOPICS = NS_FORUMS + u'#topics'
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
34
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
35 PLUGIN_INFO = {
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
36 C.PI_NAME: _("forums management"),
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 C.PI_IMPORT_NAME: "forums",
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
38 C.PI_TYPE: "EXP",
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
39 C.PI_PROTOCOLS: [],
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
40 C.PI_DEPENDENCIES: ["XEP-0060", "XEP-0277"],
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
41 C.PI_MAIN: "forums",
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
42 C.PI_HANDLER: "no",
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 C.PI_DESCRIPTION: _("""forums management plugin""")
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 }
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 FORUM_ATTR = {u'title', u'name', u'main-language', u'uri'}
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
46 FORUM_SUB_ELTS = (u'short-desc', u'desc')
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 FORUM_TOPICS_NODE_TPL = u'{node}#topics_{uuid}'
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 FORUM_TOPIC_NODE_TPL = u'{node}_{uuid}'
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
49
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
50
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 class forums(object):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
52
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 def __init__(self, host):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 log.info(_(u"forums plugin initialization"))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 self.host = host
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 self._m = self.host.plugins['XEP-0277']
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
57 self._p = self.host.plugins['XEP-0060']
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 self._node_options = {
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 self._p.OPT_ACCESS_MODEL: self._p.ACCESS_OPEN,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 self._p.OPT_PERSIST_ITEMS: 1,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
61 self._p.OPT_MAX_ITEMS: -1,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 self._p.OPT_DELIVER_PAYLOADS: 1,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
63 self._p.OPT_SEND_ITEM_SUBSCRIBE: 1,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
64 self._p.OPT_PUBLISH_MODEL: self._p.ACCESS_OPEN,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
65 }
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
66 host.registerNamespace('forums', NS_FORUMS)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 host.bridge.addMethod("forumsGet", ".plugin",
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 in_sign='ssss', out_sign='s',
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 method=self._get,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 async=True)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
71 host.bridge.addMethod("forumsSet", ".plugin",
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 in_sign='sssss', out_sign='',
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
73 method=self._set,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 async=True)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
75 host.bridge.addMethod("forumTopicsGet", ".plugin",
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
76 in_sign='ssa{ss}s', out_sign='(aa{ss}a{ss})',
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
77 method=self._getTopics,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
78 async=True)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
79 host.bridge.addMethod("forumTopicCreate", ".plugin",
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
80 in_sign='ssa{ss}s', out_sign='',
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
81 method=self._createTopic,
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
82 async=True)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
83
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
84 @defer.inlineCallbacks
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
85 def _createForums(self, client, forums, service, node, forums_elt=None, names=None):
2959
989b622faff6 plugins schema, tickets, merge_requests: use serialised data for extra dict + some cosmetic changes
Goffi <goffi@goffi.org>
parents: 2771
diff changeset
86 """Recursively create <forums> element(s)
2484
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
87
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 @param forums(list): forums which may have subforums
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
89 @param service(jid.JID): service where the new nodes will be created
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 @param node(unicode): node of the forums
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
91 will be used as basis for the newly created nodes
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
92 @param parent_elt(domish.Element, None): element where the forum must be added
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 if None, the root <forums> element will be created
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
94 @return (domish.Element): created forums
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
95 """
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 if not isinstance(forums, list):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
97 raise ValueError(_(u"forums arguments must be a list of forums"))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
98 if forums_elt is None:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 forums_elt = domish.Element((NS_FORUMS, u'forums'))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
100 assert names is None
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 names = set()
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
102 else:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 if names is None or forums_elt.name != u'forums':
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 raise exceptions.InternalError(u'invalid forums or names')
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
105 assert names is not None
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
106
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
107 for forum in forums:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 if not isinstance(forum, dict):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
109 raise ValueError(_(u"A forum item must be a dictionary"))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 forum_elt = forums_elt.addElement('forum')
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
111
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
112 for key, value in forum.iteritems():
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
113 if key == u'name' and key in names:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
114 raise exceptions.ConflictError(_(u"following forum name is not unique: {name}").format(name=key))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
115 if key == u'uri' and not value.strip():
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
116 log.info(_(u"creating missing forum node"))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
117 forum_node = FORUM_TOPICS_NODE_TPL.format(node=node, uuid=shortuuid.uuid())
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
118 yield self._p.createNode(client, service, forum_node, self._node_options)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
119 value = uri.buildXMPPUri(u'pubsub',
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
120 path=service.full(),
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
121 node=forum_node)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
122 if key in FORUM_ATTR:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
123 forum_elt[key] = value.strip()
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
124 elif key in FORUM_SUB_ELTS:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
125 forum_elt.addElement(key, content=value)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
126 elif key == u'sub-forums':
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
127 sub_forums_elt = forum_elt.addElement(u'forums')
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
128 yield self._createForums(client, value, service, node, sub_forums_elt, names=names)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
129 else:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
130 log.warning(_(u"Unknown forum attribute: {key}").format(key=key))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
131 if not forum_elt.getAttribute(u'title'):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
132 name = forum_elt.getAttribute(u'name')
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
133 if name:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
134 forum_elt[u'title'] = name
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
135 else:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
136 raise ValueError(_(u"forum need a title or a name"))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
137 if not forum_elt.getAttribute(u'uri') and not forum_elt.children:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
138 raise ValueError(_(u"forum need uri or sub-forums"))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 defer.returnValue(forums_elt)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
140
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
141 def _parseForums(self, parent_elt=None, forums=None):
2959
989b622faff6 plugins schema, tickets, merge_requests: use serialised data for extra dict + some cosmetic changes
Goffi <goffi@goffi.org>
parents: 2771
diff changeset
142 """Recursivly parse a <forums> elements and return corresponding forums data
2484
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
143
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
144 @param item(domish.Element): item with <forums> element
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
145 @param parent_elt(domish.Element, None): element to parse
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
146 @return (list): parsed data
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
147 @raise ValueError: item is invalid
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
148 """
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
149 if parent_elt.name == u'item':
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
150 forums = []
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
151 try:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
152 forums_elt = next(parent_elt.elements(NS_FORUMS, u'forums'))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
153 except StopIteration:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
154 raise ValueError(_(u"missing <forums> element"))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
155 else:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
156 forums_elt = parent_elt
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
157 if forums is None:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
158 raise exceptions.InternalError(u'expected forums')
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
159 if forums_elt.name != 'forums':
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
160 raise ValueError(_(u'Unexpected element: {xml}').format(xml=forums_elt.toXml()))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
161 for forum_elt in forums_elt.elements():
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
162 if forum_elt.name == 'forum':
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
163 data = {}
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
164 for attrib in FORUM_ATTR.intersection(forum_elt.attributes):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
165 data[attrib] = forum_elt[attrib]
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
166 unknown = set(forum_elt.attributes).difference(FORUM_ATTR)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
167 if unknown:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
168 log.warning(_(u"Following attributes are unknown: {unknown}").format(unknown=unknown))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
169 for elt in forum_elt.elements():
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
170 if elt.name in FORUM_SUB_ELTS:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
171 data[elt.name] = unicode(elt)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
172 elif elt.name == u'forums':
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
173 sub_forums = data[u'sub-forums'] = []
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
174 self._parseForums(elt, sub_forums)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
175 if not u'title' in data or not {u'uri', u'sub-forums'}.intersection(data):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
176 log.warning(_(u"invalid forum, ignoring: {xml}").format(xml=forum_elt.toXml()))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
177 else:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
178 forums.append(data)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
179 else:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
180 log.warning(_(u"unkown forums sub element: {xml}").format(xml=forum_elt))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
181
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
182 return forums
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
183
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
184 def _get(self, service=None, node=None, forums_key=None, profile_key=C.PROF_KEY_NONE):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
185 client = self.host.getClient(profile_key)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
186 if service.strip():
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
187 service = jid.JID(service)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
188 else:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
189 service = None
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
190 if not node.strip():
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
191 node = None
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
192 d=self.get(client, service, node, forums_key or None)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
193 d.addCallback(lambda data: json.dumps(data))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
194 return d
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
195
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
196 @defer.inlineCallbacks
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
197 def get(self, client, service=None, node=None, forums_key=None):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
198 if service is None:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
199 service = client.pubsub_service
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
200 if node is None:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
201 node = NS_FORUMS
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
202 if forums_key is None:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
203 forums_key = u'default'
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
204 items_data = yield self._p.getItems(client, service, node, item_ids=[forums_key])
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
205 item = items_data[0][0]
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
206 # we have the item and need to convert it to json
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
207 forums = self._parseForums(item)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
208 defer.returnValue(forums)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
209
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
210 def _set(self, forums, service=None, node=None, forums_key=None, profile_key=C.PROF_KEY_NONE):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
211 client = self.host.getClient(profile_key)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
212 forums = json.loads(forums)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
213 if service.strip():
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
214 service = jid.JID(service)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
215 else:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
216 service = None
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
217 if not node.strip():
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
218 node = None
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
219 return self.set(client, forums, service, node, forums_key or None)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
220
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
221 @defer.inlineCallbacks
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
222 def set(self, client, forums, service=None, node=None, forums_key=None):
2959
989b622faff6 plugins schema, tickets, merge_requests: use serialised data for extra dict + some cosmetic changes
Goffi <goffi@goffi.org>
parents: 2771
diff changeset
223 """Create or replace forums structure
2484
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
224
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
225 @param forums(list): list of dictionary as follow:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
226 a dictionary represent a forum metadata, with the following keys:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
227 - title: title of the forum
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
228 - name: short name (unique in those forums) for the forum
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
229 - main-language: main language to be use in the forums
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
230 - uri: XMPP uri to the microblog node hosting the forum
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
231 - short-desc: short description of the forum (in main-language)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
232 - desc: long description of the forum (in main-language)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
233 - sub-forums: a list of sub-forums with the same structure
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
234 title or name is needed, and uri or sub-forums
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
235 @param forums_key(unicode, None): key (i.e. item id) of the forums
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
236 may be used to store different forums structures for different languages
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
237 None to use "default"
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
238 """
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
239 if service is None:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
240 service = client.pubsub_service
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
241 if node is None:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
242 node = NS_FORUMS
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
243 if forums_key is None:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
244 forums_key = u'default'
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
245 forums_elt = yield self._createForums(client, forums, service, node)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
246 yield self._p.sendItem(client, service, node, forums_elt, item_id=forums_key)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
247
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
248 def _getTopics(self, service, node, extra=None, profile_key=C.PROF_KEY_NONE):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
249 client = self.host.getClient(profile_key)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
250 extra = self._p.parseExtra(extra)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
251 d = self.getTopics(client, jid.JID(service), node, rsm_request=extra.rsm_request, extra=extra.extra)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
252 d.addCallback(lambda(topics, metadata): (topics, {k: unicode(v) for k,v in metadata.iteritems()}))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
253 return d
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
254
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
255 @defer.inlineCallbacks
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
256 def getTopics(self, client, service, node, rsm_request=None, extra=None):
2959
989b622faff6 plugins schema, tickets, merge_requests: use serialised data for extra dict + some cosmetic changes
Goffi <goffi@goffi.org>
parents: 2771
diff changeset
257 """Retrieve topics data
2484
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
258
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
259 Topics are simple microblog URIs with some metadata duplicated from first post
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
260 """
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
261 topics_data = yield self._p.getItems(client, service, node, rsm_request=rsm_request, extra=extra)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
262 topics = []
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
263 item_elts, metadata = topics_data
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
264 for item_elt in item_elts:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
265 topic_elt = next(item_elt.elements(NS_FORUMS, u'topic'))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
266 title_elt = next(topic_elt.elements(NS_FORUMS, u'title'))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
267 topic = {u'uri': topic_elt[u'uri'],
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
268 u'author': topic_elt[u'author'],
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
269 u'title': unicode(title_elt)}
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
270 topics.append(topic)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
271 defer.returnValue((topics, metadata))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
272
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
273 def _createTopic(self, service, node, mb_data, profile_key):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
274 client = self.host.getClient(profile_key)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
275 return self.createTopic(client, jid.JID(service), node, mb_data)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
276
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
277 @defer.inlineCallbacks
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
278 def createTopic(self, client, service, node, mb_data):
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
279 try:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
280 title = mb_data[u'title']
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
281 if not u'content' in mb_data:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
282 raise KeyError(u'content')
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
283 except KeyError as e:
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
284 raise exceptions.DataError(u"missing mandatory data: {key}".format(key=e.args[0]))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
285
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
286 topic_node = FORUM_TOPIC_NODE_TPL.format(node=node, uuid=shortuuid.uuid())
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
287 yield self._p.createNode(client, service, topic_node, self._node_options)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
288 self._m.send(client, mb_data, service, topic_node)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
289 topic_uri = uri.buildXMPPUri(u'pubsub',
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
290 subtype=u'microblog',
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
291 path=service.full(),
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
292 node=topic_node)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
293 topic_elt = domish.Element((NS_FORUMS, 'topic'))
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
294 topic_elt[u'uri'] = topic_uri
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
295 topic_elt[u'author'] = client.jid.userhost()
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
296 topic_elt.addElement(u'title', content = title)
785b6a1cef0a plugin forums: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
297 yield self._p.sendItem(client, service, node, topic_elt)