# HG changeset patch # User Goffi # Date 1302633647 -7200 # Node ID 0aa6ca6cdbddedb1dbfb067a42474b518c5875de # Parent 53adec87d1d709a1295d4e73d39c9cc73150807b plugin group blog: group blog now use PEP to take profit of autosubscribe diff -r 53adec87d1d7 -r 0aa6ca6cdbdd src/plugins/plugin_misc_groupblog.py --- a/src/plugins/plugin_misc_groupblog.py Mon Apr 11 12:47:35 2011 +0200 +++ b/src/plugins/plugin_misc_groupblog.py Tue Apr 12 20:40:47 2011 +0200 @@ -32,7 +32,7 @@ import uuid from time import time -MBLOG_COLLECTION = 'MBLOGCOLLECTION' +NS_MICROBLOG = 'urn:xmpp:microblog:%02d' CONFIG_NODE = 'CONFIG' OPT_ACCESS_MODEL = 'pubsub#access_model' OPT_PERSIST_ITEMS = 'pubsub#persist_items' @@ -66,6 +66,8 @@ info(_("Group blog plugin initialization")) self.host = host self._blog_nodes={} + for i in range(1,21): + self.host.plugins["XEP-0163"].addPEPEvent("MICROBLOG_%02d" % i, NS_MICROBLOG % i, self.host.plugins["XEP-0277"].microblogCB, None) host.bridge.addMethod("cleanBlogCollection", ".communication", in_sign='s', out_sign='', method=self.cleanBlogCollection, @@ -98,6 +100,12 @@ def _getRootNode(self, entity): return "%(entity)s_%(root_suff)s" % {'entity':entity.userhost(), 'root_suff':MBLOG_COLLECTION} + def _getNodeName(self, number): + """Return the node name + @param number: int number of the node + @param entity: jid of the owner""" + return NS_MICROBLOG % number + def _getConfigNode(self, entity): return "%(entity)s_%(root_suff)s" % {'entity':entity.userhost(), 'root_suff':CONFIG_NODE} @@ -145,36 +153,38 @@ return client.client_initialized.addCallback(after_init) - def _publishMblog(self, name, message, pubsub_ent, profile): + def _publishMblog(self, name, message, client): """Actually publish the message on the group blog @param name: name of the node where we publish @param message: message to publish - @param pubsub_ent: entity of the publish-subscribe service - @param profile: profile of the owner of the group""" - mblog_item = self.host.plugins["XEP-0277"].data2entry({'content':message}, profile) - defer_blog = self.host.plugins["XEP-0060"].publish(pubsub_ent, name, items=[mblog_item], profile_key=profile) + @param client: SatXMPPClient of the published""" + mblog_item = self.host.plugins["XEP-0277"].data2entry({'content':message}, client.profile) + defer_blog = self.host.plugins["XEP-0060"].publish(client.jid.userhostJID(), name, items=[mblog_item], profile_key=client.profile) defer_blog.addErrback(self._mblogPublicationFailed) - def _groupNodeCreated(self, ignore, groups, name, message, user_jid, pubsub_ent, profile): + def _groupNodeCreated(self, ignore, groups, name, message, client): """A group node as been created, we need to add it to the configure node, and send the message to it @param groups: list of groups authorized to subscribe to the node - @param name: unique name of the group + @param name: unique name of the node @param message: message to publish to the group - @param user_jid: jid of the owner of the node - @param pubsub_ent: entity of the publish-subscribe service - @param profile: profile of the owner of the group""" - config_node = self._getConfigNode(user_jid) + @param client: SatXMPPClient""" + def configNodeUpdated(result): + self._blog_nodes[client.profile][name] = groups + debug(_("Configuration node updated")) + + config_node = self._getConfigNode(client.jid) _payload = domish.Element(('','node_association')) _payload['node'] = name for group in groups: _payload.addElement('group',content=group) config_item = pubsub.Item(payload=_payload) - defer_config = self.host.plugins["XEP-0060"].publish(pubsub_ent, config_node, items=[config_item], profile_key=profile) - defer_config.addCallback(lambda x: debug(_("Configuration node updated"))) + pubsub_ent = self.host.memory.getServerServiceEntity("pubsub", "service", client.profile) + defer_config = self.host.plugins["XEP-0060"].publish(pubsub_ent, config_node, items=[config_item], profile_key=client.profile) + defer_config.addCallback(configNodeUpdated) defer_config.addErrback(self._configUpdateFailed) #Finally, we publish the message - self._publishMblog(name, message, pubsub_ent, profile) + self._publishMblog(name, message, client) def _mblogPublicationFailed(self, failure): @@ -187,38 +197,42 @@ import pdb pdb.set_trace() - def _nodeCreationFailed(self, failure, name, user_jid, groups, pubsub_ent, message, profile): - #TODO - if failure.value.condition == "item-not-found": - #The root node doesn't exists - def err_creating_root_node(failure): - msg = _("Can't create Root node") - error(msg) - raise NodeCreationError(msg) + def _nodeCreationFailed(self, failure, name, groups, message, client): + #FIXME: temporary behaviour is to delete the node, + #user input should be required in the future + def unmanagedError(failure): + msg = _("Can't create node") + error(msg) + raise NodeCreationError(msg) + + if failure.value.condition == 'conflict': + pubsub_elts = filter(lambda elt: elt.name == 'pubsub', failure.value.children) + if pubsub_elts: + create_elts = filter(lambda elt: elt.name == 'create', pubsub_elts[0].children) + if create_elts: + _from = jid.JID(failure.value.stanza['from']) + _node = create_elts[0]['node'] + d = self.host.plugins["XEP-0060"].deleteNode(_from, _node, client.profile) + d.addCallback(self._createNode, name, groups, message, client) + d.addErrback(unmanagedError) + else: + unmanagedError(None) + msg = _("Can't create node") + error(msg) + raise NodeCreationError(msg) - _options = {OPT_NODE_TYPE:TYPE_COLLECTION} - d = self.host.plugins["XEP-0060"].createNode(pubsub_ent, self._getRootNode(user_jid), _options, profile_key=profile) - d.addCallback(self._createNode, name, user_jid, groups, pubsub_ent, message, profile) - d.addErrback(err_creating_root_node) - else: - import pdb - pdb.set_trace() - - def _createNode(self, ignore, name, user_jid, groups, pubsub_ent, message, profile): + def _createNode(self, ignore, name, groups, message, client): """create a group microblog node @param ignore: ignored param, necessary to be added as a deferred callback @param name: name of the node - @param user_jid: jid of the user creating the node @param groups: list of group than can subscribe to the node - @param pubsub_ent: publish/subscribe service's entity @param message: message to publish - @param profile: profile of the user creating the node""" + @param client: SatXMPPClient""" _options = {OPT_ACCESS_MODEL:"roster", OPT_PERSIST_ITEMS:1, OPT_MAX_ITEMS:-1, - 'pubsub#node_type':'leaf', 'pubsub#collection':self._getRootNode(user_jid), 'pubsub#roster_groups_allowed':groups} - d = self.host.plugins["XEP-0060"].createNode(pubsub_ent, name, _options, profile_key=profile) - d.addCallback(self._groupNodeCreated, groups, name, message, user_jid, pubsub_ent, profile) - d.addErrback(self._nodeCreationFailed, name, user_jid, groups, pubsub_ent, message, profile) + d = self.host.plugins["XEP-0060"].createNode(client.jid.userhostJID(), name, _options, client.profile) + d.addCallback(self._groupNodeCreated, groups, name, message, client) + d.addErrback(self._nodeCreationFailed, name, groups, message, client) def _getNodeForGroups(self, groups, profile): """Return node associated with the given list of groups @@ -230,6 +244,19 @@ return node return None + def _getFreeNode(self, entity, profile): + """Return a free group number, + raise an exception if we have reach limit""" + _all = set([self._getNodeName(idx) for idx in range(1,21)]) + _used = set(self._blog_nodes[profile].keys()) + _free = _all.difference(_used) + if not _free: + msg = _("Can't create group node: no more free node available") + warning(msg) + raise NodeCreationError(msg) + else: + return _free.pop() + def sendGroupBlog(self, groups, message, profile_key='@DEFAULT@'): """Publish a microblog to the node associated to the groups If the node doesn't exist, it is created, then the message is posted @@ -246,14 +273,13 @@ _groups = list(set(groups).intersection(client.roster.getGroups())) #We only keep group which actually exist #TODO: send an error signal if user want to post to non existant groups _groups.sort() - pubsub_ent = self.host.memory.getServerServiceEntity("pubsub", "service", profile) for group in _groups: _node = self._getNodeForGroups([group], profile) if not _node: - _node_name = unicode(uuid.uuid4()) - self._createNode(None, _node_name, client.jid, [group], pubsub_ent, message, profile) + _node_name = self._getFreeNode(client.jid, profile) + self._createNode(None, _node_name, [group], message, client) else: - self._publishMblog(_node, message, pubsub_ent, profile) + self._publishMblog(_node, message, client) client = self.host.getClient(profile) if not client: @@ -322,3 +348,4 @@ error(_('No client for this profile key: %s') % profile_key) return client.client_initialized.addCallback(after_init) + diff -r 53adec87d1d7 -r 0aa6ca6cdbdd src/plugins/plugin_xep_0163.py --- a/src/plugins/plugin_xep_0163.py Mon Apr 11 12:47:35 2011 +0200 +++ b/src/plugins/plugin_xep_0163.py Tue Apr 12 20:40:47 2011 +0200 @@ -62,14 +62,15 @@ disco_info.extend(map(disco.DiscoFeature, self.pep_events)) return True - def addPEPEvent(self, event_type, name, in_callback, out_callback, notify = True): + def addPEPEvent(self, event_type, name, in_callback, out_callback = None, notify = True): """Add a Personal Eventing Protocol event manager @param event_type: type of the event (always uppercase), can be MOOD, TUNE, etc @param name: namespace of the node (e.g. http://jabber.org/protocol/mood for User Mood) @param in_callback: method to call when this event occur @param out_callback: method to call when we want to publish this event @param notify: add autosubscribe (+notify) if True""" - self.pep_out_cb[event_type]=out_callback + if out_callback: + self.pep_out_cb[event_type] = out_callback self.pep_events.add(name) if notify: self.pep_events.add(name+"+notify") diff -r 53adec87d1d7 -r 0aa6ca6cdbdd src/plugins/plugin_xep_0277.py --- a/src/plugins/plugin_xep_0277.py Mon Apr 11 12:47:35 2011 +0200 +++ b/src/plugins/plugin_xep_0277.py Tue Apr 12 20:40:47 2011 +0200 @@ -159,6 +159,9 @@ @param profile_key: profile key""" _jid, xmlstream = self.host.getJidNStream(profile_key) + if not _jid: + error(_("Can't find profile's jid")) + return _options = {OPT_ACCESS_MODEL:access, OPT_PERSIST_ITEMS:1, OPT_MAX_ITEMS:-1} def cb(result): #Node is created with right permission