[Git][gajim/gajim][master] 4 commits: Move rest of UserAvatar into new module

Philipp Hörist gitlab at dev.gajim.org
Fri Jul 6 21:08:16 CEST 2018


Philipp Hörist pushed to branch master at gajim / gajim


Commits:
ccb3c2de by Philipp Hörist at 2018-07-06T19:55:13+02:00
Move rest of UserAvatar into new module

- - - - -
6a363678 by Philipp Hörist at 2018-07-06T20:05:57+02:00
Dont handle all pep events

- - - - -
70661b70 by Philipp Hörist at 2018-07-06T20:12:50+02:00
Rename method to something more appropriate

- - - - -
d45fa13e by Philipp Hörist at 2018-07-06T21:02:06+02:00
Refactor atom into new module and disable it

Gajim lacks a good UI for microblogging

Fixes #9218

- - - - -


10 changed files:

- − gajim/common/atom.py
- gajim/common/connection_handlers_events.py
- gajim/common/const.py
- + gajim/common/modules/atom.py
- gajim/common/modules/pep.py
- gajim/common/modules/user_avatar.py
- gajim/common/modules/user_nickname.py
- gajim/common/pep.py
- gajim/gui_interface.py
- gajim/roster_window.py


Changes:

=====================================
gajim/common/atom.py deleted
=====================================
--- a/gajim/common/atom.py
+++ /dev/null
@@ -1,176 +0,0 @@
-# -*- coding: utf-8 -*-
-## src/common/atom.py
-##
-## Copyright (C) 2006 Jean-Marie Traissard <jim AT lapin.org>
-##                    Tomasz Melcer <liori AT exroot.org>
-## Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
-##
-## This file is part of Gajim.
-##
-## Gajim is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published
-## by the Free Software Foundation; version 3 only.
-##
-## Gajim is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
-##
-
-"""
-Atom (rfc 4287) feed parser, used to read data from atom-over-pubsub transports
-and services. Very simple. Actually implements only atom:entry. Implement more features
-if you need
-"""
-
-# suggestion: rewrite functions that return dates to return standard python time tuples,
-# exteneded to contain timezone
-
-import nbxmpp
-import time
-
-class PersonConstruct(nbxmpp.Node, object):
-    """
-    Not used for now, as we don't need authors/contributors in pubsub.com feeds.
-    They rarely exist there
-    """
-
-    def __init__(self, node):
-        ''' Create person construct from node. '''
-        nbxmpp.Node.__init__(self, node=node)
-
-    def get_name(self):
-        return self.getTagData('name')
-
-    name = property(get_name, None, None,
-            '''Conveys a human-readable name for the person. Should not be None,
-            although some badly generated atom feeds don't put anything here
-            (this is non-standard behavior, still pubsub.com sometimes does that.)''')
-
-    def get_uri(self):
-        return self.getTagData('uri')
-
-    uri = property(get_uri, None, None,
-            '''Conveys an IRI associated with the person. Might be None when not set.''')
-
-    def get_email(self):
-        return self.getTagData('email')
-
-    email = property(get_email, None, None,
-            '''Conveys an e-mail address associated with the person. Might be None when
-            not set.''')
-
-class Entry(nbxmpp.Node, object):
-    def __init__(self, node=None):
-        nbxmpp.Node.__init__(self, 'entry', node=node)
-
-    def __repr__(self):
-        return '<Atom:Entry object of id="%r">' % self.getAttr('id')
-
-class OldEntry(nbxmpp.Node, object):
-    """
-    Parser for feeds from pubsub.com. They use old Atom 0.3 format with their
-    extensions
-    """
-
-    def __init__(self, node=None):
-        ''' Create new Atom 0.3 entry object. '''
-        nbxmpp.Node.__init__(self, 'entry', node=node)
-
-    def __repr__(self):
-        return '<Atom0.3:Entry object of id="%r">' % self.getAttr('id')
-
-    def get_feed_title(self):
-        """
-        Return title of feed, where the entry was created. The result is the feed
-        name concatenated with source-feed title
-        """
-        if self.parent is not None:
-            main_feed = self.parent.getTagData('title')
-        else:
-            main_feed = None
-
-        if self.getTag('feed') is not None:
-            source_feed = self.getTag('feed').getTagData('title')
-        else:
-            source_feed = None
-
-
-        if main_feed is not None and source_feed is not None:
-            return '%s: %s' % (main_feed, source_feed)
-        elif main_feed is not None:
-            return main_feed
-        elif source_feed is not None:
-            return source_feed
-        else:
-            return ''
-
-    feed_title = property(get_feed_title, None, None,
-            ''' Title of feed. It is built from entry''s original feed title and title of feed
-            which delivered this entry. ''')
-
-    def get_feed_link(self):
-        """
-        Get source link
-        """
-        try:
-            return self.getTag('feed').getTags('link', {'rel':'alternate'})[1].getData()
-        except Exception:
-            return None
-
-    feed_link = property(get_feed_link, None, None,
-            ''' Link to main webpage of the feed. ''')
-
-    def get_title(self):
-        """
-        Get an entry's title
-        """
-        return self.getTagData('title')
-
-    title = property(get_title, None, None,
-            ''' Entry's title. ''')
-
-    def get_uri(self):
-        """
-        Get the uri the entry points to (entry's first link element with
-        rel='alternate' or without rel attribute)
-        """
-        for element in self.getTags('link'):
-            if 'rel' in element.attrs and element.attrs['rel']!='alternate': continue
-            try:
-                return element.attrs['href']
-            except AttributeError:
-                pass
-        return None
-
-    uri = property(get_uri, None, None,
-            ''' URI that is pointed by the entry. ''')
-
-    def get_updated(self):
-        """
-        Get the time the entry was updated last time
-
-        This should be standarized, but pubsub.com sends it in human-readable
-        format. We won't try to parse it. (Atom 0.3 uses the word «modified» for
-        that).
-
-        If there's no time given in the entry, we try with <published>
-        and <issued> elements.
-        """
-        for name in ('updated', 'modified', 'published', 'issued'):
-            date = self.getTagData(name)
-            if date is not None: break
-
-        if date is None:
-            # it is not in the standard format
-            return time.asctime()
-
-        return date
-
-    updated = property(get_updated, None, None,
-            ''' Last significant modification time. ''')
-
-    feed_tagline = ''


