[Git][gajim/gajim][master] 2 commits: Roster: remove asserts

Philipp Hörist gitlab at dev.gajim.org
Tue Jan 22 20:22:55 CET 2019


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


Commits:
b0742377 by Philipp Hörist at 2019-01-20T13:29:48Z
Roster: remove asserts

- - - - -
1a7d930f by Philipp Hörist at 2019-01-21T21:45:19Z
Add blocking list dialog

- - - - -


8 changed files:

- gajim/app_actions.py
- gajim/application.py
- gajim/common/modules/blocking.py
- gajim/common/modules/privacylists.py
- + gajim/data/gui/blocking_list.ui
- + gajim/gtk/blocking.py
- gajim/gui_menu_builder.py
- gajim/roster_window.py


Changes:

=====================================
gajim/app_actions.py
=====================================
@@ -44,6 +44,7 @@ from gajim.gtk.history import HistoryWindow
 from gajim.gtk.accounts import AccountsWindow
 from gajim.gtk.proxies import ManageProxies
 from gajim.gtk.discovery import ServiceDiscoveryWindow
+from gajim.gtk.blocking import BlockingList
 
 
 # General Actions
@@ -211,6 +212,15 @@ def on_mam_preferences(action, param):
         window.present()
 
 
+def on_blocking_list(action, param):
+    account = param.get_string()
+    window = app.get_app_window(MamPreferences, account)
+    if window is None:
+        BlockingList(account)
+    else:
+        window.present()
+
+
 def on_history_sync(action, param):
     account = param.get_string()
     if 'history_sync' in interface.instances[account]:


=====================================
gajim/application.py
=====================================
@@ -469,6 +469,7 @@ class GajimApplication(Gtk.Application):
             ('-archive', a.on_mam_preferences, 'feature', 's'),
             ('-sync-history', a.on_history_sync, 'online', 's'),
             ('-privacylists', a.on_privacy_lists, 'feature', 's'),
+            ('-blocking', a.on_blocking_list, 'feature', 's'),
             ('-send-server-message', a.on_send_server_message, 'online', 's'),
             ('-set-motd', a.on_set_motd, 'online', 's'),
             ('-update-motd', a.on_update_motd, 'online', 's'),
@@ -517,3 +518,6 @@ class GajimApplication(Gtk.Application):
         elif event.feature == nbxmpp.NS_PRIVACY:
             action = '%s-privacylists' % event.account
             self.lookup_action(action).set_enabled(True)
+        elif event.feature == nbxmpp.NS_BLOCKING:
+            action = '%s-blocking' % event.account
+            self.lookup_action(action).set_enabled(True)


=====================================
gajim/common/modules/blocking.py
=====================================
@@ -15,15 +15,26 @@
 # XEP-0191: Blocking Command
 
 import logging
+from functools import wraps
 
 import nbxmpp
 
 from gajim.common import app
+from gajim.common.nec import NetworkEvent
 from gajim.common.nec import NetworkIncomingEvent
 
 log = logging.getLogger('gajim.c.m.blocking')
 
 
+def ensure_online(func):
+    @wraps(func)
+    def func_wrapper(self, *args, **kwargs):
+        if not app.account_is_connected(self._account):
+            return
+        return func(self, *args, **kwargs)
+    return func_wrapper
+
+
 class Blocking:
     def __init__(self, con):
         self._con = con
@@ -37,37 +48,48 @@ class Blocking:
 
         self.supported = False
 
+        self._nbmxpp_methods = [
+            'block',
+            'unblock',
+        ]
+
+    def __getattr__(self, key):
+        if key not in self._nbmxpp_methods:
+            raise AttributeError
+        if not app.account_is_connected(self._account):
+            log.warning('Account %s not connected, cant use %s',
+                        self._account, key)
+            return
+        module = self._con.connection.get_module('Blocking')
+        return getattr(module, key)
+
     def pass_disco(self, from_, _identities, features, _data, _node):
         if nbxmpp.NS_BLOCKING not in features:
             return
 
         self.supported = True
