aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Joe Banks <[email protected]>2020-10-31 00:01:34 +0000
committerGravatar GitHub <[email protected]>2020-10-31 00:01:34 +0000
commitc28aab2ffa7c3fc5546125d92e03b43a09752ab2 (patch)
tree3c85f9e4d6eed6d3401189029773673f5c834ab2
parentUse referral code for Linode (diff)
parentIndent 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.sql9
-rw-r--r--pydis_site/apps/api/models/bot/metricity.py31
-rw-r--r--pydis_site/apps/api/tests/test_users.py10
-rw-r--r--pydis_site/apps/api/viewsets/bot/user.py5
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"),