Merge branch 'admin-report-show-source' into 'main'

show source list of new subscriptions in admin reports

See merge request s3lph/multischleuder!3
This commit is contained in:
s3lph 2022-05-30 16:15:55 +00:00
commit 3d66918202
6 changed files with 31 additions and 28 deletions

View file

@ -31,8 +31,7 @@ class KeyConflictResolution:
target: str, target: str,
mail_from: str, mail_from: str,
subscriptions: List[SchleuderSubscriber], subscriptions: List[SchleuderSubscriber],
sources: List[SchleuderList]) -> Tuple[List[SchleuderSubscriber], List[Optional[Message]]]: sourcemap: Dict[int, str]) -> Tuple[List[SchleuderSubscriber], List[Optional[Message]]]:
sourcemap: Dict[int, str] = {s.id: s.name for s in sources}
conflicts: List[Optional[Message]] = [] conflicts: List[Optional[Message]] = []
# First check for keys that are being used by more than one subscriber # First check for keys that are being used by more than one subscriber

View file

@ -32,6 +32,7 @@ class MultiList:
def process(self, dry_run: bool = False): def process(self, dry_run: bool = False):
logging.info(f'Processing: {self._target} {"DRY RUN" if dry_run else ""}') logging.info(f'Processing: {self._target} {"DRY RUN" if dry_run else ""}')
target_list, sources = self._lists_by_name() target_list, sources = self._lists_by_name()
sourcemap: Dict[int, str] = {s.id: s.name for s in sources}
target_admins = self._api.get_list_admins(target_list) target_admins = self._api.get_list_admins(target_list)
# Get current subs, except for unmanaged adresses # Get current subs, except for unmanaged adresses
current_subs: Set[SchleuderSubscriber] = set() current_subs: Set[SchleuderSubscriber] = set()
@ -53,7 +54,7 @@ class MultiList:
continue continue
all_subs.append(s) all_subs.append(s)
# ... which is taken care of by the key conflict resolution routine # ... which is taken care of by the key conflict resolution routine
resolved, conflicts = self._kcr.resolve(self._target, self._mail_from, all_subs, sources) resolved, conflicts = self._kcr.resolve(self._target, self._mail_from, all_subs, sourcemap)
self._reporter.add_messages(conflicts) self._reporter.add_messages(conflicts)
intended_subs: Set[SchleuderSubscriber] = set(resolved) intended_subs: Set[SchleuderSubscriber] = set(resolved)
intended_keys: Set[SchleuderKey] = {s.key for s in intended_subs if s.key is not None} intended_keys: Set[SchleuderKey] = {s.key for s in intended_subs if s.key is not None}
@ -88,7 +89,7 @@ class MultiList:
report = AdminReport(self._target, admin.email, self._mail_from, report = AdminReport(self._target, admin.email, self._mail_from,
admin.key.blob if admin.key is not None else None, admin.key.blob if admin.key is not None else None,
to_subscribe, to_unsubscribe, to_update, to_add, to_remove, to_subscribe, to_unsubscribe, to_update, to_add, to_remove,
conflicts) conflicts, sourcemap)
self._reporter.add_message(report) self._reporter.add_message(report)
except BaseException: except BaseException:
logging.exception(f'Encryption to {admin.email} failed, not sending report') logging.exception(f'Encryption to {admin.email} failed, not sending report')

View file