+        app.nec.push_incoming_event(
+            NetworkEvent('feature-discovered',
+                         account=self._account,
+                         feature=nbxmpp.NS_BLOCKING))
+
         log.info('Discovered blocking: %s', from_)
 
-    def get_blocking_list(self) -> None:
-        if not self.supported:
-            return
-        iq = nbxmpp.Iq('get', nbxmpp.NS_BLOCKING)
-        iq.setQuery('blocklist')
+    @ensure_online
+    def get_blocking_list(self, callback=None):
         log.info('Request list')
-        self._con.connection.SendAndCallForResponse(
-            iq, self._blocking_list_received)
+        if callback is None:
+            callback = self._blocking_list_received
 
-    def _blocking_list_received(self, stanza: nbxmpp.Iq) -> None:
-        if not nbxmpp.isResultNode(stanza):
-            log.info('Error: %s', stanza.getError())
-            return
+        self._con.connection.get_module('Blocking').get_blocking_list(
+            callback=callback)
 
-        self.blocked = []
-        blocklist = stanza.getTag('blocklist', namespace=nbxmpp.NS_BLOCKING)
-        if blocklist is None:
-            log.error('No blocklist node')
+    def _blocking_list_received(self, result):
+        if result.is_error:
+            log.info('Error: %s', result.error)
             return
 
-        for item in blocklist.getTags('item'):
-            self.blocked.append(item.getAttr('jid'))
-        log.info('Received list: %s', self.blocked)
-
+        self.blocked = result.blocking_list
         app.nec.push_incoming_event(
             BlockingEvent(None, conn=self._con, changed=self.blocked))
 
@@ -129,35 +151,6 @@ class Blocking:
         probe = nbxmpp.Presence(jid, 'probe', frm=self._con.get_own_jid())
         self._con.connection.send(probe)
 
-    def block(self, contact_list):
-        if not self.supported:
-            return
-        iq = nbxmpp.Iq('set', nbxmpp.NS_BLOCKING)
-        query = iq.setQuery(name='block')
-
-        for contact in contact_list:
-            query.addChild(name='item', attrs={'jid': contact.jid})
-            log.info('Block: %s', contact.jid)
-        self._con.connection.SendAndCallForResponse(
-            iq, self._default_result_handler, {})
-
-    def unblock(self, contact_list):
-        if not self.supported:
-            return
-        iq = nbxmpp.Iq('set', nbxmpp.NS_BLOCKING)
-        query = iq.setQuery(name='unblock')
-
-        for contact in contact_list:
-            query.addChild(name='item', attrs={'jid': contact.jid})
-            log.info('Unblock: %s', contact.jid)
-        self._con.connection.SendAndCallForResponse(
-            iq, self._default_result_handler, {})
-
-    @staticmethod
-    def _default_result_handler(_con, stanza):
-        if not nbxmpp.isResultNode(stanza):
-            log.warning('Operation failed: %s', stanza.getError())
-
 
 class BlockingEvent(NetworkIncomingEvent):
     name = 'blocking'


=====================================
gajim/common/modules/privacylists.py
=====================================
@@ -304,7 +304,8 @@ class PrivacyLists:
 
     def block_contacts(self, contact_list, message):
         if not self.supported:
-            self._con.get_module('Blocking').block(contact_list)
+            jid_list = [contact.jid for contact in contact_list]
+            self._con.get_module('Blocking').block(jid_list)
             return
 
         if self.default_list is None:
@@ -350,7 +351,8 @@ class PrivacyLists:
 
     def unblock_contacts(self, contact_list):
         if not self.supported:
-            self._con.get_module('Blocking').unblock(contact_list)
+            jid_list = [contact.jid for contact in contact_list]
+            self._con.get_module('Blocking').unblock(jid_list)
             return
 
         new_blocked_list = []


