diff options
author | 2020-10-31 00:01:34 +0000 | |
---|---|---|
committer | 2020-10-31 00:01:34 +0000 | |
commit | c28aab2ffa7c3fc5546125d92e03b43a09752ab2 (patch) | |
tree | 3c85f9e4d6eed6d3401189029773673f5c834ab2 | |
parent | Use referral code for Linode (diff) | |
parent | Indent metricity block query correctly (diff) |
Merge pull request #418 from python-discord/metricity/add-activity-blocks
Add activity blocks to Metricity data endpoint
-rw-r--r-- | postgres/init.sql | 9 | ||||
-rw-r--r-- | pydis_site/apps/api/models/bot/metricity.py | 31 | ||||
-rw-r--r-- | pydis_site/apps/api/tests/test_users.py | 10 | ||||
-rw-r--r-- | pydis_site/apps/api/viewsets/bot/user.py | 5 |
4 files changed, 48 insertions, 7 deletions
diff --git a/postgres/init.sql b/postgres/init.sql index 922ce1ad..75a9154c 100644 --- a/postgres/init.sql +++ b/postgres/init.sql @@ -16,15 +16,18 @@ INSERT INTO users VALUES ( CREATE TABLE messages ( id varchar, author_id varchar references users(id), - primary key(id) + primary key(id), + is_deleted boolean ); INSERT INTO messages VALUES( 0, - 0 + 0, + false ); INSERT INTO messages VALUES( 1, - 0 + 0, + false ); diff --git a/pydis_site/apps/api/models/bot/metricity.py b/pydis_site/apps/api/models/bot/metricity.py index eed1deb4..e7fc92fc 100644 --- a/pydis_site/apps/api/models/bot/metricity.py +++ b/pydis_site/apps/api/models/bot/metricity.py @@ -1,5 +1,7 @@ from django.db import connections +BLOCK_INTERVAL = 10 * 60 # 10 minute blocks + class NotFound(Exception): """Raised when an entity cannot be found.""" @@ -43,3 +45,32 @@ class Metricity: raise NotFound() return values[0] + + def total_message_blocks(self, user_id: str) -> int: + """ + Query number of 10 minute blocks during which the user has been active. + + This metric prevents users from spamming to achieve the message total threshold. + """ + self.cursor.execute( + """ + SELECT + COUNT(*) + FROM ( + SELECT + (floor((extract('epoch' from created_at) / %d )) * %d) AS interval + FROM messages + WHERE + author_id='%s' + AND NOT is_deleted + GROUP BY interval + ) block_query; + """, + [BLOCK_INTERVAL, BLOCK_INTERVAL, user_id] + ) + values = self.cursor.fetchone() + + if not values: + raise NotFound() + + return values[0] diff --git a/pydis_site/apps/api/tests/test_users.py b/pydis_site/apps/api/tests/test_users.py index 72ffcb3c..c422f895 100644 --- a/pydis_site/apps/api/tests/test_users.py +++ b/pydis_site/apps/api/tests/test_users.py @@ -409,7 +409,8 @@ class UserMetricityTests(APISubdomainTestCase): # Given verified_at = "foo" total_messages = 1 - self.mock_metricity_user(verified_at, total_messages) + total_blocks = 1 + self.mock_metricity_user(verified_at, total_messages, total_blocks) # When url = reverse('bot:user-metricity-data', args=[0], host='api') @@ -421,6 +422,7 @@ class UserMetricityTests(APISubdomainTestCase): "verified_at": verified_at, "total_messages": total_messages, "voice_banned": False, + "activity_blocks": total_blocks }) def test_no_metricity_user(self): @@ -440,7 +442,7 @@ class UserMetricityTests(APISubdomainTestCase): {'exception': ObjectDoesNotExist, 'voice_banned': False}, ] - self.mock_metricity_user("foo", 1) + self.mock_metricity_user("foo", 1, 1) for case in cases: with self.subTest(exception=case['exception'], voice_banned=case['voice_banned']): @@ -453,13 +455,14 @@ class UserMetricityTests(APISubdomainTestCase): self.assertEqual(response.status_code, 200) self.assertEqual(response.json()["voice_banned"], case["voice_banned"]) - def mock_metricity_user(self, verified_at, total_messages): + def mock_metricity_user(self, verified_at, total_messages, total_blocks): patcher = patch("pydis_site.apps.api.viewsets.bot.user.Metricity") self.metricity = patcher.start() self.addCleanup(patcher.stop) self.metricity = self.metricity.return_value.__enter__.return_value self.metricity.user.return_value = dict(verified_at=verified_at) self.metricity.total_messages.return_value = total_messages + self.metricity.total_message_blocks.return_value = total_blocks def mock_no_metricity_user(self): patcher = patch("pydis_site.apps.api.viewsets.bot.user.Metricity") @@ -468,3 +471,4 @@ class UserMetricityTests(APISubdomainTestCase): self.metricity = self.metricity.return_value.__enter__.return_value self.metricity.user.side_effect = NotFound() self.metricity.total_messages.side_effect = NotFound() + self.metricity.total_message_blocks.side_effect = NotFound() diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py index 5205dc97..79f90163 100644 --- a/pydis_site/apps/api/viewsets/bot/user.py +++ b/pydis_site/apps/api/viewsets/bot/user.py @@ -110,7 +110,9 @@ class UserViewSet(ModelViewSet): #### Response format >>> { ... "verified_at": "2020-10-06T21:54:23.540766", - ... "total_messages": 2 + ... "total_messages": 2, + ... "voice_banned": False, + ... "activity_blocks": 1 ...} #### Status codes @@ -255,6 +257,7 @@ class UserViewSet(ModelViewSet): data = metricity.user(user.id) data["total_messages"] = metricity.total_messages(user.id) data["voice_banned"] = voice_banned + data["activity_blocks"] = metricity.total_message_blocks(user.id) return Response(data, status=status.HTTP_200_OK) except NotFound: return Response(dict(detail="User not found in metricity"), |