@ -208,7 +208,8 @@ class AdminReport(Message):
updated: Set[SchleuderSubscriber], updated: Set[SchleuderSubscriber],
added: Set[SchleuderKey], added: Set[SchleuderKey],
removed: Set[SchleuderKey], removed: Set[SchleuderKey],
conflicts: List[Optional[Message]]): conflicts: List[Optional[Message]],
sourcemap: Dict[int, str]):
if len(subscribed) == 0 and len(unsubscribed) == 0 and len(removed) == 0 \ if len(subscribed) == 0 and len(unsubscribed) == 0 and len(removed) == 0 \
and len(added) == 0 and len(updated) == 0 and len(conflicts) == 0: and len(added) == 0 and len(updated) == 0 and len(conflicts) == 0:
raise ValueError('No changes, not creating admin report') raise ValueError('No changes, not creating admin report')
@ -233,15 +234,14 @@ class AdminReport(Message):
>>> Subscribed: >>> Subscribed:
''' '''
for s in subscribed: for s in subscribed:
fpr = 'no key' if s.key is None else s.key.fingerprint sschleuder: str = sourcemap.get(s.schleuder, 'unknown')
content += f'{s.email} ({fpr})\n' content += f'{s.email} ({sschleuder})\n'
if len(unsubscribed) > 0: if len(unsubscribed) > 0:
content += ''' content += '''
>>> Unsubscribed: >>> Unsubscribed:
''' '''
for s in unsubscribed: for s in unsubscribed:
fpr = 'no key' if s.key is None else s.key.fingerprint content += f'{s.email}\n'
content += f'{s.email} ({fpr})\n'
if len(updated) > 0: if len(updated) > 0:
content += ''' content += '''
>>> Subscriber keys changed: >>> Subscriber keys changed:

View file

