diff sat/plugins/plugin_xep_0054.py @ 2624:56f94936df1e

code style reformatting using black
author Goffi <goffi@goffi.org>
date Wed, 27 Jun 2018 20:14:46 +0200
parents 395a3d1c2888
children 378188abe941
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0054.py	Wed Jun 27 07:51:29 2018 +0200
+++ b/sat/plugins/plugin_xep_0054.py	Wed Jun 27 20:14:46 2018 +0200
@@ -21,6 +21,7 @@
 from sat.core.i18n import _
 from sat.core.constants import Const as C
 from sat.core.log import getLogger
+
 log = getLogger(__name__)
 from twisted.internet import threads, defer
 from twisted.words.protocols.jabber import jid, error
@@ -36,10 +37,13 @@
 from sat.core import exceptions
 from sat.memory import persistent
 import mimetypes
+
 try:
     from PIL import Image
 except:
-    raise exceptions.MissingModule(u"Missing module pillow, please download/install it from https://python-pillow.github.io")
+    raise exceptions.MissingModule(
+        u"Missing module pillow, please download/install it from https://python-pillow.github.io"
+    )
 from cStringIO import StringIO
 
 try:
@@ -48,17 +52,17 @@
     from wokkel.subprotocols import XMPPHandler
 
 AVATAR_PATH = "avatars"
-AVATAR_DIM = (64, 64)  # FIXME: dim are not adapted to modern resolutions !
+AVATAR_DIM = (64, 64)  #  FIXME: dim are not adapted to modern resolutions !
 
 IQ_GET = '/iq[@type="get"]'
-NS_VCARD = 'vcard-temp'
+NS_VCARD = "vcard-temp"
 VCARD_REQUEST = IQ_GET + '/vCard[@xmlns="' + NS_VCARD + '"]'  # TODO: manage requests
 
-PRESENCE = '/presence'
-NS_VCARD_UPDATE = 'vcard-temp:x:update'
+PRESENCE = "/presence"
+NS_VCARD_UPDATE = "vcard-temp:x:update"
 VCARD_UPDATE = PRESENCE + '/x[@xmlns="' + NS_VCARD_UPDATE + '"]'
 
-CACHED_DATA = {'avatar', 'nick'}
+CACHED_DATA = {"avatar", "nick"}
 MAX_AGE = 60 * 60 * 24 * 365
 
 PLUGIN_INFO = {
@@ -70,20 +74,34 @@
     C.PI_RECOMMENDATIONS: ["XEP-0045"],
     C.PI_MAIN: "XEP_0054",
     C.PI_HANDLER: "yes",
-    C.PI_DESCRIPTION: _("""Implementation of vcard-temp""")
+    C.PI_DESCRIPTION: _("""Implementation of vcard-temp"""),
 }
 
 
 class XEP_0054(object):
-    #TODO: - check that nickname is ok
+    # TODO: - check that nickname is ok
     #      - refactor the code/better use of Wokkel
     #      - get missing values
 
     def __init__(self, host):
         log.info(_(u"Plugin XEP_0054 initialization"))
         self.host = host
-        host.bridge.addMethod(u"avatarGet", u".plugin", in_sign=u'sbbs', out_sign=u's', method=self._getAvatar, async=True)
-        host.bridge.addMethod(u"avatarSet", u".plugin", in_sign=u'ss', out_sign=u'', method=self._setAvatar, async=True)
+        host.bridge.addMethod(
+            u"avatarGet",
+            u".plugin",
+            in_sign=u"sbbs",
+            out_sign=u"s",
+            method=self._getAvatar,
+            async=True,
+        )
+        host.bridge.addMethod(
+            u"avatarSet",
+            u".plugin",
+            in_sign=u"ss",
+            out_sign=u"",
+            method=self._setAvatar,
+            async=True,
+        )
         host.trigger.add(u"presence_available", self.presenceAvailableTrigger)
         host.memory.setSignalOnUpdate(u"avatar")
         host.memory.setSignalOnUpdate(u"nick")
