changeset 483:0bbbef1d53a8

server side (blog): use user's avatar a the blog's favicon + small refactorization
author souliane <souliane@mailoo.org>
date Tue, 17 Jun 2014 16:21:42 +0200
parents 437eefa53a01
children ae86b32b959c
files src/browser/libervia_main.py src/browser/sat_browser/constants.py src/common/constants.py src/server/blog.py src/server/constants.py
diffstat 5 files changed, 85 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/browser/libervia_main.py	Sun Jun 15 18:16:24 2014 +0200
+++ b/src/browser/libervia_main.py	Tue Jun 17 16:21:42 2014 +0200
@@ -807,8 +807,7 @@
 
     def _entityDataUpdatedCb(self, entity_jid_s, key, value):
         if key == "avatar":
-            avatar = '/avatars/%s' % value
-
+            avatar = '/' + C.AVATARS_DIR + value
             self.avatars_cache[entity_jid_s] = avatar
             self.contact_panel.updateAvatar(entity_jid_s, avatar)
 
--- a/src/browser/sat_browser/constants.py	Sun Jun 15 18:16:24 2014 +0200
+++ b/src/browser/sat_browser/constants.py	Tue Jun 17 16:21:42 2014 +0200
@@ -32,6 +32,5 @@
     #     - list them as a couple (category, name)
     CACHED_PARAMS = [(C.COMPOSITION_KEY, C.ENABLE_UNIBOX_PARAM)]
 
-    # Empty and default avatars
+    # Empty avatar
     EMPTY_AVATAR = "/media/misc/empty_avatar"
-    DEFAULT_AVATAR = "/media/misc/default_avatar.png"
--- a/src/common/constants.py	Sun Jun 15 18:16:24 2014 +0200
+++ b/src/common/constants.py	Tue Jun 17 16:21:42 2014 +0200
@@ -45,3 +45,9 @@
     UPLOAD_OK = 'UPLOAD OK'
     UPLOAD_KO = 'UPLOAD KO'
     UNKNOWN_ERROR = 'UNMANAGED FAULT STRING (%s)'
+
+    # PATHS
+    AVATARS_DIR = "avatars/"
+
+    # Default avatar
+    DEFAULT_AVATAR = "/media/misc/default_avatar.png"
--- a/src/server/blog.py	Sun Jun 15 18:16:24 2014 +0200
+++ b/src/server/blog.py	Tue Jun 17 16:21:42 2014 +0200
@@ -19,6 +19,8 @@
 
 from sat.core.i18n import _
 from sat_frontends.tools.strings import addURLToText
+from sat.core.log import getLogger
+log = getLogger(__name__)
 
 from twisted.internet import defer
 from twisted.web import server
@@ -27,6 +29,7 @@
 from datetime import datetime
 import uuid
 import re
+import os
 
 from libervia.server.html_tools import sanitizeHtml
 from libervia.server.constants import Const as C
@@ -50,6 +53,62 @@
     def __init__(self, host):
         self.host = host
         Resource.__init__(self)
