From 2552f22a25913adbbc024dfe6b8948b5e7acd18f Mon Sep 17 00:00:00 2001 From: bendiller Date: Tue, 7 Jan 2020 03:14:22 -0700 Subject: Instantiate test_reminders module; implement UnauthedReminderAPITests --- pydis_site/apps/api/tests/test_reminders.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 pydis_site/apps/api/tests/test_reminders.py diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py new file mode 100644 index 00000000..55fb8000 --- /dev/null +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -0,0 +1,27 @@ +from django_hosts.resolvers import reverse + +from .base import APISubdomainTestCase + + +class UnauthedReminderAPITests(APISubdomainTestCase): + def setUp(self): + super().setUp() + self.client.force_authenticate(user=None) + + def test_list_returns_401(self): + url = reverse('bot:reminder-list', host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 401) + + def test_create_returns_401(self): + url = reverse('bot:reminder-list', host='api') + response = self.client.post(url, data={'not': 'important'}) + + self.assertEqual(response.status_code, 401) + + def test_delete_returns_401(self): + url = reverse('bot:reminder-detail', args=('1234',), host='api') + response = self.client.delete(url) + + self.assertEqual(response.status_code, 401) -- cgit v1.2.3 From 647a3576402cbcb83f2998e0277c2d4774d55ee8 Mon Sep 17 00:00:00 2001 From: bendiller Date: Tue, 7 Jan 2020 03:14:56 -0700 Subject: Implement EmptyDatabaseReminderAPITests --- pydis_site/apps/api/tests/test_reminders.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index 55fb8000..01f6d8e4 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -25,3 +25,18 @@ class UnauthedReminderAPITests(APISubdomainTestCase): response = self.client.delete(url) self.assertEqual(response.status_code, 401) + + +class EmptyDatabaseReminderAPITests(APISubdomainTestCase): + def test_list_all_returns_empty_list(self): + url = reverse('bot:reminder-list', host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), []) + + def test_delete_returns_404(self): + url = reverse('bot:reminder-detail', args=('1234',), host='api') + response = self.client.delete(url) + + self.assertEqual(response.status_code, 404) -- cgit v1.2.3 From 74c03c067ec17324bee83a633ff8b4dca0c3a8aa Mon Sep 17 00:00:00 2001 From: bendiller Date: Mon, 13 Jan 2020 06:59:44 -0700 Subject: Implement ReminderCreationTests --- pydis_site/apps/api/tests/test_reminders.py | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index 01f6d8e4..cb5e5867 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -1,6 +1,9 @@ +from datetime import datetime + from django_hosts.resolvers import reverse from .base import APISubdomainTestCase +from ..models import User class UnauthedReminderAPITests(APISubdomainTestCase): @@ -40,3 +43,35 @@ class EmptyDatabaseReminderAPITests(APISubdomainTestCase): response = self.client.delete(url) self.assertEqual(response.status_code, 404) + + +class ReminderCreationTests(APISubdomainTestCase): + def setUp(self): + super().setUp() + self.author = User.objects.create( + id=1234, + name='Mermaid Man', + discriminator=1234, + avatar_hash=None, + ) + self.data = { + 'author': self.author.id, + 'content': 'Remember to...wait what was it again?', + 'expiration': datetime.utcnow().isoformat(), + 'jump_url': "https://www.google.com", + 'channel_id': 123, + } + url = reverse('bot:reminder-list', host='api') + response = self.client.post(url, data=self.data) + self.assertEqual(response.status_code, 201) + + def test_reminder_in_full_list(self): + url = reverse('bot:reminder-list', host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + + self.data['expiration'] += 'Z' # Massaging a quirk of the response time format + self.data['active'] = True + self.data['id'] = 1 + self.assertEqual(response.json(), [self.data]) -- cgit v1.2.3 From 1301b2274f9f9d0fcaa2e6632d47737a92a1e741 Mon Sep 17 00:00:00 2001 From: bendiller Date: Mon, 13 Jan 2020 10:17:54 -0700 Subject: Implement ReminderDeletionTests --- pydis_site/apps/api/tests/test_reminders.py | 33 ++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index cb5e5867..e1bd95de 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -3,7 +3,7 @@ from datetime import datetime from django_hosts.resolvers import reverse from .base import APISubdomainTestCase -from ..models import User +from ..models import Reminder, User class UnauthedReminderAPITests(APISubdomainTestCase): @@ -75,3 +75,34 @@ class ReminderCreationTests(APISubdomainTestCase): self.data['active'] = True self.data['id'] = 1 self.assertEqual(response.json(), [self.data]) + + +class ReminderDeletionTests(APISubdomainTestCase): + @classmethod + def setUpTestData(cls): + cls.author = User.objects.create( + id=6789, + name='Barnacle Boy', + discriminator=6789, + avatar_hash=None, + ) + + cls.reminder = Reminder.objects.create( + author=cls.author, + content="Don't forget to set yourself a reminder", + expiration= datetime.utcnow().isoformat(), + jump_url="https://www.decliningmentalfaculties.com", + channel_id=123 + ) + + def test_delete_unknown_reminder_returns_404(self): + url = reverse('bot:reminder-detail', args=('something',), host='api') + response = self.client.delete(url) + + self.assertEqual(response.status_code, 404) + + def test_delete_known_reminder_returns_204(self): + url = reverse('bot:reminder-detail', args=(self.reminder.id,), host='api') + response = self.client.delete(url) + + self.assertEqual(response.status_code, 204) -- cgit v1.2.3 From 3ae762e826d3ff09cc0c795a709f2fa1e8f29a6a Mon Sep 17 00:00:00 2001 From: bendiller Date: Mon, 13 Jan 2020 11:58:05 -0700 Subject: Implement ReminderUpdateTests --- pydis_site/apps/api/tests/test_reminders.py | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index e1bd95de..d79dbffc 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -106,3 +106,34 @@ class ReminderDeletionTests(APISubdomainTestCase): response = self.client.delete(url) self.assertEqual(response.status_code, 204) + + +class ReminderUpdateTests(APISubdomainTestCase): + @classmethod + def setUpTestData(cls): + cls.author = User.objects.create( + id=666, + name='Man Ray', + discriminator=666, + avatar_hash=None, + ) + + cls.reminder = Reminder.objects.create( + author=cls.author, + content="Squash those do-gooders", + expiration=datetime.utcnow().isoformat(), + jump_url="https://www.decliningmentalfaculties.com", + channel_id=123 + ) + + cls.data = {'content': 'Oops I forgot'} + + def test_patch_updates_record(self): + url = reverse('bot:reminder-detail', args=(self.reminder.id,), host='api') + response = self.client.patch(url, data=self.data) + self.assertEqual(response.status_code, 200) + + url = reverse('bot:reminder-list', host='api') + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json()[0]['content'], self.data['content']) -- cgit v1.2.3 From 02d2ce00b05facec9f6d34d5c854cd7f72e94b58 Mon Sep 17 00:00:00 2001 From: bendiller Date: Mon, 13 Jan 2020 11:58:40 -0700 Subject: Tiny linting edit --- pydis_site/apps/api/tests/test_reminders.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index d79dbffc..97742544 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -90,7 +90,7 @@ class ReminderDeletionTests(APISubdomainTestCase): cls.reminder = Reminder.objects.create( author=cls.author, content="Don't forget to set yourself a reminder", - expiration= datetime.utcnow().isoformat(), + expiration=datetime.utcnow().isoformat(), jump_url="https://www.decliningmentalfaculties.com", channel_id=123 ) -- cgit v1.2.3 From b1801cfabb7a7ade3f67b86a14a64bc48cb59bf7 Mon Sep 17 00:00:00 2001 From: bendiller Date: Sun, 2 Feb 2020 12:00:59 -0700 Subject: Rework ReminderCreationTests --- pydis_site/apps/api/tests/test_reminders.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index 97742544..29430f40 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -46,15 +46,17 @@ class EmptyDatabaseReminderAPITests(APISubdomainTestCase): class ReminderCreationTests(APISubdomainTestCase): - def setUp(self): - super().setUp() - self.author = User.objects.create( + @classmethod + def setUpTestData(cls): + cls.author = User.objects.create( id=1234, name='Mermaid Man', discriminator=1234, avatar_hash=None, ) - self.data = { + + def test_accepts_valid_data(self): + data = { 'author': self.author.id, 'content': 'Remember to...wait what was it again?', 'expiration': datetime.utcnow().isoformat(), @@ -62,19 +64,18 @@ class ReminderCreationTests(APISubdomainTestCase): 'channel_id': 123, } url = reverse('bot:reminder-list', host='api') - response = self.client.post(url, data=self.data) + response = self.client.post(url, data=data) self.assertEqual(response.status_code, 201) + self.assertIsNotNone(Reminder.objects.get(id=1)) - def test_reminder_in_full_list(self): + def test_rejects_invalid_data(self): + data = { + 'author': self.author.id, # Missing multiple required fields + } url = reverse('bot:reminder-list', host='api') - response = self.client.get(url) - - self.assertEqual(response.status_code, 200) - - self.data['expiration'] += 'Z' # Massaging a quirk of the response time format - self.data['active'] = True - self.data['id'] = 1 - self.assertEqual(response.json(), [self.data]) + response = self.client.post(url, data=data) + self.assertEqual(response.status_code, 400) + self.assertRaises(Reminder.DoesNotExist, Reminder.objects.get, **{'id': 1}) class ReminderDeletionTests(APISubdomainTestCase): -- cgit v1.2.3 From 9663690bc34ef363e62fa2b63012f1bd8f9a8a47 Mon Sep 17 00:00:00 2001 From: bendiller Date: Sun, 2 Feb 2020 12:48:06 -0700 Subject: Rework test_patch_updates_record to avoid list API endpoint --- pydis_site/apps/api/tests/test_reminders.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index 29430f40..06a194c1 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -132,9 +132,6 @@ class ReminderUpdateTests(APISubdomainTestCase): def test_patch_updates_record(self): url = reverse('bot:reminder-detail', args=(self.reminder.id,), host='api') response = self.client.patch(url, data=self.data) - self.assertEqual(response.status_code, 200) - url = reverse('bot:reminder-list', host='api') - response = self.client.get(url) self.assertEqual(response.status_code, 200) - self.assertEqual(response.json()[0]['content'], self.data['content']) + self.assertEqual(Reminder.objects.get(id=self.reminder.id).content, self.data['content']) -- cgit v1.2.3 From ba5532eaf2eb2ceef938d19e5c78af5129dc66e2 Mon Sep 17 00:00:00 2001 From: bendiller Date: Sun, 2 Feb 2020 12:51:42 -0700 Subject: Improve deletion test (asserting that deleted record no longer exists) --- pydis_site/apps/api/tests/test_reminders.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index 06a194c1..a06a5974 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -107,6 +107,7 @@ class ReminderDeletionTests(APISubdomainTestCase): response = self.client.delete(url) self.assertEqual(response.status_code, 204) + self.assertRaises(Reminder.DoesNotExist, Reminder.objects.get, **{'id': self.reminder.id}) class ReminderUpdateTests(APISubdomainTestCase): -- cgit v1.2.3 From dd7297c33850b6ac5d966b66a91aaca6b3448a2b Mon Sep 17 00:00:00 2001 From: bendiller Date: Sun, 2 Feb 2020 13:55:08 -0700 Subject: Add ReminderListTests --- pydis_site/apps/api/tests/test_reminders.py | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index a06a5974..fdbc829e 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -1,5 +1,6 @@ from datetime import datetime +from django.forms.models import model_to_dict from django_hosts.resolvers import reverse from .base import APISubdomainTestCase @@ -110,6 +111,42 @@ class ReminderDeletionTests(APISubdomainTestCase): self.assertRaises(Reminder.DoesNotExist, Reminder.objects.get, **{'id': self.reminder.id}) +class ReminderListTests(APISubdomainTestCase): + @classmethod + def setUpTestData(cls): + cls.author = User.objects.create( + id=6789, + name='Patrick Star', + discriminator=6789, + avatar_hash=None, + ) + + cls.reminder = Reminder.objects.create( + author=cls.author, + content="We should take Bikini Bottom, and push it somewhere else!", + expiration=datetime.utcnow().isoformat(), + jump_url="https://www.icantseemyforehead.com", + channel_id=123 + ) + + cls.rem_dict = model_to_dict(cls.reminder) + cls.rem_dict['expiration'] += 'Z' # Massaging a quirk of the response time format + + def test_reminder_in_full_list(self): + url = reverse('bot:reminder-list', host='api') + response = self.client.get(url) + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), [self.rem_dict]) + + def test_filter_search(self): + url = reverse('bot:reminder-list', host='api') + response = self.client.get(f'{url}?search={self.author.name}') + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), [self.rem_dict]) + + class ReminderUpdateTests(APISubdomainTestCase): @classmethod def setUpTestData(cls): -- cgit v1.2.3 From 1c5a1b9ba6850272cd1a521f75d455ce60f86c51 Mon Sep 17 00:00:00 2001 From: bendiller Date: Mon, 3 Feb 2020 08:38:08 -0700 Subject: Fix unnecessary kwarg syntax --- pydis_site/apps/api/tests/test_reminders.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index fdbc829e..33b705b0 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -76,7 +76,7 @@ class ReminderCreationTests(APISubdomainTestCase): url = reverse('bot:reminder-list', host='api') response = self.client.post(url, data=data) self.assertEqual(response.status_code, 400) - self.assertRaises(Reminder.DoesNotExist, Reminder.objects.get, **{'id': 1}) + self.assertRaises(Reminder.DoesNotExist, Reminder.objects.get, id=1) class ReminderDeletionTests(APISubdomainTestCase): @@ -108,7 +108,7 @@ class ReminderDeletionTests(APISubdomainTestCase): response = self.client.delete(url) self.assertEqual(response.status_code, 204) - self.assertRaises(Reminder.DoesNotExist, Reminder.objects.get, **{'id': self.reminder.id}) + self.assertRaises(Reminder.DoesNotExist, Reminder.objects.get, id=self.reminder.id) class ReminderListTests(APISubdomainTestCase): -- cgit v1.2.3 From b0068347e3aefe49ab68c4af653df9d14564df5b Mon Sep 17 00:00:00 2001 From: bendiller Date: Mon, 3 Feb 2020 08:48:23 -0700 Subject: Improve test failure clarity (reduce unhandled exceptions in assertions) --- pydis_site/apps/api/tests/test_reminders.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index 33b705b0..618e4e54 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -67,7 +67,7 @@ class ReminderCreationTests(APISubdomainTestCase): url = reverse('bot:reminder-list', host='api') response = self.client.post(url, data=data) self.assertEqual(response.status_code, 201) - self.assertIsNotNone(Reminder.objects.get(id=1)) + self.assertIsNotNone(Reminder.objects.filter(id=1).first()) def test_rejects_invalid_data(self): data = { @@ -172,4 +172,4 @@ class ReminderUpdateTests(APISubdomainTestCase): response = self.client.patch(url, data=self.data) self.assertEqual(response.status_code, 200) - self.assertEqual(Reminder.objects.get(id=self.reminder.id).content, self.data['content']) + self.assertEqual(Reminder.objects.filter(id=self.reminder.id).first().content, self.data['content']) -- cgit v1.2.3 From 254d7ac7354f5bb1f7e23efb6faa04a221b3d907 Mon Sep 17 00:00:00 2001 From: bendiller Date: Mon, 3 Feb 2020 08:50:38 -0700 Subject: Improve test failure clarity (reduce unhandled exceptions in assertions) --- pydis_site/apps/api/tests/test_reminders.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index 618e4e54..f3dd5eec 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -172,4 +172,7 @@ class ReminderUpdateTests(APISubdomainTestCase): response = self.client.patch(url, data=self.data) self.assertEqual(response.status_code, 200) - self.assertEqual(Reminder.objects.filter(id=self.reminder.id).first().content, self.data['content']) + self.assertEqual( + Reminder.objects.filter(id=self.reminder.id).first().content, + self.data['content'] + ) -- cgit v1.2.3 From 410460f92a49f05f7ec667a83651ff175e1a07f7 Mon Sep 17 00:00:00 2001 From: bendiller Date: Mon, 3 Feb 2020 10:07:43 -0700 Subject: Add second reminder to list tests, implement `test_filter_field` test --- pydis_site/apps/api/tests/test_reminders.py | 30 +++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index f3dd5eec..83b992f7 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -121,7 +121,7 @@ class ReminderListTests(APISubdomainTestCase): avatar_hash=None, ) - cls.reminder = Reminder.objects.create( + cls.reminder_one = Reminder.objects.create( author=cls.author, content="We should take Bikini Bottom, and push it somewhere else!", expiration=datetime.utcnow().isoformat(), @@ -129,22 +129,40 @@ class ReminderListTests(APISubdomainTestCase): channel_id=123 ) - cls.rem_dict = model_to_dict(cls.reminder) - cls.rem_dict['expiration'] += 'Z' # Massaging a quirk of the response time format + cls.reminder_two = Reminder.objects.create( + author=cls.author, + content="Gahhh-I love being purple!", + expiration=datetime.utcnow().isoformat(), + jump_url="https://www.goofygoobersicecreampartyboat.com", + channel_id=123, + active=False + ) + + cls.rem_dict_one = model_to_dict(cls.reminder_one) + cls.rem_dict_one['expiration'] += 'Z' # Massaging a quirk of the response time format + cls.rem_dict_two = model_to_dict(cls.reminder_two) + cls.rem_dict_two['expiration'] += 'Z' # Massaging a quirk of the response time format - def test_reminder_in_full_list(self): + def test_reminders_in_full_list(self): url = reverse('bot:reminder-list', host='api') response = self.client.get(url) self.assertEqual(response.status_code, 200) - self.assertEqual(response.json(), [self.rem_dict]) + self.assertEqual(response.json(), [self.rem_dict_one, self.rem_dict_two]) def test_filter_search(self): url = reverse('bot:reminder-list', host='api') response = self.client.get(f'{url}?search={self.author.name}') self.assertEqual(response.status_code, 200) - self.assertEqual(response.json(), [self.rem_dict]) + self.assertEqual(response.json(), [self.rem_dict_one, self.rem_dict_two]) + + def test_filter_field(self): + url = reverse('bot:reminder-list', host='api') + response = self.client.get(f'{url}?active=true') + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), [self.rem_dict_one]) class ReminderUpdateTests(APISubdomainTestCase): -- cgit v1.2.3 From 1b0f366827567d755fd4b6944090c83cad3269cb Mon Sep 17 00:00:00 2001 From: bendiller Date: Mon, 3 Feb 2020 14:23:35 -0700 Subject: Improve robustness with regard to ordering --- pydis_site/apps/api/tests/test_reminders.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pydis_site/apps/api/tests/test_reminders.py b/pydis_site/apps/api/tests/test_reminders.py index 83b992f7..3441e0cc 100644 --- a/pydis_site/apps/api/tests/test_reminders.py +++ b/pydis_site/apps/api/tests/test_reminders.py @@ -148,14 +148,14 @@ class ReminderListTests(APISubdomainTestCase): response = self.client.get(url) self.assertEqual(response.status_code, 200) - self.assertEqual(response.json(), [self.rem_dict_one, self.rem_dict_two]) + self.assertCountEqual(response.json(), [self.rem_dict_one, self.rem_dict_two]) def test_filter_search(self): url = reverse('bot:reminder-list', host='api') response = self.client.get(f'{url}?search={self.author.name}') self.assertEqual(response.status_code, 200) - self.assertEqual(response.json(), [self.rem_dict_one, self.rem_dict_two]) + self.assertCountEqual(response.json(), [self.rem_dict_one, self.rem_dict_two]) def test_filter_field(self): url = reverse('bot:reminder-list', host='api') -- cgit v1.2.3