@@ -98,7 +116,7 @@
         @return (bool): True if the bare jid of the entity is a room jid
         """
         try:
-            muc_plg = self.host.plugins['XEP-0045']
+            muc_plg = self.host.plugins["XEP-0045"]
         except KeyError:
             return False
 
@@ -123,12 +141,12 @@
     def presenceAvailableTrigger(self, presence_elt, client):
         if client.jid.userhost() in client._cache_0054:
             try:
-                avatar_hash = client._cache_0054[client.jid.userhost()]['avatar']
+                avatar_hash = client._cache_0054[client.jid.userhost()]["avatar"]
             except KeyError:
                 log.info(u"No avatar in cache for {}".format(client.jid.userhost()))
                 return True
-            x_elt = domish.Element((NS_VCARD_UPDATE, 'x'))
-            x_elt.addElement('photo', content=avatar_hash)
+            x_elt = domish.Element((NS_VCARD_UPDATE, "x"))
+            x_elt.addElement("photo", content=avatar_hash)
             presence_elt.addChild(x_elt)
         return True
 
@@ -139,7 +157,7 @@
         self._fillCachedValues(client.profile)
 
     def _fillCachedValues(self, profile):
-        #FIXME: this may need to be reworked
+        # FIXME: this may need to be reworked
         #       the current naive approach keeps a map between all jids
         #       in persistent cache, then put avatar hashs in memory.
         #       Hashes should be shared between profiles (or not ? what
@@ -153,9 +171,15 @@
                 try:
                     value = data[name]
                     if value is None:
-                        log.error(u"{name} value for {jid_} is None, ignoring".format(name=name, jid_=jid_))
+                        log.error(
+                            u"{name} value for {jid_} is None, ignoring".format(
+                                name=name, jid_=jid_
+                            )
+                        )
                         continue
-                    self.host.memory.updateEntityData(jid_, name, data[name], silent=True, profile_key=profile)
+                    self.host.memory.updateEntityData(
+                        jid_, name, data[name], silent=True, profile_key=profile
+                    )
                 except KeyError:
                     pass
 
@@ -184,7 +208,9 @@
                 else:
                     client._cache_0054.force(jid_s)
         else:
-            self.host.memory.updateEntityData(jid_, name, value, profile_key=client.profile)
+            self.host.memory.updateEntityData(
+                jid_, name, value, profile_key=client.profile
+            )
             if name in CACHED_DATA:
                 client._cache_0054.setdefault(jid_s, {})[name] = value
                 client._cache_0054.force(jid_s)
@@ -206,7 +232,7 @@
         """Parse a <PHOTO> photo_elt and save the picture"""
         # XXX: this method is launched in a separate thread
         try:
-            mime_type = unicode(photo_elt.elements(NS_VCARD, 'TYPE').next())
+            mime_type = unicode(photo_elt.elements(NS_VCARD, "TYPE").next())
         except StopIteration:
             log.warning(u"no MIME type found, assuming image/png")
             mime_type = u"image/png"
@@ -220,35 +246,41 @@
                     mime_type = "image/png"
                 else:
                     # TODO: handle other image formats (svg?)
-                    log.warning(u"following avatar image format is not handled: {type} [{jid}]".format(
-                        type=mime_type, jid=entity_jid.full()))
+                    log.warning(
+                        u"following avatar image format is not handled: {type} [{jid}]".format(
+                            type=mime_type, jid=entity_jid.full()
+                        )
+                    )
                     raise Failure(exceptions.DataError())
 
             ext = mimetypes.guess_extension(mime_type, strict=False)
             assert ext is not None
-            if ext == u'.jpe':
-                ext = u'.jpg'
-            log.debug(u'photo of type {type} with extension {ext} found [{jid}]'.format(
-                    type=mime_type, ext=ext, jid=entity_jid.full()))
+            if ext == u".jpe":
+                ext = u".jpg"
+            log.debug(
+                u"photo of type {type} with extension {ext} found [{jid}]".format(
+                    type=mime_type, ext=ext, jid=entity_jid.full()
+                )
+            )
         try:
-            buf = str(photo_elt.elements(NS_VCARD, 'BINVAL').next())
+            buf = str(photo_elt.elements(NS_VCARD, "BINVAL").next())
         except StopIteration:
             log.warning(u"BINVAL element not found")
             raise Failure(exceptions.NotFound())
         if not buf:
             log.warning(u"empty avatar for {jid}".format(jid=entity_jid.full()))
             raise Failure(exceptions.NotFound())
-        log.debug(_(u'Decoding binary'))
+        log.debug(_(u"Decoding binary"))
         decoded = b64decode(buf)
         del buf
         image_hash = sha1(decoded).hexdigest()
         with client.cache.cacheData(
-            PLUGIN_INFO['import_name'],
+            PLUGIN_INFO["import_name"],
             image_hash,
             mime_type,
             # we keep in cache for 1 year
-            MAX_AGE
-            ) as f:
+            MAX_AGE,
+        ) as f:
             f.write(decoded)
         return image_hash
 
@@ -259,39 +291,44 @@
         vcard_dict = {}
 
         for elem in vcard.elements():
-            if elem.name == 'FN':
-                vcard_dict['fullname'] = unicode(elem)
-            elif elem.name == 'NICKNAME':
-                vcard_dict['nick'] = unicode(elem)
-                self.updateCache(client, entity_jid, 'nick', vcard_dict['nick'])
-            elif elem.name == 'URL':
-                vcard_dict['website'] = unicode(elem)
-            elif elem.name == 'EMAIL':
-                vcard_dict['email'] = unicode(elem)
-            elif elem.name == 'BDAY':
-                vcard_dict['birthday'] = unicode(elem)
-            elif elem.name == 'PHOTO':
+            if elem.name == "FN":
+                vcard_dict["fullname"] = unicode(elem)
+            elif elem.name == "NICKNAME":
+                vcard_dict["nick"] = unicode(elem)
+                self.updateCache(client, entity_jid, "nick", vcard_dict["nick"])
+            elif elem.name == "URL":
+                vcard_dict["website"] = unicode(elem)
+            elif elem.name == "EMAIL":
+                vcard_dict["email"] = unicode(elem)
+            elif elem.name == "BDAY":
+                vcard_dict["birthday"] = unicode(elem)
+            elif elem.name == "PHOTO":
                 # TODO: handle EXTVAL
                 try:
                     avatar_hash = yield threads.deferToThread(
-                        self.savePhoto, client, elem, entity_jid)
+                        self.savePhoto, client, elem, entity_jid
+                    )
                 except (exceptions.DataError, exceptions.NotFound) as e:
-                    avatar_hash = ''
-                    vcard_dict['avatar'] = avatar_hash
+                    avatar_hash = ""
+                    vcard_dict["avatar"] = avatar_hash
                 except Exception as e:
                     log.error(u"avatar saving error: {}".format(e))
                     avatar_hash = None
                 else:
-                    vcard_dict['avatar'] = avatar_hash
-                self.updateCache(client, entity_jid, 'avatar', avatar_hash)
+                    vcard_dict["avatar"] = avatar_hash
+                self.updateCache(client, entity_jid, "avatar", avatar_hash)
             else:
-                log.debug(u'FIXME: [{}] VCard tag is not managed yet'.format(elem.name))
+                log.debug(u"FIXME: [{}] VCard tag is not managed yet".format(elem.name))
 
         # if a data in cache doesn't exist anymore, we need to delete it
         # so we check CACHED_DATA no gotten (i.e. not in vcard_dict keys)
         # and we reset them
         for datum in CACHED_DATA.difference(vcard_dict.keys()):
-            log.debug(u"reseting vcard datum [{datum}] for {entity}".format(datum=datum, entity=entity_jid.full()))
+            log.debug(
+                u"reseting vcard datum [{datum}] for {entity}".format(
+                    datum=datum, entity=entity_jid.full()
+                )
+            )
             self.updateCache(client, entity_jid, datum, None)
 
         defer.returnValue(vcard_dict)
@@ -309,11 +346,15 @@
 
     def _vCardEb(self, failure_, to_jid, client):
         """Called when something is wrong with registration"""
-        log.warning(u"Can't get vCard for {jid}: {failure}".format(jid=to_jid.full, failure=failure_))
+        log.warning(
+            u"Can't get vCard for {jid}: {failure}".format(
+                jid=to_jid.full, failure=failure_
+            )
+        )
         self.updateCache(client, to_jid, "avatar", None)
 
     def _getVcardElt(self, iq_elt):
-       return iq_elt.elements(NS_VCARD, "vCard").next()
+        return iq_elt.elements(NS_VCARD, "vCard").next()
 
     def getCardRaw(self, client, entity_jid):
         """get raw vCard XML
