# HG changeset patch # User Goffi # Date 1457541180 -3600 # Node ID 2e0e9cf9efb4b90d4b44cddb37be92d78b8aedaa # Parent 2aaac0605ae25042ee10f96f952058c56304bbf3 blog (atom feed): fixed atom handling: - atom generation code moved from backend to Libervia - replaced hardcoded urls by urls based on request path - added xmpp: uri as alternate links - feed id was not unique (it was the node), now it is the quoted xmpp uri - atom:updated was using current time which is wrong, now take the more recent item "updated" value - link elements where missing attributes (e.g.: type) - added correct http(s) links for each items - microblog items (without title) now use an abstract of content as title - use 20 as max_items for atom feeds (may change in the future) - removed bad use of encode diff -r 2aaac0605ae2 -r 2e0e9cf9efb4 src/server/blog.py --- a/src/server/blog.py Sat Mar 05 13:55:24 2016 +0100 +++ b/src/server/blog.py Wed Mar 09 17:33:00 2016 +0100 @@ -23,11 +23,13 @@ from sat.core.log import getLogger log = getLogger(__name__) from sat.tools import common +from sat.tools import xml_tools from dbus.exceptions import DBusException from twisted.internet import defer from twisted.web import server from twisted.web.resource import Resource from twisted.words.protocols.jabber.jid import JID +from twisted.words.xish import domish from jinja2 import Environment, PackageLoader from datetime import datetime import re @@ -38,10 +40,15 @@ from libervia.server.html_tools import sanitizeHtml, convertNewLinesToXHTML from libervia.server.constants import Const as C +NS_ATOM = 'http://www.w3.org/2005/Atom' +ATOM_MAX_ITEMS = 20 PARAMS_TO_GET = (C.STATIC_BLOG_PARAM_TITLE, C.STATIC_BLOG_PARAM_BANNER, C.STATIC_BLOG_PARAM_KEYWORDS, C.STATIC_BLOG_PARAM_DESCRIPTION) re_strip_empty_div = re.compile(r"
|
*?
") # TODO: chech disco features and use max_items when RSM is not available +# FIXME: Deferred are not used +# FIXME: change navigation links handling, this is is fragile +# TODO: refactorise this def getDefaultQueryData(request): @@ -174,22 +181,20 @@ request.extra_dict = {} # will be used for RSM and MAM self.parseURLParams(request) if request.item_id: + # FIXME: this part seems useless # we want a specific item - item_ids = [request.item_id] + # item_ids = [request.item_id] # max_items = 1 max_items = 0 # FIXME else: - item_ids = [] # max_items = int(request.extra_dict['rsm_max']) # FIXME max_items = 0 # TODO: use max_items only when RSM is not available if request.atom: request.extra_dict.update(request.mam_extra) - self.host.bridge.mbGetAtom(pub_jid.userhost(), '', max_items, item_ids, - request.extra_dict, C.SERVICE_PROFILE, - lambda feed: self.renderAtomFeed(feed, request), - lambda failure: self.renderError(failure, request, pub_jid)) + self.getAtom(pub_jid, ATOM_MAX_ITEMS, request.extra_dict, request.extra_comments_dict, request, profile) + elif request.item_id: # we can't merge mam_extra now because we'll use item_ids self.getItemById(pub_jid, request.item_id, request.extra_dict, @@ -377,6 +382,107 @@ max_comments, extra_dict, extra_comments_dict, C.SERVICE_PROFILE, callback=getResult) + def getAtom(self, pub_jid, max_items, extra_dict, extra_comments_dict, request, profile): + """ + + @param pub_jid (jid.JID): publisher JID + @param max_items(int): maximum number of item to get, C.NO_LIMIT for no limit + @param extra_dict (dict): extra configuration for initial items only + @param extra_comments_dict (dict): extra configuration for comments only + @param request: HTTP request + @param profile + """ + def gotItems(data): + # Generate a clean atom feed with uri linking to this blog + # from microblog data + items, metadata= data + feed_elt = domish.Element((NS_ATOM, u'feed')) + title = _(u"{user}'s blog").format(user=profile) + feed_elt.addElement(u'title', content=title) + url_path = request.URLPath() + base_blog_url = u"{0.scheme}://{0.netloc}/blog/{user}".format(url_path, user=profile) + + # atom link + link_feed_elt = feed_elt.addElement('link') + link_feed_elt['href'] = u'{base}/atom.xml'.format(base=base_blog_url) + link_feed_elt['type'] = u'application/atom+xml' + link_feed_elt['rel'] = u'self' + + # blog link + link_blog_elt = feed_elt.addElement('link') + link_blog_elt['rel'] = u'alternate' + link_blog_elt['type'] = u'text/html' + link_blog_elt['href'] = base_blog_url + + # blog link XMPP uri + blog_xmpp_uri = metadata['uri'] + link_blog_elt = feed_elt.addElement('link') + link_blog_elt['rel'] = u'alternate' + link_blog_elt['type'] = u'application/xmpp+xml' + link_blog_elt['href'] = blog_xmpp_uri + + feed_elt.addElement('id', content=urllib.quote(blog_xmpp_uri)) + updated_unix = max([float(item['updated']) for item in items]) + updated_dt = datetime.fromtimestamp(updated_unix) + feed_elt.addElement(u'updated', u'{}Z'.format(updated_dt.isoformat("T"))) + + for item in items: + entry_elt = feed_elt.addElement(u'entry') + + # Title + try: + title = item['title'] + except KeyError: + # for microblog (without title), we use an abstract of content as title + title = u'{}...'.format(u' '.join(item['content'][:70].split())) + entry_elt.addElement(u'title', content=title) + + # HTTP link + http_link_elt = entry_elt.addElement(u'link') + http_link_elt['rel'] = u'alternate' + http_link_elt['type'] = u'text/html' + http_link_elt['href'] = u'{base}/{quoted_id}'.format(base=base_blog_url, quoted_id=urllib.quote(item['id'])) + # XMPP link + xmpp_link_elt = entry_elt.addElement(u'link') + xmpp_link_elt['rel'] = u'alternate' + xmpp_link_elt['type'] = u'application/xmpp+xml' + xmpp_link_elt['href'] = u'{blog_uri};item={item_id}'.format(blog_uri=blog_xmpp_uri, item_id=item['id']) + + # date metadata + entry_elt.addElement(u'id', content=item['atom_id']) + updated = datetime.fromtimestamp(float(item['updated'])) + entry_elt.addElement(u'updated', u'{}Z'.format(updated.isoformat("T"))) + published = datetime.fromtimestamp(float(item['published'])) + entry_elt.addElement(u'published', u'{}Z'.format(published.isoformat("T"))) + + # author metadata + author_elt = entry_elt.addElement(u'author') + author_elt.addElement('name', item.get('author', profile)) + try: + author_elt.addElement('uri', u'xmpp:{}'.format(item['author_jid'])) + except KeyError: + pass + try: + author_elt.addElement('email', item['author_email']) + except KeyError: + pass + + # content + try: + content_xhtml = item['content_xhtml'] + except KeyError: + content_elt = entry_elt.addElement('content', content='content') + content_elt['type'] = 'text' + else: + content_elt = entry_elt.addElement('content') + content_elt['type'] = 'xhtml' + content_elt.addChild(xml_tools.ElementParser()(content_xhtml, namespace=C.NS_XHTML)) + + atom_feed = u'\n{}'.format(feed_elt.toXml()) + self.renderAtomFeed(atom_feed, request), + + self.host.bridge.mbGet(pub_jid.userhost(), '', max_items, [], extra_dict, C.SERVICE_PROFILE, callback=gotItems) + ## rendering def _updateDict(self, value, dict_, key):