Mercurial > libervia-web
diff src/server/blog.py @ 712:bf562fb9c273
server_side: use Jinja2 template engine for static blog
author | souliane <souliane@mailoo.org> |
---|---|
date | Mon, 13 Jul 2015 18:11:38 +0200 |
parents | e9a6cbb924e6 |
children | 29b84af2ff7b |
line wrap: on
line diff
--- a/src/server/blog.py Mon Jul 13 13:33:01 2015 +0200 +++ b/src/server/blog.py Mon Jul 13 18:11:38 2015 +0200 @@ -3,6 +3,7 @@ # Libervia: a Salut à Toi frontend # Copyright (C) 2011, 2012, 2013, 2014, 2015 Jérôme Poisson <goffi@goffi.org> +# Copyright (C) 2013, 2014, 2015 Adrien Cossa <souliane@mailoo.org> # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -20,15 +21,16 @@ from sat.core.i18n import _, D_ from sat_frontends.tools.strings import addURLToText from sat.core.log import getLogger +from django.conf.urls import url log = getLogger(__name__) 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 jinja2 import Environment, PackageLoader from datetime import datetime from sys import path -import importlib import uuid import re import os @@ -45,22 +47,22 @@ self.host = host # add Libervia's themes directory to the python path - path.append(os.path.dirname(self.host.themes_dir)) + path.append(os.path.dirname(os.path.normpath(self.host.themes_dir))) + themes = os.path.basename(os.path.normpath(self.host.themes_dir)) + self.env = Environment(loader=PackageLoader(themes, self.THEME)) def useTemplate(self, request, tpl, data=None): root_url = '../' * len(request.postpath) theme_url = os.path.join(root_url, 'themes', self.THEME) - # import the theme module - themes = os.path.basename(os.path.dirname(os.path.dirname(self.host.themes_dir))) - theme = importlib.import_module("%s.templates" % self.THEME, themes) - data_ = {'theme': theme_url, - 'images': os.path.join(theme_url, 'images'), + data_ = {'images': os.path.join(theme_url, 'images'), 'styles': os.path.join(theme_url, 'styles'), } if data: data_.update(data) - return getattr(theme, tpl.upper()).encode('utf-8').format(**data_) + + template = self.env.get_template('%s.html' % tpl) + return template.render(**data_).encode('utf-8') class MicroBlog(Resource, TemplateProcessor): @@ -126,20 +128,20 @@ jid_s = (profile + '@' + self.host.bridge.getNewAccountDomain()).lower() if jid_s in self.avatars_cache: return defer.succeed(self.avatars_cache[jid_s]) - # FIXME: request_id is no more need when actionResult is removed + # FIXME: request_id is no more needed when actionResult is removed request_id = self.host.bridge.getCard(jid_s, C.SERVICE_PROFILE) self.waiting_deferreds[jid_s] = (request_id, defer.Deferred()) return self.waiting_deferreds[jid_s][1] def render_GET(self, request): if not request.postpath: - return self.useTemplate(request, "error", {'message': "You must indicate a nickname"}) + return self.useTemplate(request, "static_blog_error", {'message': "You must indicate a nickname"}) prof_requested = request.postpath[0] - #TODO: char check: only use alphanumerical chars + some extra(_,-,...) here + #TODO : char check: only use alphanumeric chars + some extra(_,-,...) here prof_found = self.host.bridge.getProfileName(prof_requested) if not prof_found or prof_found == C.SERVICE_PROFILE: - return self.useTemplate(request, "error", {'message': "Invalid nickname"}) + return self.useTemplate(request, "static_blog_error", {'message': "Invalid nickname"}) d = defer.Deferred() JID(self.host.bridge.asyncGetParamA('JabberID', 'Connection', 'value', C.SERVER_SECURITY_LIMIT, prof_found, callback=d.callback, errback=d.errback)) @@ -266,43 +268,48 @@ def getOption(key): return sanitizeHtml(options[key]).encode('utf-8') if key in options else '' - def getImageOption(key, default, alt): + def getImageParams(key, default, alt): """regexp from http://answers.oreilly.com/topic/280-how-to-validate-urls-with-regular-expressions/""" url = options[key].encode('utf-8') if key in options else '' regexp = r"^(https?|ftp)://[a-z0-9-]+(\.[a-z0-9-]+)+(/[\w-]+)*/[\w-]+\.(gif|png|jpg)$" if re.match(regexp, url): url = url - suffix = "<br/>" else: url = default - suffix = "" - return self.useTemplate(request, "banner", {'alt': alt, 'url': url, 'suffix': suffix}) + return BlogImage(url, alt) avatar = os.path.normpath(root_url + getOption('avatar')) title = getOption(C.STATIC_BLOG_PARAM_TITLE) or user data = {'base_url': base_url, - 'user': user, 'keywords': getOption(C.STATIC_BLOG_PARAM_KEYWORDS), 'description': getOption(C.STATIC_BLOG_PARAM_DESCRIPTION), - 'title': getOption(C.STATIC_BLOG_PARAM_TITLE) or "%s's microblog" % user, + 'title': title, 'favicon': avatar, - 'banner_elt': getImageOption(C.STATIC_BLOG_PARAM_BANNER, avatar, title), - 'title_elt': title, + 'banner_img': getImageParams(C.STATIC_BLOG_PARAM_BANNER, avatar, title) } mblog_data, main_rsm = mblog_data mblog_data = [(entry if isinstance(entry, tuple) else (entry, ([], {}))) for entry in mblog_data] - mblog_data = sorted(mblog_data, key=lambda entry: (-float(entry[0].get('updated', 0)))) + mblog_data.sort(key=lambda entry: (-float(entry[0].get('updated', 0)))) - data.update(self.getNavigationLinks(request, mblog_data, main_rsm, base_url)) - request.write(self.useTemplate(request, 'header', data)) + data['navlinks'] = NavigationLinks(request, mblog_data, main_rsm, base_url) + data['messages'] = [BlogMessage(request, base_url, entry, comments[0]) for entry, comments in mblog_data] - BlogMessages(self.host, request, base_url, mblog_data).render() - - request.write(self.useTemplate(request, "footer", data)) + request.write(self.useTemplate(request, 'static_blog', data)) request.finish() - def getNavigationLinks(self, request, mblog_data, rsm_data, base_url): + def render_atom_feed(self, feed, request): + request.write(feed.encode('utf-8')) + request.finish() + + def render_error_blog(self, error, request, profile): + request.write(self.useTemplate(request, "static_blog_error", {'message': "Can't access requested data"})) + request.finish() + + +class NavigationLinks(object): + + def __init__(self, request, mblog_data, rsm_data, base_url): """Build the navigation links. @param mblog_data (dict): the microblogs that are displayed on the page @@ -310,10 +317,9 @@ @param base_url (unicode): the base URL for this user's blog @return: dict """ - data = {} for key in ('later_message', 'later_messages', 'older_message', 'older_messages'): count = int(rsm_data.get('count', 0)) - data[key] = '' # key must exist when using the template + setattr(self, key, '') # key must exist when using the template if count <= 0 or (request.display_single == key.endswith('s')): continue @@ -337,33 +343,64 @@ link = "%(base_url)s?%(post_arg)s=%(item_id)s%(suffix)s" % link_data - link_data = {'link': link, 'class': key, 'text': key.replace('_', ' ')} - data[key] = (self.useTemplate(request, 'nav_link', link_data)).encode('utf-8') + setattr(self, key, BlogLink(link, key, key.replace('_', ' '))) - return data + +class BlogImage(object): - def render_atom_feed(self, feed, request): - request.write(feed.encode('utf-8')) - request.finish() + def __init__(self, url_, alt): + self.url = url_ + self.alt = alt + - def render_error_blog(self, error, request, profile): - request.write(self.useTemplate(request, "error", {'message': "Can't access requested data"})) - request.finish() +class BlogLink(object): + + def __init__(self, url_, style, text): + self.url = url_ + self.style = style + self.text = text -class BlogMessages(TemplateProcessor): +class BlogMessage(object): + + def __init__(self, request, base_url, entry, comments=None): + """ + + @param request: HTTP request + @param base_url (unicode): the base URL + @param entry (dict{unicode:unicode]): microblog entry received from the backend + @param comments (list[dict]): comments + """ + timestamp = float(entry.get('published', 0)) + is_comment = entry['type'] == 'comment' + + self.date = datetime.fromtimestamp(timestamp) + self.type = entry['type'] + self.style = 'mblog_comment' if entry['type'] == 'comment' else '' + self.content = self.getText(entry, 'content') - def __init__(self, host, request, base_url, mblog_data): - TemplateProcessor.__init__(self, host) - self.request = request - self.base_url = base_url - self.mblog_data = mblog_data + if is_comment: + self.author = (_("from %s") % entry['author']).encode('utf-8') + else: + self.author = ' ' + self.url = (u"%s/%s" % (base_url, entry['id'])).encode('utf-8') + self.title = self.getText(entry, 'title') + + comments_count = int(entry['comments_count']) + count_text = lambda count: D_('comments') if count > 1 else D_('comment') - def render(self): - for entry, comments_data in self.mblog_data: - comments, comments_rsm = comments_data - comments = sorted(comments, key=lambda entry: (float(entry.get('published', 0)))) - self.render_html(entry, comments) + self.comments_text = "%s %s" % (comments_count, count_text(comments_count)) + + delta = comments_count - len(comments) + if request.display_single and delta > 0: + prev_url = "%s?max=%s" % (self.url, entry['comments_count']) + prev_text = D_("show %(count)d previous %(comments)s") % \ + {'count': delta, 'comments': count_text(delta)} + self.all_comments_link = BlogLink(prev_url, "comments_link", prev_text) + + if comments: + comments.sort(key=lambda entry: float(entry.get('published', 0))) + self.comments = [BlogMessage(request, base_url, comment) for comment in comments] def getText(self, entry, key): if ('%s_xhtml' % key) in entry: @@ -372,51 +409,3 @@ processor = addURLToText if key.startswith('content') else sanitizeHtml return convertNewLinesToXHTML(processor(entry[key])).encode('utf-8') return None - - def render_html(self, entry, comments=None): - """Render one microblog entry. - @param entry: the microblog entry - @param base_url: the base url of the blog - @param request: the HTTP request - """ - timestamp = float(entry.get('published', 0)) - is_comment = entry['type'] == 'comment' - - data = {'date': datetime.fromtimestamp(timestamp), - 'comments_link': '', - 'previous_comments': '', - } - - if is_comment: - author = (_("from %s") % entry['author']).encode('utf-8') - else: - author = ' ' - message_link = (u"%s/%s" % (self.base_url, entry['id'])).encode('utf-8') - - count_text = lambda count: D_('comments') if count > 1 else D_('comment') - - comments_count = int(entry['comments_count']) - delta = comments_count - len(comments) - if self.request.display_single and delta > 0: - data['comments_link'] = ("%s?max=%s" % (message_link, entry['comments_count'])) - data['previous_comments'] = D_("Show %(count)d previous %(comments)s") % \ - {'count': delta, 'comments': count_text(delta)} - - data.update({'comments_count': comments_count, - 'comments_text': count_text(comments_count), - 'message_link': message_link, - 'message_title': self.getText(entry, 'title'), - }) - - data.update({'author': author, - 'extra_style': 'mblog_comment' if entry['type'] == 'comment' else '', - 'content': self.getText(entry, 'content'), - }) - - tpl = "%s%s" % ("" if data.get('message_title', None) else "micro_", "comment" if is_comment else "message") - self.request.write(self.useTemplate(self.request, tpl, data)) - - if comments: - for comment in comments: - self.render_html(comment) -