@@ -322,10 +363,10 @@
         """
         entity_jid = self.getBareOrFull(client, entity_jid)
         log.debug(u"Asking for {}'s VCard".format(entity_jid.full()))
-        reg_request = client.IQ('get')
+        reg_request = client.IQ("get")
         reg_request["from"] = client.jid.full()
         reg_request["to"] = entity_jid.full()
-        reg_request.addElement('vCard', NS_VCARD)
+        reg_request.addElement("vCard", NS_VCARD)
         d = reg_request.send(entity_jid.full())
         d.addCallback(self._getVcardElt)
         return d
@@ -337,19 +378,24 @@
         @result: id to retrieve the profile
         """
         d = self.getCardRaw(client, entity_jid)
-        d.addCallbacks(self._vCardCb, self._vCardEb, callbackArgs=[entity_jid, client], errbackArgs=[entity_jid, client])
+        d.addCallbacks(
+            self._vCardCb,
+            self._vCardEb,
+            callbackArgs=[entity_jid, client],
+            errbackArgs=[entity_jid, client],
+        )
         return d
 
     def _getCardCb(self, dummy, client, entity):
         try:
-            return client._cache_0054[entity.full()]['avatar']
+            return client._cache_0054[entity.full()]["avatar"]
         except KeyError:
             raise Failure(exceptions.NotFound())
 
     def _getAvatar(self, entity, cache_only, hash_only, profile):
         client = self.host.getClient(profile)
         d = self.getAvatar(client, jid.JID(entity), cache_only, hash_only)
