home · contact · privacy
Into channel log add membership status change messages on MODE commands.
authorChristian Heller <c.heller@plomlompom.de>
Tue, 25 Nov 2025 14:46:58 +0000 (15:46 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Tue, 25 Nov 2025 14:46:58 +0000 (15:46 +0100)
src/ircplom/client.py
src/ircplom/client_tui.py
src/tests/channels.test

index 420b67f4db6457033a58fe800e65fd1e008a83ac..15a29ca37643c88114b9f50a4ae76cea14e5f64b 100644 (file)
@@ -189,7 +189,8 @@ class _Channel(Channel):
 
     def _add_membership_prefix(self, user_id: str, prefix: str) -> None:
         if prefix in self.prefixes.keys():
-            self.prefixes[prefix] += (user_id,)
+            self.prefixes[prefix] = tuple(sorted(self.prefixes[prefix]
+                                                 + (user_id,)))
         else:
             self.prefixes[prefix] = (user_id,)
 
@@ -217,11 +218,11 @@ class _Channel(Channel):
 
     def remove_user(self, user: '_User', msg: str) -> None:
         'From .user_ids remove .nickname, keep .user_ids declared complete.'
-        for prefix in self.prefixes.keys():
-            self._remove_membership_prefix(user.id_, prefix)
         self.exits[user.id_] = msg
         self.user_ids.completable_remove(user.id_, on_complete=True)
         del self.exits[user.id_]
+        for prefix in self.prefixes.keys():
+            self._remove_membership_prefix(user.id_, prefix)
         self.purge_users()
 
     def mode_on_nick(self, nick: str, modeset: str) -> None:
index 35f1e26313d5d0aab1600655a3a2804f5143d54d..b57adbfffe95b621847f597c58befb49cb7fa1c2 100644 (file)
@@ -287,31 +287,41 @@ class _UpdatingChannel(_UpdatingNode, Channel):
     prefixes: _UpdatingDict[tuple[str, ...]]
 
     def recursive_set_and_report_change(self, update: _Update) -> None:
+        def diff_in(base: tuple[str, ...], excluder: tuple[str, ...]
+                    ) -> tuple[str, ...]:
+            return tuple(id_ for id_ in base if id_ not in excluder)
+
         super().recursive_set_and_report_change(update)
-        if update.key == 'topic':
-            msg = f':{self.topic.who} set topic: {self.topic.what}'
-            update.results += [(_LogScope.CHAT, [msg])]
+        if update.full_path[-2] == 'prefixes' and self.user_ids:
+            update.results += [
+                    (_LogScope.CHAT, [f'NICK:{id_}', f': gains {update.key}'])
+                    for id_ in diff_in(update.value, update.old_value)]
+            update.results += [
+                    (_LogScope.CHAT, [f'NICK:{id_}', f': loses {update.key}'])
+                    for id_ in diff_in(update.old_value, update.value)
+                    if id_ in self.user_ids]
+        elif update.key == 'topic':
+            update.results += [
+                    (_LogScope.CHAT,
+                     [f':{self.topic.who} set topic: {self.topic.what}'])]
         elif update.key == 'user_ids':
             if not update.old_value:
-                nicks = []
+                toks = []
                 for id_ in sorted(update.value):
-                    nicks += [
-                        ':' + ''.join(prefix for prefix in self.prefixes.keys()
-                                      if id_ in self.prefixes[prefix]),
-                        f'NICK:{id_}',
-                        ':, ']
-                nicks.pop()
-                update.results += [(_LogScope.CHAT, [':residents: '] + nicks)]
+                    toks += [':' + ''.join(pfx for pfx in self.prefixes.keys()
+                                           if id_ in self.prefixes[pfx]),
+                             f'NICK:{id_}',
+                             ':, ']
+                update.results += [
+                        (_LogScope.CHAT, [':residents: '] + toks[:-1])]
             else:
-                for id_ in (id_ for id_ in update.value
-                            if id_ not in update.old_value):
-                    update.results += [(_LogScope.CHAT,
-                                        [f'NUH:{id_}', ': joins'])]
-                for id_ in (id_ for id_ in update.old_value
-                            if id_ not in update.value):
-                    update.results += [(_LogScope.CHAT,
-                                        _UpdatingUser.exit_msg_toks(
-                                            f'NUH:{id_}', self.exits[id_]))]
+                update.results += [
+                        (_LogScope.CHAT, [f'NUH:{id_}', ': joins'])
+                        for id_ in diff_in(update.value, update.old_value)]
+                update.results += [
+                        (_LogScope.CHAT, _UpdatingUser.exit_msg_toks(
+                            f'NUH:{id_}', self.exits[id_]))
+                        for id_ in diff_in(update.old_value, update.value)]
 
 
 class _UpdatingUser(_UpdatingNode, User):
index 417f1a27f3b0eb602fe5aad5f69d31169043cfbb..ccec44731f672e7dd31f0908520341cbb8698fc2 100644 (file)
@@ -44,15 +44,18 @@ log LOG_WIN_ID $ already in that channel
 × part-other-0
 insert servermsglogged : + MSG ::NICK!~NICK@NICK.NICK PART ARGS
 
-× part-other-0-no-msg
-insert part-other-0 : + ARGS ::#ch_test0
-
 × part-other-1
 insert parts-core : + USERIDS_CLEAR=set§to:§REMAINING_IDS CHANNEL=#ch_test0 CHAN_WIN_ID=3 § : 
 
-× part-other-1-no-msg
+× part-other-no-msg
+insert part-other-0 : + ARGS ::#ch_test0
 insert part-other-1 : + exitMSG= exitPREFIX :
 
+× set-prefix
+insert servermsglogged : + MSG ::foo.bar.baz MODE #ch_test0 MODESET NICK
+log 1 $ channels:#ch_test0:prefixes:PREFIX NEW_IDS
+log 3 $ NICK VERB PREFIX
+
 × ×--------------------------
 
 insert connect-to-connected
@@ -128,10 +131,12 @@ insert join-channel-1 : + CHANNEL=#ch_test0 RESIDENT_IDS :[2], [3], [4], [5], [m
 log 3 $ residents: @baz, +oof, +rab, zab, foo
 
 # check server giving and taking membership prefixes
-insert servermsglogged : + MSG ::foo.bar.baz MODE #ch_test0 +o zab
-log 1 $ channels:#ch_test0:prefixes:@ set to: [2], [5]
-insert servermsglogged : + MSG ::foo.bar.baz MODE #ch_test0 -v rab
-log 1 $ channels:#ch_test0:prefixes:+ set to: [3]
+insert set-prefix : + MODESET=-o PREFIX=@ VERB=loses NICK=baz NEW_IDS :emptied
+insert set-prefix : + MODESET=-v PREFIX=+ VERB=loses NICK=rab NEW_IDS :set to: [3]
+insert set-prefix : + MODESET=-v PREFIX=+ VERB=loses NICK=oof NEW_IDS :emptied
+insert set-prefix : + MODESET=+v PREFIX=+ VERB=gains NICK=oof NEW_IDS :set to: [3]
+insert set-prefix : + MODESET=+o PREFIX=@ VERB=gains NICK=zab NEW_IDS :set to: [5]
+insert set-prefix : + MODESET=+o PREFIX=@ VERB=gains NICK=baz NEW_IDS :set to: [2], [5]
 
 # check server setting unknown modes towards users
 insert servermsglogged : + MSG ::foo.bar.baz MODE #ch_test0 +a zab
@@ -172,19 +177,17 @@ insert servermsglogged : + MSG ::*.?.net NOTICE #ch_test0 :msg_test6 msg_test7
 log 3 < (*.?.net) msg_test6 msg_test7
 
 # check part of user visible, and of user NOT visible in other channel
-insert part-other-0-no-msg : + NICK :baz
+insert part-other-no-msg : + USER_ID=2 NICK=baz REMAINING_IDS :[3], [4], [5], [me]
 log 1 $ channels:#ch_test0:prefixes:@ set to: [5]
-insert part-other-1-no-msg : + USER_ID=2 NICK=baz REMAINING_IDS :[3], [4], [5], [me]
-insert part-other-0-no-msg : + NICK :oof
+insert part-other-no-msg : + USER_ID=3 NICK=oof REMAINING_IDS :[4], [5], [me]
 log 1 $ channels:#ch_test0:prefixes:+ emptied
-insert part-other-1-no-msg : + USER_ID=3 NICK=oof REMAINING_IDS :[4], [5], [me]
 log 1 $ users:3 deleted
 
 # check other-user part with exit message
 insert part-other-0 : + NICK=zab ARGS :#ch_test0 :goodbye
 insert user-set-to 1: + USER_ID=5 USERNAME=~zab USERHOST :zab.zab
-log 1 $ channels:#ch_test0:prefixes:@ emptied
 insert part-other-1 : + USER_ID=5 NICK=zab exitPREFIX=:§ exitMSG=goodbye REMAINING_IDS=[4],§[me] § : 
+log 1 $ channels:#ch_test0:prefixes:@ emptied
 log 1 $ users:5 deleted
 
 # check re-join of user kept visible in other channel