=====================================
gajim/data/gui/blocking_list.ui
=====================================
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+  <requires lib="gtk+" version="3.12"/>
+  <object class="GtkListStore" id="blocking_store">
+    <columns>
+      <!-- column-name jid -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkGrid" id="blocking_grid">
+    <property name="width_request">400</property>
+    <property name="height_request">300</property>
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="margin_left">18</property>
+    <property name="margin_right">18</property>
+    <property name="margin_top">18</property>
+    <property name="margin_bottom">18</property>
+    <property name="row_spacing">5</property>
+    <property name="column_spacing">10</property>
+    <child>
+      <object class="GtkButtonBox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="halign">start</property>
+        <property name="spacing">5</property>
+        <property name="layout_style">start</property>
+        <child>
+          <object class="GtkButton" id="add_button">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <signal name="clicked" handler="_on_add" swapped="no"/>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="icon_name">list-add-symbolic</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+            <property name="non_homogeneous">True</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="remove_button">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <signal name="clicked" handler="_on_remove" swapped="no"/>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="icon_name">list-remove-symbolic</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+            <property name="non_homogeneous">True</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="save_button">
+        <property name="label">Save</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="halign">end</property>
+        <property name="always_show_image">True</property>
+        <signal name="clicked" handler="_on_save" swapped="no"/>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkOverlay" id="overlay">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <child>
+          <object class="GtkScrolledWindow">
+            <property name="height_request">150</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <property name="shadow_type">in</property>
+            <child>
+              <object class="GtkTreeView" id="block_view">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="model">blocking_store</property>
+                <property name="search_column">0</property>
+                <child internal-child="selection">
+                  <object class="GtkTreeSelection" id="treeview-selection2"/>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+                    <property name="title" translatable="yes">Jabber ID</property>
+                    <property name="expand">True</property>
+                    <property name="clickable">True</property>
+                    <property name="sort_indicator">True</property>
+                    <property name="sort_column_id">0</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="cellrenderertext3">
+                        <property name="editable">True</property>
+                        <property name="placeholder_text">user at example.org</property>
+                        <signal name="edited" handler="_jid_edited" swapped="no"/>
+                      </object>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="index">-1</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">0</property>
+        <property name="width">2</property>
+      </packing>
+    </child>
+  </object>
+</interface>