+        self.host.bridge.register('entityDataUpdated', self.entityDataUpdatedCb)
+        self.host.bridge.register('actionResult', self.actionResultCb)  # FIXME: actionResult is to be removed
+        self.waiting_deferreds = {}
+
+    def entityDataUpdatedCb(self, entity_jid_s, key, value, dummy):
+        """Retrieve the avatar we've been waiting for and fires the callback
+        for self.getAvatar to return.
+
+        @param entity_jid_s (str): JID of the contact
+        @param key (str): entity data key
+        @param value (str): entity data value
+        @param dummy (str): that would be C.SERVICE_PROFILE
+        """
+        if key != 'avatar':
+            return
+        try:
+            avatar = (C.AVATARS_DIR + value)
+            self.waiting_deferreds[entity_jid_s][1].callback(avatar)
+            del self.waiting_deferreds[entity_jid_s]
+        except KeyError:
+            log.error(_("Avatar retrieved but key not found in the waiting list for entity %s" % entity_jid_s))
+
+    def actionResultCb(self, answer_type, action_id, data, dummy):
+        """Fires the callback for self.getAvatar to return
+
+        @param answer_type (str): 'SUPPRESS' or another value that we would ignore
+        @param action_id (str): the request ID
+        @param data (dict): ignored
+        @param dummy (str): that would be C.SERVICE_PROFILE
+        """
+        # FIXME: actionResult is to be removed. For now we use it to get notified
+        # when the requested vCard hasn't been found. Replace with the new system.
+        if answer_type != 'SUPPRESS':
+            return
+        try:
+            entity_jid_s = [key for (key, value) in self.waiting_deferreds.items() if value[0] == action_id][0]
+        except IndexError:
+            log.error(_("Key not found in the waiting list for request ID %s" % action_id))
+            return
+        self.waiting_deferreds[entity_jid_s][1].callback(C.DEFAULT_AVATAR)
+        del self.waiting_deferreds[entity_jid_s]
+
+    def getAvatar(self, profile):
+        """Get the avatar of the given profile
+
+        @param profile (str):
+        @return: deferred avatar path, relative to the server's root
+        """
+        jid_s = profile + '@' + self.host.bridge.getNewAccountDomain()
+        data = self.host.bridge.getEntityData(jid_s, ['avatar'], C.SERVICE_PROFILE)
+        if 'avatar' in data:
+            return defer.succeed(C.AVATARS_DIR + data['avatar'])
+        # FIXME: request_id is no more need 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:
@@ -100,43 +159,44 @@
         @param profile
         """
         d_list = []
-        style = {}
+        options = {}
 
         def getCallback(param_name):
             d = defer.Deferred()
-            d.addCallback(lambda value: style.update({param_name: value}))
+            d.addCallback(lambda value: options.update({param_name: value}))
             d_list.append(d)
             return d.callback
 
         eb = lambda failure: self.render_error_blog(failure, request, profile)
 
+        self.getAvatar(profile).addCallbacks(getCallback('avatar'), eb)
         for param_name in (C.STATIC_BLOG_PARAM_TITLE, C.STATIC_BLOG_PARAM_BANNER, C.STATIC_BLOG_PARAM_KEYWORDS, C.STATIC_BLOG_PARAM_DESCRIPTION):
             self.host.bridge.asyncGetParamA(param_name, C.STATIC_BLOG_KEY, 'value', C.SERVER_SECURITY_LIMIT, profile, callback=getCallback(param_name), errback=eb)
 
-        cb = lambda dummy: self.__render_html_blog(mblog_data, style, request, profile)
+        cb = lambda dummy: self.__render_html_blog(mblog_data, options, request, profile)
         defer.DeferredList(d_list).addCallback(cb)
 
-    def __render_html_blog(self, mblog_data, style, request, profile):
+    def __render_html_blog(self, mblog_data, options, request, profile):
         """Actually render the static blog. If mblog_data is a list of dict, we are missing
         the comments items so we just display the main items. If mblog_data is a list of couple,
         each couple is associating a main item data with the list of its comments, so we render all.
         @param mblog_data: list of microblog data or list of couple (microblog data, list of microblog data)
-        @param style: dict defining the blog's rendering parameters
+        @param options: dict defining the blog's parameters
         @param request: the HTTP request
         @profile
         """
-        if not isinstance(style, dict):
-            style = {}
+        if not isinstance(options, dict):
+            options = {}
         user = sanitizeHtml(profile).encode('utf-8')
         root_url = '../' * len(request.postpath)
         base_url = root_url + 'blog/' + user
 
-        def getFromData(key):
-            return sanitizeHtml(style[key]).encode('utf-8') if key in style else ''
+        def getOption(key):
+            return sanitizeHtml(options[key]).encode('utf-8') if key in options else ''
 
-        def getImageFromData(key, alt):
+        def getImageOption(key, alt):
             """regexp from http://answers.oreilly.com/topic/280-how-to-validate-urls-with-regular-expressions/"""
-            url = style[key].encode('utf-8') if key in style else ''
+            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)$"
             return "<img src='%(url)s' alt='%(alt)s'/>" % {'alt': alt, 'url': url} if re.match(regexp, url) else alt
 
@@ -148,7 +208,7 @@
                 <meta name="description" content="%(description)s">
                 <link rel="alternate" type="application/atom+xml" href="%(base)s/atom.xml"/>
                 <link rel="stylesheet" type="text/css" href="%(root)scss/blog.css" />
-                <link rel="icon" type="image/png" href="%(root)ssat_logo_16.png">
+                <link rel="icon" type="image/png" href="%(favicon)s">
                 <title>%(title)s</title>
             </head>
             <body>
@@ -156,10 +216,11 @@
             """ % {'base': base_url,
                    'root': root_url,
                    'user': user,
-                   'keywords': getFromData(C.STATIC_BLOG_PARAM_KEYWORDS),
-                   'description': getFromData(C.STATIC_BLOG_PARAM_DESCRIPTION),
-                   'title': getFromData(C.STATIC_BLOG_PARAM_TITLE) or "%s's microblog" % user,
-                   'banner_elt': getImageFromData(C.STATIC_BLOG_PARAM_BANNER, 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,
+                   'favicon': os.path.normpath(root_url + getOption('avatar')),
+                   'banner_elt': getImageOption(C.STATIC_BLOG_PARAM_BANNER, getOption(C.STATIC_BLOG_PARAM_TITLE) or user)})
         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('published', 0))))
         for entry in mblog_data:
--- a/src/server/constants.py	Sun Jun 15 18:16:24 2014 +0200
+++ b/src/server/constants.py	Tue Jun 17 16:21:42 2014 +0200
@@ -30,7 +30,6 @@
     HTML_DIR = "html/"
     SERVER_CSS_DIR = "server_css/"
     MEDIA_DIR = "media/"
-    AVATARS_DIR = "avatars/"
     CARDS_DIR = "games/cards/tarot"
 
     ERRNUM_BRIDGE_ERRBACK = 0  # FIXME