@ -123,7 +123,7 @@ class TestKeyConflictResolution(unittest.TestCase):
contents.seek(io.SEEK_END) # Opened with 'a+' contents.seek(io.SEEK_END) # Opened with 'a+'
with patch('builtins.open', mock_open(read_data=_CONFLICT_STATE_NONE)) as mock_statefile: with patch('builtins.open', mock_open(read_data=_CONFLICT_STATE_NONE)) as mock_statefile:
mock_statefile().__enter__.return_value = contents mock_statefile().__enter__.return_value = contents
resolved, messages = kcr.resolve('', '', [], []) resolved, messages = kcr.resolve('', '', [], {})
self.assertEqual(0, len(resolved)) self.assertEqual(0, len(resolved))
self.assertEqual(0, len(messages)) self.assertEqual(0, len(messages))
@ -133,7 +133,7 @@ class TestKeyConflictResolution(unittest.TestCase):
date1 = datetime(2022, 4, 15, 5, 23, 42, 0, tzinfo=tzutc()) date1 = datetime(2022, 4, 15, 5, 23, 42, 0, tzinfo=tzutc())
sub1 = SchleuderSubscriber(3, 'foo@example.org', key1, sch1.id, date1) sub1 = SchleuderSubscriber(3, 'foo@example.org', key1, sch1.id, date1)
kcr = KeyConflictResolution(3600, '/tmp/state.json', _KEY_TEMPLATE, _USER_TEMPLATE) kcr = KeyConflictResolution(3600, '/tmp/state.json', _KEY_TEMPLATE, _USER_TEMPLATE)
resolved, messages = kcr.resolve('', '', [sub1], [sch1]) resolved, messages = kcr.resolve('', '', [sub1], {42: sch1})
self.assertEqual(1, len(resolved)) self.assertEqual(1, len(resolved))
self.assertEqual(sub1, resolved[0]) self.assertEqual(sub1, resolved[0])
self.assertEqual(0, len(messages)) self.assertEqual(0, len(messages))
@ -159,7 +159,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(1, len(resolved)) self.assertEqual(1, len(resolved))
self.assertEqual('2FBBC0DF97FDBF1E4B704EEDE39EF4FAC420BEB6', resolved[0].key.fingerprint) self.assertEqual('2FBBC0DF97FDBF1E4B704EEDE39EF4FAC420BEB6', resolved[0].key.fingerprint)
@ -187,7 +187,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(1, len(resolved)) self.assertEqual(1, len(resolved))
self.assertEqual('135AFA0FB3FF584828911208B7913308392972A4', resolved[0].key.fingerprint) self.assertEqual('135AFA0FB3FF584828911208B7913308392972A4', resolved[0].key.fingerprint)
@ -225,7 +225,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(1, len(resolved)) self.assertEqual(1, len(resolved))
self.assertEqual('2FBBC0DF97FDBF1E4B704EEDE39EF4FAC420BEB6', resolved[0].key.fingerprint) self.assertEqual('2FBBC0DF97FDBF1E4B704EEDE39EF4FAC420BEB6', resolved[0].key.fingerprint)
@ -246,7 +246,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1], subscriptions=[sub1],
sources=[sch1]) sourcemap={42: sch1})
self.assertEqual(0, len(resolved)) self.assertEqual(0, len(resolved))
self.assertEqual(0, len(messages)) self.assertEqual(0, len(messages))
@ -271,7 +271,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(1, len(resolved)) self.assertEqual(1, len(resolved))
self.assertEqual('bar@example.org', resolved[0].email) self.assertEqual('bar@example.org', resolved[0].email)
@ -324,7 +324,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2, sub3], subscriptions=[sub1, sub2, sub3],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(2, len(resolved)) self.assertEqual(2, len(resolved))
foo, bar = resolved foo, bar = resolved
@ -376,7 +376,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(0, len(msgs)) self.assertEqual(0, len(msgs))
def test_send_messages_brokenstate(self): def test_send_messages_brokenstate(self):
@ -399,7 +399,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(0, len(msgs)) self.assertEqual(0, len(msgs))
def test_send_messages_emptystate(self): def test_send_messages_emptystate(self):
@ -421,7 +421,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(1, len(msgs)) self.assertEqual(1, len(msgs))
now = datetime.utcnow().timestamp() now = datetime.utcnow().timestamp()
@ -452,7 +452,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(1, len(msgs)) self.assertEqual(1, len(msgs))
now = datetime.utcnow().timestamp() now = datetime.utcnow().timestamp()
@ -483,7 +483,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(1, len(messages)) self.assertEqual(1, len(messages))
msg = messages[0] msg = messages[0]
@ -515,7 +515,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(0, len(messages)) self.assertEqual(0, len(messages))
now = datetime.utcnow().timestamp() now = datetime.utcnow().timestamp()
@ -549,7 +549,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2], subscriptions=[sub1, sub2],
sources=[sch1, sch2]) sourcemap={42: sch1, 23: sch2})
self.assertEqual(1, len(messages)) self.assertEqual(1, len(messages))
now = datetime.utcnow().timestamp() now = datetime.utcnow().timestamp()
@ -582,7 +582,7 @@ class TestKeyConflictResolution(unittest.TestCase):
target='test@schleuder.example.org', target='test@schleuder.example.org',
mail_from='test-owner@schleuder.example.org', mail_from='test-owner@schleuder.example.org',
subscriptions=[sub1, sub2, sub3], subscriptions=[sub1, sub2, sub3],
sources=[sch1, sch2, sch3]) sourcemap={42: sch1, 23: sch2, 7: sch1})
self.assertEqual(1, len(messages)) self.assertEqual(1, len(messages))
msg = messages[0].mime msg = messages[0].mime
pgp = pgpy.PGPMessage.from_blob(msg.get_payload()[1].get_payload(decode=True)) pgp = pgpy.PGPMessage.from_blob(msg.get_payload()[1].get_payload(decode=True))

View file

@ -46,7 +46,8 @@ def one_of_each_kind():
updated={}, updated={},
added={}, added={},
removed={}, removed={},
conflicts=[]) conflicts=[],
sourcemap={1: 'test@example.org'})
msg3 = UserConflictMessage( msg3 = UserConflictMessage(
schleuder='test@example.org', schleuder='test@example.org',
subscriber='bar@example.org', subscriber='bar@example.org',
@ -124,4 +125,5 @@ class TestReporting(unittest.TestCase):
updated={}, updated={},
added={}, added={},
removed={}, removed={},
conflicts=[]) conflicts=[],
sourcemap={1: 'test@example.org'})

View file

@ -188,7 +188,8 @@ class TestSmtpClient(unittest.TestCase):
updated={}, updated={},
added={}, added={},
removed={}, removed={},
conflicts=[]) conflicts=[],
sourcemap={1: 'foo@example.org'})
client.send_messages([msg1, msg2]) client.send_messages([msg1, msg2])
ctrl.stop() ctrl.stop()
self.assertTrue(ctrl.handler.connected) self.assertTrue(ctrl.handler.connected)