=====================================
gajim/gtk/blocking.py
=====================================
@@ -0,0 +1,150 @@
+# 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/>.
+
+import logging
+
+from gi.repository import Gtk
+from gi.repository import Gdk
+
+from gajim.common import app
+from gajim.common.i18n import _
+
+from gajim.gtk.util import get_builder
+from gajim.gtk.dialogs import HigDialog
+
+log = logging.getLogger('gajim.gtk.blocking_list')
+
+
+class BlockingList(Gtk.ApplicationWindow):
+    def __init__(self, account):
+        Gtk.ApplicationWindow.__init__(self)
+        self.set_application(app.app)
+        self.set_position(Gtk.WindowPosition.CENTER)
+        self.set_show_menubar(False)
+        self.set_title(_('Blocking List for %s') % account)
+
+        self.connect('key-press-event', self._on_key_press)
+
+        self.account = account
+        self._con = app.connections[account]
+        self._prev_blocked_jids = set()
+        self._await_results = 2
+        self._received_errors = False
+
+        self._ui = get_builder('blocking_list.ui')
+        self.add(self._ui.blocking_grid)
+
+        self._spinner = Gtk.Spinner()
+        self._ui.overlay.add_overlay(self._spinner)
+
+        self._set_grid_state(False)
+        self._ui.connect_signals(self)
+        self.show_all()
+
+        self._activate_spinner()
+
+        self._con.get_module('Blocking').get_blocking_list(
+            callback=self._on_blocking_list_received)
+
+    def _reset_after_error(self):
+        self._received_errors = False
+        self._await_results = 2
+        self._disable_spinner()
+        self._set_grid_state(True)
+
+    def _show_error(self, error):
+        dialog = HigDialog(
+            self, Gtk.MessageType.INFO, Gtk.ButtonsType.OK,
+            _('Error!'),
+            error)
+        dialog.popup()
+
+    def _on_blocking_list_received(self, result):
+        self._disable_spinner()
+        self._set_grid_state(not result.is_error)
+
+        if result.is_error:
+            self._show_error(result.error)
+
+        else:
+            self._prev_blocked_jids = set(result.blocking_list)
+            self._ui.blocking_store.clear()
+            for item in result.blocking_list:
+                self._ui.blocking_store.append((item,))
+
+    def _on_save_result(self, result):
+        self._await_results -= 1
+        if result.is_error and not self._received_errors:
+            self._show_error(result.error)
+            self._received_errors = True
+
+        if not self._await_results:
+            if self._received_errors:
+                self._reset_after_error()
+            else:
+                self.destroy()
+
+    def _set_grid_state(self, state):
+        self._ui.blocking_grid.set_sensitive(state)
+
+    def _jid_edited(self, _renderer, path, new_text):
+        iter_ = self._ui.blocking_store.get_iter(path)
+        self._ui.blocking_store.set_value(iter_, 0, new_text)
+
+    def _on_add(self, _button):
+        self._ui.blocking_store.append([''])
+
+    def _on_remove(self, _button):
+        mod, paths = self._ui.block_view.get_selection().get_selected_rows()
+        for path in paths:
+            iter_ = mod.get_iter(path)
+            self._ui.blocking_store.remove(iter_)
+
+    def _on_save(self, _button):
+        self._activate_spinner()
+        self._set_grid_state(False)
+
+        blocked_jids = set()
+        for item in self._ui.blocking_store:
+            blocked_jids.add(item[0].lower())
+
+        unblock_jids = self._prev_blocked_jids - blocked_jids
+        if unblock_jids:
+            self._con.get_module('Blocking').unblock(
+                unblock_jids, callback=self._on_save_result)
+        else:
+            self._await_results -= 1
+
+        block_jids = blocked_jids - self._prev_blocked_jids
+        if block_jids:
+            self._con.get_module('Blocking').block(
+                block_jids, callback=self._on_save_result)
+        else:
+            self._await_results -= 1
+
+        if not self._await_results:
+            # No changes
+            self.destroy()
+
+    def _activate_spinner(self):
+        self._spinner.show()
+        self._spinner.start()
+
+    def _disable_spinner(self):
+        self._spinner.hide()
+        self._spinner.stop()
+
+    def _on_key_press(self, _widget, event):
+        if event.keyval == Gdk.KEY_Escape:
+            self.destroy()