-        d.addErrback(lambda dummy: '')
+        d.addErrback(lambda dummy: "")
 
         return d
 
@@ -370,7 +416,7 @@
 
         try:
             # we first check if we have avatar in cache
-            avatar_hash = client._cache_0054[entity.full()]['avatar']
+            avatar_hash = client._cache_0054[entity.full()]["avatar"]
             if avatar_hash:
                 # avatar is known and exists
                 full_path = client.cache.getFilePath(avatar_hash)
@@ -379,7 +425,7 @@
                     raise KeyError
             else:
                 # avatar has already been checked but it is not set
-                full_path = u''
+                full_path = u""
         except KeyError:
             # avatar is not in cache
             if cache_only:
@@ -406,11 +452,11 @@
         @param entity(jid.JID): entity to get nick from
         @return(unicode, None): nick or None if not found
         """
-        nick = self.getCache(client, entity, u'nick')
+        nick = self.getCache(client, entity, u"nick")
         if nick is not None:
             defer.returnValue(nick)
         yield self.getCard(client, entity)
-        defer.returnValue(self.getCache(client, entity, u'nick'))
+        defer.returnValue(self.getCache(client, entity, u"nick"))
 
     @defer.inlineCallbacks
     def setNick(self, client, nick):
@@ -422,22 +468,22 @@
         try:
             vcard_elt = yield self.getCardRaw(client, jid_)
         except error.StanzaError as e:
-            if e.condition == 'item-not-found':
-                vcard_elt = domish.Element((NS_VCARD, 'vCard'))
+            if e.condition == "item-not-found":
+                vcard_elt = domish.Element((NS_VCARD, "vCard"))
             else:
                 raise e
         try:
-            nickname_elt = next(vcard_elt.elements(NS_VCARD, u'NICKNAME'))
+            nickname_elt = next(vcard_elt.elements(NS_VCARD, u"NICKNAME"))
         except StopIteration:
             pass
         else:
             vcard_elt.children.remove(nickname_elt)
 
-        nickname_elt = vcard_elt.addElement((NS_VCARD, u'NICKNAME'), content=nick)
+        nickname_elt = vcard_elt.addElement((NS_VCARD, u"NICKNAME"), content=nick)
         iq_elt = client.IQ()
         vcard_elt = iq_elt.addChild(vcard_elt)
         yield iq_elt.send()
-        self.updateCache(client, jid_, u'nick', unicode(nick))
+        self.updateCache(client, jid_, u"nick", unicode(nick))
 
     def _buildSetAvatar(self, client, vcard_elt, file_path):
         # XXX: this method is executed in a separate thread
@@ -460,18 +506,15 @@
                     right -= offset
                 img = img.crop((left, upper, right, lower))
         img_buf = StringIO()
-        img.save(img_buf, 'PNG')
+        img.save(img_buf, "PNG")
 
-        photo_elt = vcard_elt.addElement('PHOTO')
-        photo_elt.addElement('TYPE', content='image/png')
-        photo_elt.addElement('BINVAL', content=b64encode(img_buf.getvalue()))
+        photo_elt = vcard_elt.addElement("PHOTO")
+        photo_elt.addElement("TYPE", content="image/png")
+        photo_elt.addElement("BINVAL", content=b64encode(img_buf.getvalue()))
         image_hash = sha1(img_buf.getvalue()).hexdigest()
         with client.cache.cacheData(
-            PLUGIN_INFO['import_name'],
-            image_hash,
-            "image/png",
-            MAX_AGE
-            ) as f:
+            PLUGIN_INFO["import_name"], image_hash, "image/png", MAX_AGE
+        ) as f:
             f.write(img_buf.getvalue())
         return image_hash
 
@@ -489,14 +532,14 @@
             # we first check if a vcard already exists, to keep data
             vcard_elt = yield self.getCardRaw(client, client.jid.userhostJID())
         except error.StanzaError as e:
-            if e.condition == 'item-not-found':
-                vcard_elt = domish.Element((NS_VCARD, 'vCard'))
+            if e.condition == "item-not-found":
+                vcard_elt = domish.Element((NS_VCARD, "vCard"))
             else:
                 raise e
         else:
             # the vcard exists, we need to remove PHOTO element as we'll make a new one
             try:
-                photo_elt = next(vcard_elt.elements(NS_VCARD, u'PHOTO'))
+                photo_elt = next(vcard_elt.elements(NS_VCARD, u"PHOTO"))
             except StopIteration:
                 pass
             else:
@@ -504,12 +547,14 @@
 
         iq_elt = client.IQ()
         iq_elt.addChild(vcard_elt)
-        image_hash = yield threads.deferToThread(self._buildSetAvatar, client, vcard_elt, file_path)
+        image_hash = yield threads.deferToThread(
+            self._buildSetAvatar, client, vcard_elt, file_path
+        )
         # image is now at the right size/format
 
-        self.updateCache(client, client.jid.userhostJID(), 'avatar', image_hash)
+        self.updateCache(client, client.jid.userhostJID(), "avatar", image_hash)
         yield iq_elt.send()
-        client.presence.available() # FIXME: should send the current presence, not always "available" !
+        client.presence.available()  # FIXME: should send the current presence, not always "available" !
 
 
 class XEP_0054_handler(XMPPHandler):
@@ -522,21 +567,24 @@
     def connectionInitialized(self):
         self.xmlstream.addObserver(VCARD_UPDATE, self.update)
 
-    def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
+    def getDiscoInfo(self, requestor, target, nodeIdentifier=""):
         return [disco.DiscoFeature(NS_VCARD)]
 
-    def getDiscoItems(self, requestor, target, nodeIdentifier=''):
+    def getDiscoItems(self, requestor, target, nodeIdentifier=""):
         return []
 
     def _checkAvatarHash(self, dummy, client, entity, given_hash):
         """check that hash in cash (i.e. computed hash) is the same as given one"""
         # XXX: if they differ, the avater will be requested on each connection
         # TODO: try to avoid re-requesting avatar in this case
-        computed_hash = self.plugin_parent.getCache(client, entity, 'avatar')
+        computed_hash = self.plugin_parent.getCache(client, entity, "avatar")
         if computed_hash != given_hash:
-            log.warning(u"computed hash differs from given hash for {entity}:\n"
+            log.warning(
+                u"computed hash differs from given hash for {entity}:\n"
                 "computed: {computed}\ngiven: {given}".format(
-                entity=entity, computed=computed_hash, given=given_hash))
+                    entity=entity, computed=computed_hash, given=given_hash
+                )
+            )
 
     def update(self, presence):
         """Called on <presence/> stanza with vcard data
