diff --git a/multischleuder/api.py b/multischleuder/api.py index 429c13d..9ab9f3d 100644 --- a/multischleuder/api.py +++ b/multischleuder/api.py @@ -72,6 +72,15 @@ class SchleuderApi: subs.append(sub) return subs + def get_subscriber(self, email: str, schleuder: 'SchleuderList') -> 'SchleuderSubscriber': + response = self.__request('subscriptions.json', list_id=schleuder.id) + for r in response: + if r['email'] != email: + continue + key = self.get_key(r['fingerprint'], schleuder) + return SchleuderSubscriber.from_api(key, **r) + raise KeyError(f'{email} is not subscribed to {schleuder.name}') + def subscribe(self, sub: 'SchleuderSubscriber', schleuder: 'SchleuderList'): if self._dry_run: return @@ -81,16 +90,18 @@ class SchleuderApi: }) self.__request('subscriptions.json', list_id=schleuder.id, data=data, method='POST') - def unsubscribe(self, sub: 'SchleuderSubscriber'): + def unsubscribe(self, sub: 'SchleuderSubscriber', schleuder: 'SchleuderList'): + listsub = self.get_subscriber(sub.email, schleuder) if self._dry_run: return - self.__request('subscriptions/{}.json', fmt=[sub.id], method='DELETE') + self.__request('subscriptions/{}.json', fmt=[listsub.id], method='DELETE') - def update_fingerprint(self, sub: 'SchleuderSubscriber'): + def update_fingerprint(self, sub: 'SchleuderSubscriber', schleuder: 'SchleuderList'): + listsub = self.get_subscriber(sub.email, schleuder) if self._dry_run: return data = json.dumps({'fingerprint': sub.key.fingerprint}) - self.__request('subscriptions/{}.json', fmt=[sub.id], data=data, method='PATCH') + self.__request('subscriptions/{}.json', fmt=[listsub.id], data=data, method='PATCH') # Key Management diff --git a/multischleuder/test/test_api.py b/multischleuder/test/test_api.py index e7ce859..04ca5e8 100644 --- a/multischleuder/test/test_api.py +++ b/multischleuder/test/test_api.py @@ -102,11 +102,13 @@ class TestSchleuderApi(unittest.TestCase): def read(): url = mock.call_args_list[-1][0][0].get_full_url() - if 'lists.json' in url: + if '/lists' in url: return _LIST_RESPONSE.encode() - if 'subscriptions.json' in url: + if '/subscriptions' in url: return _SUBSCRIBER_RESPONSE.encode() - return _KEY_RESPONSE.encode() + if '/keys' in url: + return _KEY_RESPONSE.encode() + return b'null' m.read = read m.__enter__.return_value = m mock.return_value = m @@ -145,6 +147,18 @@ class TestSchleuderApi(unittest.TestCase): self.assertIn('-----BEGIN PGP PUBLIC KEY BLOCK-----', subs[0].key.blob) self.assertEqual(42, subs[0].key.schleuder) + @patch('urllib.request.urlopen') + def test_get_subscriber(self, mock): + api = self._mock_api(mock) + sub = api.get_subscriber('foo@example.org', SchleuderList(42, '', '')) + self.assertEqual(23, sub.id) + self.assertEqual('foo@example.org', sub.email) + self.assertEqual('2FBBC0DF97FDBF1E4B704EEDE39EF4FAC420BEB6', sub.key.fingerprint) + self.assertEqual(42, sub.key.schleuder) + self.assertEqual(42, sub.schleuder) + with self.assertRaises(KeyError): + api.get_subscriber('bar@example.org', SchleuderList(42, '', '')) + @patch('urllib.request.urlopen') def test_subscribe(self, mock): api = self._mock_api(mock) @@ -153,8 +167,8 @@ class TestSchleuderApi(unittest.TestCase): sub = SchleuderSubscriber(23, 'foo@example.org', key, 42, now) api.subscribe(sub, SchleuderList(42, '', '')) self.assertEqual('https://localhost:4443/subscriptions.json?list_id=42', - mock.call_args_list[0][0][0].get_full_url()) - self.assertEqual('POST', mock.call_args_list[0][0][0].method) + mock.call_args_list[-1][0][0].get_full_url()) + self.assertEqual('POST', mock.call_args_list[-1][0][0].method) # todo assert request payload @patch('urllib.request.urlopen') @@ -163,10 +177,10 @@ class TestSchleuderApi(unittest.TestCase): now = datetime.utcnow() key = SchleuderKey('2FBBC0DF97FDBF1E4B704EEDE39EF4FAC420BEB6', 'foo@example.org', 'verylongpgpkeyblock', 42) sub = SchleuderSubscriber(23, 'foo@example.org', key, 42, now) - api.unsubscribe(sub) + api.unsubscribe(sub, SchleuderList(42, '', '')) self.assertEqual('https://localhost:4443/subscriptions/23.json', - mock.call_args_list[0][0][0].get_full_url()) - self.assertEqual('DELETE', mock.call_args_list[0][0][0].method) + mock.call_args_list[-1][0][0].get_full_url()) + self.assertEqual('DELETE', mock.call_args_list[-1][0][0].method) # todo assert request payload @patch('urllib.request.urlopen') @@ -175,10 +189,10 @@ class TestSchleuderApi(unittest.TestCase): now = datetime.utcnow() key = SchleuderKey('2FBBC0DF97FDBF1E4B704EEDE39EF4FAC420BEB6', 'foo@example.org', 'verylongpgpkeyblock', 42) sub = SchleuderSubscriber(23, 'foo@example.org', key, 42, now) - api.update_fingerprint(sub) + api.update_fingerprint(sub, SchleuderList(42, '', '')) self.assertEqual('https://localhost:4443/subscriptions/23.json', - mock.call_args_list[0][0][0].get_full_url()) - self.assertEqual('PATCH', mock.call_args_list[0][0][0].method) + mock.call_args_list[-1][0][0].get_full_url()) + self.assertEqual('PATCH', mock.call_args_list[-1][0][0].method) # todo assert request payload @patch('urllib.request.urlopen') @@ -220,15 +234,15 @@ class TestSchleuderApi(unittest.TestCase): key = SchleuderKey('2FBBC0DF97FDBF1E4B704EEDE39EF4FAC420BEB6', 'foo@example.org', 'verylongpgpkeyblock', 42) sub = SchleuderSubscriber(23, 'foo@example.org', key, 42, now) sch = SchleuderList(42, '', '') - # create, update, delete should be no-ops + # create, update, delete should be no-ops; 2 requests for retrieving the subscriptions in unsub & update api.subscribe(sub, sch) - api.unsubscribe(sub) - api.update_fingerprint(sub) + api.unsubscribe(sub, sch) + api.update_fingerprint(sub, sch) api.post_key(key, SchleuderList(42, '', '')) api.delete_key(key, SchleuderList(42, '', '')) - self.assertEqual(0, len(mock.call_args_list)) + self.assertGreater(3, len(mock.call_args_list)) # only reads should execute api.get_lists() api.get_subscribers(sch) api.get_key('2FBBC0DF97FDBF1E4B704EEDE39EF4FAC420BEB6', sch) - self.assertLess(0, len(mock.call_args_list)) + self.assertLess(2, len(mock.call_args_list))