=====================================
gajim/common/connection_handlers_events.py
=====================================
--- a/gajim/common/connection_handlers_events.py
+++ b/gajim/common/connection_handlers_events.py
@@ -22,7 +22,6 @@
 # pylint: disable=attribute-defined-outside-init
 
 from calendar import timegm
-import datetime
 import hashlib
 import hmac
 import logging
@@ -33,7 +32,6 @@ import OpenSSL.crypto
 import nbxmpp
 from nbxmpp.protocol import NS_CHATSTATES
 
-from gajim.common import atom
 from gajim.common import nec
 from gajim.common import helpers
 from gajim.common import app
@@ -1759,24 +1757,6 @@ class PEPReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
                 self.pep_type = pep.type_
                 return True
 
-        items = self.event_tag.getTag('items')
-        if items:
-            # for each entry in feed (there shouldn't be more than one, but to
-            # be sure...
-            for item in items.getTags('item'):
-                entry = item.getTag('entry', namespace=nbxmpp.NS_ATOM)
-                if entry:
-                    app.nec.push_incoming_event(AtomEntryReceived(None,
-                        conn=self.conn, node=entry))
-
-class AtomEntryReceived(nec.NetworkIncomingEvent):
-    name = 'atom-entry-received'
-    base_network_events = []
-
-    def generate(self):
-        self.atom_entry = atom.OldEntry(node=self.node)
-        return True
-
 class PlainConnectionEvent(nec.NetworkIncomingEvent):
     name = 'plain-connection'
     base_network_events = []