@@ -545,22 +593,22 @@
         @param presend(domish.Element): <presence/> stanza
         """
         client = self.parent
-        entity_jid = self.plugin_parent.getBareOrFull(client, jid.JID(presence['from']))
-        #FIXME: wokkel's data_form should be used here
+        entity_jid = self.plugin_parent.getBareOrFull(client, jid.JID(presence["from"]))
+        # FIXME: wokkel's data_form should be used here
         try:
-            x_elt = presence.elements(NS_VCARD_UPDATE, 'x').next()
+            x_elt = presence.elements(NS_VCARD_UPDATE, "x").next()
         except StopIteration:
             return
 
         try:
-            photo_elt = x_elt.elements(NS_VCARD_UPDATE, 'photo').next()
+            photo_elt = x_elt.elements(NS_VCARD_UPDATE, "photo").next()
         except StopIteration:
             return
 
         hash_ = unicode(photo_elt).strip()
         if hash_ == C.HASH_SHA1_EMPTY:
-            hash_ = u''
-        old_avatar = self.plugin_parent.getCache(client, entity_jid, 'avatar')
+            hash_ = u""
+        old_avatar = self.plugin_parent.getCache(client, entity_jid, "avatar")
 
         if old_avatar == hash_:
             # no change, we can return...
@@ -568,7 +616,11 @@
                 # ...but we double check that avatar is in cache
                 file_path = client.cache.getFilePath(hash_)
                 if file_path is None:
-                    log.error(u"Avatar for [{}] should be in cache but it is not! We get it".format(entity_jid.full()))
+                    log.error(
+                        u"Avatar for [{}] should be in cache but it is not! We get it".format(
+                            entity_jid.full()
+                        )
+                    )
                     self.plugin_parent.getCard(client, entity_jid)
             else:
                 log.debug(u"avatar for {} already in cache".format(entity_jid.full()))
@@ -578,14 +630,20 @@
             # the avatar has been removed
             # XXX: we use empty string instead of None to indicate that we took avatar
             #      but it is empty on purpose
-            self.plugin_parent.updateCache(client, entity_jid, 'avatar', '')
+            self.plugin_parent.updateCache(client, entity_jid, "avatar", "")
             return
 
         file_path = client.cache.getFilePath(hash_)
         if file_path is not None:
-            log.debug(u"New avatar found for [{}], it's already in cache, we use it".format(entity_jid.full()))
-            self.plugin_parent.updateCache(client, entity_jid, 'avatar', hash_)
+            log.debug(
+                u"New avatar found for [{}], it's already in cache, we use it".format(
+                    entity_jid.full()
+                )
+            )
+            self.plugin_parent.updateCache(client, entity_jid, "avatar", hash_)
         else:
-            log.debug(u'New avatar found for [{}], requesting vcard'.format(entity_jid.full()))
+            log.debug(
+                u"New avatar found for [{}], requesting vcard".format(entity_jid.full())
+            )
             d = self.plugin_parent.getCard(client, entity_jid)
             d.addCallback(self._checkAvatarHash, client, entity_jid, hash_)