=====================================
gajim/gui_menu_builder.py
=====================================
@@ -788,6 +788,7 @@ def get_account_menu(account):
         ('-start-single-chat', _('Send Single Message…')),
         (_('Advanced'), [
             ('-archive', _('Archiving Preferences')),
+            ('-blocking', _('Blocking List')),
             ('-sync-history', _('Synchronise History')),
             ('-privacylists', _('Privacy Lists')),
             ('-server-info', _('Server Info')),


=====================================
gajim/roster_window.py
=====================================
@@ -388,7 +388,6 @@ class RosterWindow:
             parent_iters = self._get_contact_iter(
                     big_brother_contact.jid, big_brother_account,
                     big_brother_contact, self.model)
-            assert parent_iters, 'Big brother is not yet in roster!'
 
             # Do not confuse get_contact_iter: Sync groups of family members
             contact.groups = big_brother_contact.groups[:]
@@ -445,7 +444,6 @@ class RosterWindow:
                 if group not in app.groups[account]:
                     app.groups[account][group] = {'expand': is_expanded}
 
-        assert added_iters, '%s has not been added to roster!' % contact.jid
         return added_iters
 
     def _remove_entity(self, contact, account, groups=None):
@@ -464,7 +462,6 @@ class RosterWindow:
         """
         iters = self._get_contact_iter(contact.jid, account, contact,
             self.model)
-        assert iters, '%s shall be removed but is not in roster' % contact.jid
 
         parent_iter = self.model.iter_parent(iters[0])
         parent_type = self.model[parent_iter][Column.TYPE]
@@ -484,10 +481,6 @@ class RosterWindow:
             return False
         # Remove us and empty groups from the model
         for i in iters:
-            assert self.model[i][Column.JID] == contact.jid and \
-                    self.model[i][Column.ACCOUNT] == account, \
-                    "Invalidated iters of %s" % contact.jid
-
             parent_i = self.model.iter_parent(i)
             parent_type = self.model[parent_i][Column.TYPE]
 
@@ -529,10 +522,6 @@ class RosterWindow:
         big_brother_contact = app.contacts.get_first_contact_from_jid(
                 big_brother_account, big_brother_jid)
 
-        assert not self._get_contact_iter(big_brother_jid,
-                big_brother_account, big_brother_contact, self.model), \
-                'Big brother %s already in roster\n Family: %s' \
-                % (big_brother_jid, family)
         self._add_entity(big_brother_contact, big_brother_account)
 
         brothers = []
@@ -548,9 +537,6 @@ class RosterWindow:
                 # or brother already added
                 continue
 
-            assert not self._get_contact_iter(_jid, _account,
-                    _contact, self.model), \
-                    "%s already in roster.\n Family: %s" % (_jid, nearby_family)
             self._add_entity(_contact, _account,
                     big_brother_contact=big_brother_contact,
                     big_brother_account=big_brother_account)
@@ -582,8 +568,6 @@ class RosterWindow:
                 # Family might not be up to date.
                 # Only try to remove what is actually in the roster
                 continue
-            assert iters, '%s shall be removed but is not in roster \
-                    \n Family: %s' % (_jid, family)
 
             family_in_roster = True
 
@@ -594,31 +578,14 @@ class RosterWindow:
                 # The contact on top
                 old_big_account = _account
                 old_big_contact = _contact
-                old_big_jid = _jid
                 continue
 
-            ok = self._remove_entity(_contact, _account)
-            assert ok, '%s was not removed' % _jid
-            assert not self._get_contact_iter(_jid, _account, _contact,
-                self.model), '%s is removed but still in roster' % _jid
+            self._remove_entity(_contact, _account)
 
         if not family_in_roster:
             return False
 
-        assert old_big_jid, 'No Big Brother in nearby family %s (Family: %s)' %\
-            (nearby_family, family)
-        iters = self._get_contact_iter(old_big_jid, old_big_account,
-            old_big_contact, self.model)
-        assert iters, 'Old Big Brother %s is not in roster anymore' % \
-            old_big_jid
-        assert not self.model.iter_children(iters[0]), \
-            'Old Big Brother %s still has children' % old_big_jid
-
-        ok = self._remove_entity(old_big_contact, old_big_account)
-        assert ok, "Old Big Brother %s not removed" % old_big_jid
-        assert not self._get_contact_iter(old_big_jid, old_big_account,
-            old_big_contact, self.model), \
-            'Old Big Brother %s is removed but still in roster' % old_big_jid
+        self._remove_entity(old_big_contact, old_big_account)
 
         return True
 
@@ -682,9 +649,6 @@ class RosterWindow:
         jid = app.get_jid_from_account(account)
         contact = app.contacts.get_first_contact_from_jid(account, jid)
 
-        assert not self._get_contact_iter(jid, account, contact,
-        self.model), 'Self contact %s already in roster' % jid
-
         child_iterA = self._get_account_iter(account, self.model)
         self._iters[account]['contacts'][jid] = [self.model.append(child_iterA,
             [None, app.nicks[account], 'self_contact', jid, account, None,
@@ -1047,7 +1011,6 @@ class RosterWindow:
     def _really_draw_account(self, account):
         child_iter = self._get_account_iter(account, self.model)
         if not child_iter:
-            assert False, 'Account iter of %s could not be found.' % account
             return
 
         num_of_accounts = app.get_number_of_connected_accounts()



View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/46707606687671488314f947cf5eeaac1360c354...1a7d930fc475df03155c81aeecc6ef1fe33cb0bc

-- 
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/46707606687671488314f947cf5eeaac1360c354...1a7d930fc475df03155c81aeecc6ef1fe33cb0bc
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/20190122/79f4f54a/attachment-0001.html>


More information about the Commits mailing list