=====================================
gajim/common/const.py
=====================================
--- a/gajim/common/const.py
+++ b/gajim/common/const.py
@@ -152,6 +152,8 @@ class PEPEventType(IntEnum):
     MOOD = 2
     LOCATION = 3
     NICKNAME = 4
+    AVATAR = 5
+    ATOM = 6
 
 
 ACTIVITIES = {


=====================================
gajim/common/modules/atom.py
=====================================
--- /dev/null
+++ b/gajim/common/modules/atom.py
@@ -0,0 +1,226 @@
+# Copyright (C) 2006 Jean-Marie Traissard <jim AT lapin.org>
+#                    Tomasz Melcer <liori AT exroot.org>
+# Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
+#
+# This file is part of Gajim.
+#
+# Gajim is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation; version 3 only.
+#
+# Gajim is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Atom (rfc 4287) feed parser, used to read data from atom-over-pubsub transports
+and services. Very simple. Actually implements only atom:entry.
+Implement more features if you need
+"""
+
+# XEP-0277: Microblogging over XMPP
+
+# Module is disabled for now because Gajim lacks a good UI for that
+# register the module in connection.py with register_module() to activate again
+
+import logging
+import nbxmpp
+import time
+
+from gajim.common.const import PEPEventType
+from gajim.common.exceptions import StanzaMalformed
+from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData
+
+log = logging.getLogger('gajim.c.m.atom')
+
+
+class AtomData(AbstractPEPData):
+
+    type_ = PEPEventType.ATOM
+
+    def __init__(self, atom):
+        self._pep_specific_data = atom
+
+    def get_entry(self):
+        return self._pep_specific_data
+
+
+class Atom(AbstractPEPModule):
+
+    name = 'atom'
+    namespace = 'urn:xmpp:microblog:0'
+    pep_class = AtomData
+    store_publish = False
+    _log = log
+
+    def __init__(self, con):
+        AbstractPEPModule.__init__(self, con, con.name)
+
+        self.handlers = []
+
+    def _extract_info(self, item):
+        entry = item.getTag('entry', namespace=nbxmpp.NS_ATOM)
+        if entry is None:
+            StanzaMalformed('no entry node')
+
+        return OldEntry(node=entry) or None
+
+
+class PersonConstruct(nbxmpp.Node, object):
+    """
+    Not used for now, as we don't need authors/contributors
+    in pubsub.com feeds. They rarely exist there
+    """
+
+    def __init__(self, node):
+        ''' Create person construct from node. '''
+        nbxmpp.Node.__init__(self, node=node)
+
+    def get_name(self):
+        return self.getTagData('name')
+
+    name = property(
+        get_name, None, None,
+        '''Conveys a human-readable name for the person. Should not be None,
+        although some badly generated atom feeds don't put anything here
+        (this is non-standard behavior, still pubsub.com sometimes does that.)''')
+
+    def get_uri(self):
+        return self.getTagData('uri')
+
+    uri = property(
+        get_uri, None, None,
+        '''Conveys an IRI associated with the person.
+        Might be None when not set.''')
+
+    def get_email(self):
+        return self.getTagData('email')
+
+    email = property(
+        get_email, None, None,
+        '''Conveys an e-mail address associated with the person. Might be None when
+        not set.''')
+
+
+class Entry(nbxmpp.Node, object):
+    def __init__(self, node=None):
+        nbxmpp.Node.__init__(self, 'entry', node=node)
+
+    def __repr__(self):
+        return '<Atom:Entry object of id="%r">' % self.getAttr('id')
+
+
+class OldEntry(nbxmpp.Node, object):
+    """
+    Parser for feeds from pubsub.com. They use old Atom 0.3 format with their
+    extensions
+    """
+
+    def __init__(self, node=None):
+        ''' Create new Atom 0.3 entry object. '''
+        nbxmpp.Node.__init__(self, 'entry', node=node)
+
+    def __repr__(self):
+        return '<Atom0.3:Entry object of id="%r">' % self.getAttr('id')
+
+    def get_feed_title(self):
+        """
+        Return title of feed, where the entry was created.
+        The result is the feed name concatenated with source-feed title
+        """
+        if self.parent is not None:
+            main_feed = self.parent.getTagData('title')
+        else:
+            main_feed = None
+
+        if self.getTag('feed') is not None:
+            source_feed = self.getTag('feed').getTagData('title')
+        else:
+            source_feed = None
+
+        if main_feed is not None and source_feed is not None:
+            return '%s: %s' % (main_feed, source_feed)
+        elif main_feed is not None:
+            return main_feed
+        elif source_feed is not None:
+            return source_feed
+        else:
+            return ''
+
+    feed_title = property(
+        get_feed_title, None, None,
+        ''' Title of feed. It is built from entry''s original feed title
+        and title of feed which delivered this entry. ''')
+
+    def get_feed_link(self):
+        """
+        Get source link
+        """
+        try:
+            return self.getTag('feed').getTags('link', {'rel': 'alternate'})[1].getData()
+        except Exception:
+            return None
+
+    feed_link = property(
+        get_feed_link, None, None,
+        ''' Link to main webpage of the feed. ''')
+
+    def get_title(self):
+        """
+        Get an entry's title
+        """
+        return self.getTagData('title')
+
+    title = property(
+        get_title, None, None,
+        ''' Entry's title. ''')
+
+    def get_uri(self):
+        """
+        Get the uri the entry points to (entry's first link element with
+        rel='alternate' or without rel attribute)
+        """
+        for element in self.getTags('link'):
+            if 'rel' in element.attrs and element.attrs['rel'] != 'alternate':
+                continue
+            try:
+                return element.attrs['href']
+            except AttributeError:
+                pass
+        return None
+
+    uri = property(
+        get_uri, None, None,
+        ''' URI that is pointed by the entry. ''')
+
+    def get_updated(self):
+        """
+        Get the time the entry was updated last time
+
+        This should be standarized, but pubsub.com sends it in human-readable
+        format. We won't try to parse it.
+        (Atom 0.3 uses the word «modified» for that).
+
+        If there's no time given in the entry, we try with <published>
+        and <issued> elements.
+        """
+        for name in ('updated', 'modified', 'published', 'issued'):
+            date = self.getTagData(name)
+            if date is not None:
+                break
+
+        if date is None:
+            # it is not in the standard format
+            return time.asctime()
+
+        return date
+
+    updated = property(
+        get_updated, None, None,
+        ''' Last significant modification time. ''')
+
+    feed_tagline = ''


=====================================
gajim/common/modules/pep.py
=====================================
--- a/gajim/common/modules/pep.py
+++ b/gajim/common/modules/pep.py
@@ -134,14 +134,14 @@ class AbstractPEPModule:
         raise NotImplementedError
 
     def _push_event(self, jid, user_pep):
-        self._update_contacts(jid, user_pep)
+        self._notification_received(jid, user_pep)
         app.nec.push_incoming_event(
             PEPReceivedEvent(None, conn=self._con,
                              jid=str(jid),
                              pep_type=self.name,
                              user_pep=user_pep))
 
-    def _update_contacts(self, jid, user_pep):
+    def _notification_received(self, jid, user_pep):
         for contact in app.contacts.get_contacts(self._account, str(jid)):
             if user_pep:
                 contact.pep[self.name] = user_pep


=====================================
gajim/common/modules/user_avatar.py
=====================================
--- a/gajim/common/modules/user_avatar.py
+++ b/gajim/common/modules/user_avatar.py
@@ -21,15 +21,31 @@ import binascii
 import nbxmpp
 
 from gajim.common import app
+from gajim.common.const import PEPEventType
 from gajim.common.exceptions import StanzaMalformed
+from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData
 
 log = logging.getLogger('gajim.c.m.user_avatar')
 
 
-class UserAvatar:
+class UserAvatarData(AbstractPEPData):
+
+    type_ = PEPEventType.AVATAR
+
+    def __init__(self, avatar):
+        self._pep_specific_data = avatar
+
+
+class UserAvatar(AbstractPEPModule):
+
+    name = 'user-avatar'
+    namespace = 'urn:xmpp:avatar:metadata'
+    pep_class = UserAvatarData
+    store_publish = False
+    _log = log
+
     def __init__(self, con):
-        self._con = con
-        self._account = con.name
+        AbstractPEPModule.__init__(self, con, con.name)
 
         self.handlers = []
 
@@ -83,7 +99,7 @@ class UserAvatar:
             log.warning('Error: %s %s', stanza.getFrom(), error)
             return
 
-        log.info('Received: %s %s', jid, sha)
+        log.info('Received Avatar: %s %s', jid, sha)
         app.interface.save_avatar(data)
 
         if self._con.get_own_jid().bareMatch(jid):
@@ -94,3 +110,45 @@ class UserAvatar:
             app.contacts.set_avatar(self._account, jid, sha)
 
         app.interface.update_avatar(self._account, jid)
+
+    def _extract_info(self, item):
+        metadata = item.getTag('metadata', namespace=self.namespace)
+        if metadata is None:
+            raise StanzaMalformed('No metadata node')
+
+        info = metadata.getTags('info', one=True)
+        if not info:
+            return None
+
+        avatar = info.getAttrs()
+        return avatar or None
+
+    def _notification_received(self, jid, user_pep):
+        avatar = user_pep._pep_specific_data
+        own_jid = self._con.get_own_jid()
+        if avatar is None:
+            # Remove avatar
+            log.info('Remove: %s', jid)
+            app.contacts.set_avatar(self._account, str(jid), None)
+            app.logger.set_avatar_sha(own_jid.getStripped(), str(jid), None)
+            app.interface.update_avatar(self._account, str(jid))
+        else:
+            if own_jid.bareMatch(jid):
+                sha = app.config.get_per(
+                    'accounts', self._account, 'avatar_sha')
+            else:
+                sha = app.contacts.get_avatar_sha(self._account, str(jid))
+
+            if sha == avatar['id']:
+                log.info('Avatar already known: %s %s',
+                         jid, avatar['id'])
+                return
+            self.get_pubsub_avatar(jid, avatar['id'])
+
+    def send(self, data):
+        # Not implemented yet
+        return
+
+    def retract(self):
+        # Not implemented yet
+        return


=====================================
gajim/common/modules/user_nickname.py
=====================================
--- a/gajim/common/modules/user_nickname.py
+++ b/gajim/common/modules/user_nickname.py
@@ -66,7 +66,7 @@ class UserNickname(AbstractPEPModule):
         item.addData(data)
         return item
 
-    def _update_contacts(self, jid, user_pep):
+    def _notification_received(self, jid, user_pep):
         for contact in app.contacts.get_contacts(self._account, str(jid)):
             contact.contact_name = user_pep.get_nick()
 


=====================================
gajim/common/pep.py
=====================================
--- a/gajim/common/pep.py
+++ b/gajim/common/pep.py
@@ -80,48 +80,4 @@ class AbstractPEP(object):
         pass
 
 
-class AvatarNotificationPEP(AbstractPEP):
-    '''XEP-0084: Avatars'''
-
-    type_ = 'avatar-notification'
-    namespace = 'urn:xmpp:avatar:metadata'
-
-    def _extract_info(self, items):
-        self.avatar = None
-        for item in items.getTags('item'):
-            metadata = item.getTag('metadata')
-            if metadata is None:
-                app.log('c.m.user_avatar').warning(
-                    'Invalid avatar stanza:\n%s', items)
-                break
-            info = item.getTag('metadata').getTag('info')
-            if info is not None:
-                self.avatar = info.getAttrs()
-            break
-
-        return (None, False)
-
-    def _on_receive(self, jid, account):
-        con = app.connections[account]
-        if self.avatar is None:
-            # Remove avatar
-            app.log('c.m.user_avatar').info('Remove: %s', jid)
-            app.contacts.set_avatar(account, jid, None)
-            own_jid = con.get_own_jid().getStripped()
-            app.logger.set_avatar_sha(own_jid, jid, None)
-            app.interface.update_avatar(account, jid)
-        else:
-            sha = app.contacts.get_avatar_sha(account, jid)
-            app.log('c.m.user_avatar').info(
-                'Update: %s %s', jid, self.avatar['id'])
-            if sha == self.avatar['id']:
-                app.log('c.m.user_avatar').info(
-                    'Avatar already known: %s %s',
-                    jid, self.avatar['id'])
-                return
-            con.get_module('UserAvatar').get_pubsub_avatar(
-                jid, self.avatar['id'])
-
-
-SUPPORTED_PERSONAL_USER_EVENTS = [
-    AvatarNotificationPEP]
+SUPPORTED_PERSONAL_USER_EVENTS = []


=====================================
gajim/gui_interface.py
=====================================
--- a/gajim/gui_interface.py
+++ b/gajim/gui_interface.py
@@ -1166,7 +1166,10 @@ class Interface:
 
     @staticmethod
     def handle_atom_entry(obj):
-        AtomWindow.newAtomEntry(obj.atom_entry)
+        if obj != PEPEventType.ATOM:
+            return
+        if obj.get_entry():
+            AtomWindow.newAtomEntry(obj.get_entry())
 
     def handle_event_zc_name_conflict(self, obj):
         def on_ok(new_name):
@@ -1503,7 +1506,7 @@ class Interface:
         self.handlers = {
             'DB_ERROR': [self.handle_event_db_error],
             'FILE_SEND_ERROR': [self.handle_event_file_send_error],
-            'atom-entry-received': [self.handle_atom_entry],
+            'pep-received': [self.handle_atom_entry],
             'bad-gpg-passphrase': [self.handle_event_bad_gpg_passphrase],
             'bookmarks-received': [self.handle_event_bookmarks],
             'client-cert-passphrase': [


=====================================
gajim/roster_window.py
=====================================
--- a/gajim/roster_window.py
+++ b/gajim/roster_window.py
@@ -64,6 +64,7 @@ from gajim.common import helpers
 from gajim.common import idle
 from gajim.common.exceptions import GajimGeneralException
 from gajim.common import i18n
+from gajim.common.const import PEPEventType
 if app.is_installed('GEOCLUE'):
     from gajim.common import location_listener
 from gajim.common import ged
@@ -2648,6 +2649,13 @@ class RosterWindow:
             self.remove_contact(jid, obj.conn.name, backend=True)
 
     def _nec_pep_received(self, obj):
+        if obj.user_pep.type_ not in (PEPEventType.ACTIVITY,
+                                      PEPEventType.TUNE,
+                                      PEPEventType.MOOD,
+                                      PEPEventType.LOCATION,
+                                      PEPEventType.NICKNAME):
+            return
+
         if obj.jid == app.get_jid_from_account(obj.conn.name):
             self.draw_account(obj.conn.name)
 



View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/0a6b2126b34dd9d627e203a630c185f2dfc34e1d...d45fa13ee944e6539413ea6682cdc291fecc959e

-- 
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/0a6b2126b34dd9d627e203a630c185f2dfc34e1d...d45fa13ee944e6539413ea6682cdc291fecc959e
You're receiving this email because of your account on dev.gajim.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.gajim.org/pipermail/commits/attachments/20180706/5f585c45/attachment-0001.html>


More information about the Commits mailing list