From 2cd9af7462465fefbafae74374fb9e0063fa0fa0 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Tue, 17 Mar 2015 14:09:30 +0100 Subject: [PATCH] accounts: Export the jpegPhoto LDAP attribute This adds the functionality to link to the avatar of a certain user. The image is taken from the LDAP database and resized as requested. If no image was found, the client will be redirected to gravatar. --- webapp/__init__.py | 8 +++- webapp/backend/accounts.py | 74 ++++++++++++++++++++++++++++++------- webapp/backend/base.py | 3 +- webapp/handlers.py | 1 + webapp/handlers_accounts.py | 46 +++++++++++++++++++++++ 5 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 webapp/handlers_accounts.py diff --git a/webapp/__init__.py b/webapp/__init__.py index 87cebb2a..22e4e0d8 100644 --- a/webapp/__init__.py +++ b/webapp/__init__.py @@ -255,6 +255,11 @@ class Application(tornado.web.Application): (r"/trunks", TalkTrunksHandler), ] + authentication_handlers + static_handlers) + # accounts.ipfire.org + self.add_handlers(r"accounts(\.dev)?\.ipfire\.org", [ + (r"/avatar/(\w+)\.jpg", AccountsAvatarHandler), + ] + static_handlers) + # admin.ipfire.org self.add_handlers(r"admin(\.dev)?\.ipfire\.org", [ (r"/", AdminIndexHandler), @@ -302,7 +307,8 @@ class Application(tornado.web.Application): if not configfile: raise RuntimeException("Could not find configuration file") - self.__backend = backend.Backend(configfile=configfile) + self.__backend = backend.Backend(configfile=configfile, + debug=self.settings.get("debug", False)) return self.__backend diff --git a/webapp/backend/accounts.py b/webapp/backend/accounts.py index d67fc617..e3b70f55 100644 --- a/webapp/backend/accounts.py +++ b/webapp/backend/accounts.py @@ -1,6 +1,8 @@ #!/usr/bin/python # encoding: utf-8 +import PIL +import StringIO import hashlib import ldap import logging @@ -236,20 +238,8 @@ class Account(Object): if mail.startswith("%s@ipfire.org" % name): return mail - raise Exception, "Cannot figure out email address" - - def gravatar_icon(self, size=128): - try: - gravatar_email = self.email.lower() - except: - gravatar_email = "nobody@ipfire.org" - - # construct the url - gravatar_url = "http://www.gravatar.com/avatar/" + \ - hashlib.md5(gravatar_email).hexdigest() + "?" - gravatar_url += urllib.urlencode({'d': "mm", 's': str(size)}) - - return gravatar_url + # If everything else fails, we will go with the UID + return "%s@ipfire.org" % self.uid @property def sip_id(self): @@ -286,6 +276,62 @@ class Account(Object): def telephone_numbers(self): return self.attributes.get("telephoneNumber") + def avatar_url(self, size=None): + if self.backend.debug: + hostname = "accounts.dev.ipfire.org" + else: + hostname = "accounts.ipfire.org" + + url = "http://%s/avatar/%s.jpg" % (hostname, self.uid) + + if size: + url += "?size=%s" % size + + return url + + gravatar_icon = avatar_url + + def get_avatar(self, size=None): + avatar = self._get_first_attribute("jpegPhoto") + if not avatar: + return + + if not size: + return avatar + + return self._resize_avatar(avatar, size) + + def _resize_avatar(self, image, size): + image = StringIO.StringIO(image) + image = PIL.Image.open(image) + + # Resize the image to the desired resolution + image.thumbnail((size, size), PIL.Image.ANTIALIAS) + + f = StringIO.StringIO() + + # If writing out the image does not work with optimization, + # we try to write it out without any optimization. + try: + image.save(f, "JPEG", optimize=True) + except: + image.save(f, "JPEG") + + return f.getvalue() + + def get_gravatar_url(self, size=128): + try: + gravatar_email = self.email.lower() + except: + gravatar_email = "nobody@ipfire.org" + + # construct the url + gravatar_url = "http://www.gravatar.com/avatar/" + \ + hashlib.md5(gravatar_email).hexdigest() + "?" + gravatar_url += urllib.urlencode({'d': "mm", 's': str(size)}) + + return gravatar_url + if __name__ == "__main__": a = Accounts() diff --git a/webapp/backend/base.py b/webapp/backend/base.py index 1878e836..6cdb5a45 100644 --- a/webapp/backend/base.py +++ b/webapp/backend/base.py @@ -21,9 +21,10 @@ import tracker import wishlist class Backend(object): - def __init__(self, configfile): + def __init__(self, configfile, debug=False): # Read configuration file. self.config = self.read_config(configfile) + self.debug = debug # Setup database. self.setup_database() diff --git a/webapp/handlers.py b/webapp/handlers.py index 7d662dd8..8a082b0f 100644 --- a/webapp/handlers.py +++ b/webapp/handlers.py @@ -15,6 +15,7 @@ import tornado.web import backend +from handlers_accounts import * from handlers_admin import * from handlers_base import * from handlers_boot import * diff --git a/webapp/handlers_accounts.py b/webapp/handlers_accounts.py new file mode 100644 index 00000000..bc419fdd --- /dev/null +++ b/webapp/handlers_accounts.py @@ -0,0 +1,46 @@ +#!/usr/bin/python + +import logging +import tornado.web + +from handlers_base import * + +class AccountsAvatarHandler(BaseHandler): + def get(self, who): + # Get the desired size of the avatar file + size = self.get_argument("size", 0) + + try: + size = int(size) + except (TypeError, ValueError): + size = None + + # Cache handle + cache_handle = "accounts-avatar-%s-%s" % (who, size or 0) + avatar = self.memcached.get(cache_handle) + + if not avatar: + logging.debug("Querying for avatar of %s" % who) + + account = self.backend.accounts.get_by_uid(who) + if not account: + raise tornado.web.HTTPError(404) + + avatar = account.get_avatar(size) + + # Save the avatar to cache for 6 hours + if avatar: + self.memcached.set(cache_handle, avatar, 6 * 3600) + + # Otherwise redirect to gravatar + else: + avatar = account.get_gravatar_url(size) + + if avatar.startswith("http://"): + return self.redirect(avatar) + + self.set_header("Cache-Control", "public,max-age=300") + self.set_header("Content-Disposition", "inline; filename=\"%s.jpg\"" % who) + self.set_header("Content-Type", "image/jpeg") + + self.finish(avatar) -- 2.47.3