comparison src/plugins/plugin_misc_groupblog.py @ 308:ce3607b7198d

plugin group blog: blog collection cleaning
author Goffi <goffi@goffi.org>
date Thu, 07 Apr 2011 23:40:33 +0200
parents 1e4575e12581
children 53adec87d1d7
comparison
equal deleted inserted replaced
307:1e4575e12581 308:ce3607b7198d
18 You should have received a copy of the GNU General Public License 18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. 19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 """ 20 """
21 21
22 from logging import debug, info, error 22 from logging import debug, info, error
23 from twisted.internet import protocol 23 from twisted.internet import protocol, defer
24 from twisted.words.protocols.jabber import jid 24 from twisted.words.protocols.jabber import jid
25 from twisted.words.protocols.jabber import error as jab_error 25 from twisted.words.protocols.jabber import error as jab_error
26 import twisted.internet.error 26 import twisted.internet.error
27 from twisted.words.xish import domish 27 from twisted.words.xish import domish
28 from sat.tools.xml_tools import ElementParser 28 from sat.tools.xml_tools import ElementParser
30 from wokkel import disco,pubsub 30 from wokkel import disco,pubsub
31 from feed.atom import Entry, Author 31 from feed.atom import Entry, Author
32 import uuid 32 import uuid
33 from time import time 33 from time import time
34 34
35 NS_BLOG_COLLECTION = 'urn:xmpp:blogcollection:0'
36 MBLOG_COLLECTION = 'MBLOGCOLLECTION' 35 MBLOG_COLLECTION = 'MBLOGCOLLECTION'
37 CONFIG_NODE = 'CONFIG' 36 CONFIG_NODE = 'CONFIG'
38 NS_ACCESS_MODEL = 'pubsub#access_model' 37 NS_ACCESS_MODEL = 'pubsub#access_model'
39 NS_PERSIST_ITEMS = 'pubsub#persist_items' 38 NS_PERSIST_ITEMS = 'pubsub#persist_items'
40 NS_MAX_ITEMS = 'pubsub#max_items' 39 NS_MAX_ITEMS = 'pubsub#max_items'
53 } 52 }
54 53
55 class NodeCreationError(Exception): 54 class NodeCreationError(Exception):
56 pass 55 pass
57 56
57 class NodeDeletionError(Exception):
58 pass
59
58 class GroupBlog(): 60 class GroupBlog():
59 """This class use a PubSub Collection to manage roster access on microblog""" 61 """This class use a PubSub Collection to manage roster access on microblog"""
60 62
61 def __init__(self, host): 63 def __init__(self, host):
62 info(_("Group blog plugin initialization")) 64 info(_("Group blog plugin initialization"))
63 self.host = host 65 self.host = host
64 self._blog_nodes={} 66 self._blog_nodes={}
65 """host.bridge.addMethod("getLastMicroblogs", ".communication", 67
66 in_sign='sis', out_sign='aa{ss}', 68 host.bridge.addMethod("cleanBlogCollection", ".communication", in_sign='s', out_sign='',
67 method=self.getLastMicroblogs, 69 method=self.cleanBlogCollection,
68 async = True,
69 doc = { 'summary':'retrieve items',
70 'param_0':'jid: publisher of wanted microblog',
71 'param_1':'max_items: see XEP-0060 #6.5.7',
72 'param_2':'%(doc_profile)s',
73 'return':'list of microblog data (dict)'
74 })
75 host.bridge.addMethod("setMicroblogAccess", ".communication", in_sign='ss', out_sign='',
76 method=self.setMicroblogAccess,
77 doc = {
78 })"""
79
80 host.bridge.addMethod("initBlogCollection", ".communication", in_sign='s', out_sign='',
81 method=self.initBlogCollection,
82 doc = { 70 doc = {
83 }) 71 })
84 72
85 host.bridge.addMethod("getMblogNodes", ".communication", in_sign='s', out_sign='a{sas}', 73 host.bridge.addMethod("getMblogNodes", ".communication", in_sign='s', out_sign='a{sas}',
86 method=self.getMblogNodes, 74 method=self.getMblogNodes,
145 client = self.host.getClient(profile) 133 client = self.host.getClient(profile)
146 if not client: 134 if not client:
147 error(_('No client for this profile key: %s') % profile_key) 135 error(_('No client for this profile key: %s') % profile_key)
148 return 136 return
149 client.client_initialized.addCallback(after_init) 137 client.client_initialized.addCallback(after_init)
150
151
152 def initBlogCollection(self, profile_key="@DEFAULT@"):
153 _jid, xmlstream = self.host.getJidNStream(profile_key)
154 _options = {NS_NODE_TYPE:TYPE_COLLECTION}
155 def cb(result):
156 #Node is created with right permission
157 debug(_("Microblog node collection created"))
158
159 def fatal_err(s_error):
160 #Something went wrong
161 error(_("Can't create node collection"))
162
163 def err_cb(s_error):
164 #If the node already exists, the condition is "conflict",
165 #else we have an unmanaged error
166 if s_error.value.condition=='conflict':
167 fatal_err(s_error)
168 else:
169 fatal_err(s_error)
170
171 def create_node():
172 #return self.host.plugins["XEP-0060"].createNode(_jid.userhostJID(), NS_BLOG_COLLECTION, _options, profile_key=profile_key)
173 return self.host.plugins["XEP-0060"].createNode(jid.JID("pubsub.tazar.int"), self._getRootNode(_jid), _options, profile_key=profile_key)
174
175 create_node().addCallback(cb).addErrback(err_cb)
176 138
177 def _publishMblog(self, name, message, pubsub_ent, profile): 139 def _publishMblog(self, name, message, pubsub_ent, profile):
178 """Actually publish the message on the group blog 140 """Actually publish the message on the group blog
179 @param name: name of the node where we publish 141 @param name: name of the node where we publish
180 @param message: message to publish 142 @param message: message to publish
288 if not client: 250 if not client:
289 error(_('No client for this profile key: %s') % profile_key) 251 error(_('No client for this profile key: %s') % profile_key)
290 return 252 return
291 client.client_initialized.addCallback(after_init) 253 client.client_initialized.addCallback(after_init)
292 254
255 def _doCleaning(self, result, pubsub_ent, profile):
256 """Compare the node in config node, and the existing nodes, and delete unknown ones"""
257 #TODO: manage groups which don't exist anymore
258 assert(len(result)==2)
259 assert(result[0][0]==True and result[1][0]==True)
260 config_nodes = [item.firstChildElement()["node"] for item in result[0][1]]
261 existing_nodes = [item.nodeIdentifier for item in result[1][1]._items]
262 to_delete = set(config_nodes).symmetric_difference(existing_nodes)
263 def check_deletion(result):
264 for (success, value) in result:
265 if not success:
266 msg = _("Can't delete node")
267 error(msg)
268 raise NodeDeletionError(msg)
269 #TODO: log node which was not deleted
270
271
272 d = defer.DeferredList([self.host.plugins["XEP-0060"].deleteNode(pubsub_ent, node, profile) for node in to_delete])
273 d.addCallback(check_deletion)
274
275 def cleanBlogCollection(self, profile_key='@DEFAULT@'):
276 """Remove blog nodes not referenced in config node"""
277 debug(_('Getting mblog nodes'))
278 profile = self.host.memory.getProfileName(profile_key)
279 if not profile:
280 error(_("Unknown profile"))
281 return {}
282
283 def after_init(ignore):
284 pubsub_ent = self.host.memory.getServerServiceEntity("pubsub", "service", profile)
285 _jid, xmlstream = self.host.getJidNStream(profile_key)
286 d_config = self.host.plugins["XEP-0060"].getItems(pubsub_ent, self._getConfigNode(_jid), profile_key=profile_key)
287 d_root = client.disco.requestItems(pubsub_ent, self._getRootNode(client.jid))
288 defer.DeferredList([d_config, d_root]).addCallback(self._doCleaning, pubsub_ent, profile)
289
290 client = self.host.getClient(profile)
291 if not client:
292 error(_('No client for this profile key: %s') % profile_key)
293 return
294 client.client_initialized.addCallback(after_init)
295