Mercurial > libervia-backend
diff sat/plugins/plugin_xep_0277.py @ 3308:384283adcce1
plugins XEP-0059, XEP-0060, XEP-0277, XEP-0313: better serialisation:
`data_format.serialise` is now used for `mbGet`, and RSM/MAM values are not transtyped to
strings anymore. A serialised dict is now used, items are put in the `items` key.
Comments handling has been refactored to use a list for the potentially multiple comments
nodes.
`rsm` data are now in a `rsm` key of the dict, and `mam` data are merged with other
metadata.
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 16 Jul 2020 09:07:20 +0200 |
parents | 84a94b385760 |
children | d49607e3a066 |
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0277.py Fri Jun 19 15:47:16 2020 +0200 +++ b/sat/plugins/plugin_xep_0277.py Thu Jul 16 09:07:20 2020 +0200 @@ -103,7 +103,7 @@ "mbGet", ".plugin", in_sign="ssiasa{ss}s", - out_sign="(asa{ss})", + out_sign="s", method=self._mbGet, async_=True, ) @@ -357,21 +357,25 @@ ) # links + comments = microblog_data['comments'] = [] for link_elt in entry_elt.elements(NS_ATOM, "link"): if ( link_elt.getAttribute("rel") == "replies" and link_elt.getAttribute("title") == "comments" ): - key = check_conflict("comments", True) - microblog_data[key] = link_elt["href"] + uri = link_elt["href"] + comments_data = { + "uri": uri, + } try: - service, node = self.parseCommentUrl(microblog_data[key]) + service, node = self.parseCommentUrl(uri) except Exception as e: - log.warning(f"Can't parse url {microblog_data[key]}: {e}") - del microblog_data[key] + log.warning(f"Can't parse comments url: {e}") + continue else: - microblog_data["{}_service".format(key)] = service.full() - microblog_data["{}_node".format(key)] = node + comments_data["service"] = service.full() + comments_data["node"] = node + comments.append(comments_data) else: rel = link_elt.getAttribute("rel", "") title = link_elt.getAttribute("title", "") @@ -589,9 +593,10 @@ entry_elt.addElement("id", content=entry_id) # ## comments ## - if "comments" in data: + for comments_data in data.get('comments', []): link_elt = entry_elt.addElement("link") - link_elt["href"] = data["comments"] + # XXX: "uri" is set in self._manageComments if not already existing + link_elt["href"] = comments_data["uri"] link_elt["rel"] = "replies" link_elt["title"] = "comments" @@ -646,8 +651,8 @@ def _manageComments(self, client, mb_data, service, node, item_id, access=None): """Check comments keys in mb_data and create comments node if necessary - if mb_data['comments'] exists, it is used (or mb_data['comments_service'] and/or mb_data['comments_node']), - else it is generated (if allow_comments is True). + if a comments node metadata is set in the mb_data['comments'] list, it is used + otherwise it is generated (if allow_comments is True). @param mb_data(dict): microblog mb_data @param service(jid.JID, None): PubSub service of the parent item @param node(unicode): node of the parent item @@ -655,11 +660,13 @@ @param access(unicode, None): access model None to use same access model as parent item """ - # FIXME: if 'comments' already exists in mb_data, - # it is not used to create the Node allow_comments = mb_data.pop("allow_comments", None) if allow_comments is None: - return + if "comments" in mb_data: + mb_data["allow_comments"] = True + else: + # no comments set or requested, nothing to do + return elif allow_comments == False: if "comments" in mb_data: log.warning( @@ -671,6 +678,13 @@ del mb_data["comments"] return + # we have usually a single comment node, but the spec allow several, so we need to + # handle this in a list + if len(mb_data.setdefault('comments', [])) == 0: + # we need at least one comment node + comments_data = {} + mb_data['comments'].append({}) + if access is None: # TODO: cache access models per service/node parent_node_config = yield self._p.getConfiguration(client, service, node) @@ -689,63 +703,65 @@ # if other plugins need to change the options yield self.host.trigger.point("XEP-0277_comments", client, mb_data, options) - try: - comments_node = mb_data["comments_node"] - except KeyError: - comments_node = self.getCommentsNode(item_id) - else: - if not comments_node: - raise exceptions.DataError( - "if comments_node is present, it must not be empty" + for comments_data in mb_data['comments']: + uri = comments_data.get('uri') + comments_node = comments_data.get('node') + try: + comments_service = jid.JID(comments_data["service"]) + except KeyError: + comments_service = None + + if uri: + uri_service, uri_node = self.parseCommentUrl(uri) + if ((comments_node is not None and comments_node!=uri_node) + or (comments_service is not None and comments_service!=uri_service)): + raise ValueError( + f"Incoherence between comments URI ({uri}) and comments_service " + f"({comments_service}) or comments_node ({comments_node})") + comments_data['service'] = comments_service = uri_service + comments_data['node'] = comments_node = uri_node + else: + if not comments_node: + comments_node = self.getCommentsNode(item_id) + comments_data['node'] = comments_node + if comments_service is None: + comments_service = yield self.getCommentsService(client, service) + if comments_service is None: + comments_service = client.jid.userhostJID() + comments_data['service'] = comments_service + + comments_data['uri'] = xmpp_uri.buildXMPPUri( + "pubsub", + path=comments_service.full(), + node=comments_node, ) - try: - comments_service = jid.JID(mb_data["comments_service"]) - except KeyError: - comments_service = yield self.getCommentsService(client, service) - - try: - yield self._p.createNode(client, comments_service, comments_node, options) - except error.StanzaError as e: - if e.condition == "conflict": - log.info( - "node {} already exists on service {}".format( - comments_node, comments_service + try: + yield self._p.createNode(client, comments_service, comments_node, options) + except error.StanzaError as e: + if e.condition == "conflict": + log.info( + "node {} already exists on service {}".format( + comments_node, comments_service + ) ) - ) + else: + raise e else: - raise e - else: - if access == self._p.ACCESS_WHITELIST: - # for whitelist access we need to copy affiliations from parent item - comments_affiliations = yield self._p.getNodeAffiliations( - client, service, node - ) - # …except for "member", that we transform to publisher - # because we wants members to be able to write to comments - for jid_, affiliation in list(comments_affiliations.items()): - if affiliation == "member": - comments_affiliations[jid_] == "publisher" + if access == self._p.ACCESS_WHITELIST: + # for whitelist access we need to copy affiliations from parent item + comments_affiliations = yield self._p.getNodeAffiliations( + client, service, node + ) + # …except for "member", that we transform to publisher + # because we wants members to be able to write to comments + for jid_, affiliation in list(comments_affiliations.items()): + if affiliation == "member": + comments_affiliations[jid_] == "publisher" - yield self._p.setNodeAffiliations( - client, comments_service, comments_node, comments_affiliations - ) - - if comments_service is None: - comments_service = client.jid.userhostJID() - - if "comments" in mb_data: - if not mb_data["comments"]: - raise exceptions.DataError( - "if comments is present, it must not be empty" - ) - if "comments_node" in mb_data or "comments_service" in mb_data: - raise exceptions.DataError( - "You can't use comments_service/comments_node and comments at the " - "same time" - ) - else: - mb_data["comments"] = self._p.getNodeURI(comments_service, comments_node) + yield self._p.setNodeAffiliations( + client, comments_service, comments_node, comments_affiliations + ) def _mbSend(self, service, node, data, profile_key): service = jid.JID(service) if service else None @@ -796,8 +812,8 @@ def _mbGetSerialise(self, data): items, metadata = data - items = [data_format.serialise(item) for item in items] - return items, metadata + metadata['items'] = items + return data_format.serialise(metadata) def _mbGet(self, service="", node="", max_items=10, item_ids=None, extra_dict=None, profile_key=C.PROF_KEY_NONE): @@ -840,7 +856,8 @@ rsm_request=rsm_request, extra=extra, ) - mb_data = yield self._p.transItemsDataD(items_data, self.item2mbdata) + mb_data = yield self._p.transItemsDataD( + items_data, self.item2mbdata) defer.returnValue(mb_data) def parseCommentUrl(self, node_url): @@ -1259,7 +1276,8 @@ client, service, node, max_items, rsm_request=rsm_request, extra=extra ) d.addCallback( - lambda items_data: self._p.transItemsDataD(items_data, self.item2mbdata) + lambda items_data: self._p.transItemsDataD( + items_data, self.item2mbdata) ) d.addCallback(getComments) d.addCallback(lambda items_comments_data: ("", items_comments_data))