aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/apps/api/models
diff options
context:
space:
mode:
authorGravatar ChrisJL <[email protected]>2021-05-16 18:42:50 +0100
committerGravatar GitHub <[email protected]>2021-05-16 18:42:50 +0100
commit8c7c3b137fb6c60818d29ac3d14ebb397357ee0e (patch)
treefec5581d5e27fc860db6424f7c1d6a3a71565693 /pydis_site/apps/api/models
parentResolve conflicts (diff)
parentMerge pull request #501 from python-discord/update/sir-lancebot-env-vars (diff)
Merge branch 'main' into fix_327
Diffstat (limited to 'pydis_site/apps/api/models')
-rw-r--r--pydis_site/apps/api/models/__init__.py1
-rw-r--r--pydis_site/apps/api/models/bot/__init__.py2
-rw-r--r--pydis_site/apps/api/models/bot/documentation_link.py17
-rw-r--r--pydis_site/apps/api/models/bot/metricity.py41
-rw-r--r--pydis_site/apps/api/models/bot/nomination.py52
5 files changed, 99 insertions, 14 deletions
diff --git a/pydis_site/apps/api/models/__init__.py b/pydis_site/apps/api/models/__init__.py
index 0a8c90f6..fd5bf220 100644
--- a/pydis_site/apps/api/models/__init__.py
+++ b/pydis_site/apps/api/models/__init__.py
@@ -8,6 +8,7 @@ from .bot import (
Message,
MessageDeletionContext,
Nomination,
+ NominationEntry,
OffensiveMessage,
OffTopicChannelName,
Reminder,
diff --git a/pydis_site/apps/api/models/bot/__init__.py b/pydis_site/apps/api/models/bot/__init__.py
index 1673b434..ac864de3 100644
--- a/pydis_site/apps/api/models/bot/__init__.py
+++ b/pydis_site/apps/api/models/bot/__init__.py
@@ -6,7 +6,7 @@ from .documentation_link import DocumentationLink
from .infraction import Infraction
from .message import Message
from .message_deletion_context import MessageDeletionContext
-from .nomination import Nomination
+from .nomination import Nomination, NominationEntry
from .off_topic_channel_name import OffTopicChannelName
from .offensive_message import OffensiveMessage
from .reminder import Reminder
diff --git a/pydis_site/apps/api/models/bot/documentation_link.py b/pydis_site/apps/api/models/bot/documentation_link.py
index 2a0ce751..3dcc71fc 100644
--- a/pydis_site/apps/api/models/bot/documentation_link.py
+++ b/pydis_site/apps/api/models/bot/documentation_link.py
@@ -1,7 +1,20 @@
+from django.core.exceptions import ValidationError
+from django.core.validators import RegexValidator
from django.db import models
from pydis_site.apps.api.models.mixins import ModelReprMixin
+package_name_validator = RegexValidator(
+ regex=r"^[a-z0-9_]+$",
+ message="Package names can only consist of lowercase a-z letters, digits, and underscores."
+)
+
+
+def ends_with_slash_validator(string: str) -> None:
+ """Raise a ValidationError if `string` does not end with a slash."""
+ if not string.endswith("/"):
+ raise ValidationError("The entered URL must end with a slash.")
+
class DocumentationLink(ModelReprMixin, models.Model):
"""A documentation link used by the `!docs` command of the bot."""
@@ -9,13 +22,15 @@ class DocumentationLink(ModelReprMixin, models.Model):
package = models.CharField(
primary_key=True,
max_length=50,
+ validators=(package_name_validator,),
help_text="The Python package name that this documentation link belongs to."
)
base_url = models.URLField(
help_text=(
"The base URL from which documentation will be available for this project. "
"Used to generate links to various symbols within this package."
- )
+ ),
+ validators=(ends_with_slash_validator,)
)
inventory_url = models.URLField(
help_text="The URL at which the Sphinx inventory is available for this package."
diff --git a/pydis_site/apps/api/models/bot/metricity.py b/pydis_site/apps/api/models/bot/metricity.py
index cae630f1..5daa5c66 100644
--- a/pydis_site/apps/api/models/bot/metricity.py
+++ b/pydis_site/apps/api/models/bot/metricity.py
@@ -1,3 +1,5 @@
+from typing import List, Tuple
+
from django.db import connections
BLOCK_INTERVAL = 10 * 60 # 10 minute blocks
@@ -89,3 +91,42 @@ class Metricity:
raise NotFound()
return values[0]
+
+ def top_channel_activity(self, user_id: str) -> List[Tuple[str, int]]:
+ """
+ Query the top three channels in which the user is most active.
+
+ Help channels are grouped under "the help channels",
+ and off-topic channels are grouped under "off-topic".
+ """
+ self.cursor.execute(
+ """
+ SELECT
+ CASE
+ WHEN channels.name ILIKE 'help-%%' THEN 'the help channels'
+ WHEN channels.name ILIKE 'ot%%' THEN 'off-topic'
+ WHEN channels.name ILIKE '%%voice%%' THEN 'voice chats'
+ ELSE channels.name
+ END,
+ COUNT(1)
+ FROM
+ messages
+ LEFT JOIN channels ON channels.id = messages.channel_id
+ WHERE
+ author_id = '%s' AND NOT messages.is_deleted
+ GROUP BY
+ 1
+ ORDER BY
+ 2 DESC
+ LIMIT
+ 3;
+ """,
+ [user_id]
+ )
+
+ values = self.cursor.fetchall()
+
+ if not values:
+ raise NotFound()
+
+ return values
diff --git a/pydis_site/apps/api/models/bot/nomination.py b/pydis_site/apps/api/models/bot/nomination.py
index 11b9e36e..221d8534 100644
--- a/pydis_site/apps/api/models/bot/nomination.py
+++ b/pydis_site/apps/api/models/bot/nomination.py
@@ -5,23 +5,12 @@ from pydis_site.apps.api.models.mixins import ModelReprMixin
class Nomination(ModelReprMixin, models.Model):
- """A helper nomination created by staff."""
+ """A general helper nomination information created by staff."""
active = models.BooleanField(
default=True,
help_text="Whether this nomination is still relevant."
)
- actor = models.ForeignKey(
- User,
- on_delete=models.CASCADE,
- help_text="The staff member that nominated this user.",
- related_name='nomination_set'
- )
- reason = models.TextField(
- help_text="Why this user was nominated.",
- null=True,
- blank=True
- )
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
@@ -42,6 +31,10 @@ class Nomination(ModelReprMixin, models.Model):
help_text="When the nomination was ended.",
null=True
)
+ reviewed = models.BooleanField(
+ default=False,
+ help_text="Whether a review was made."
+ )
def __str__(self):
"""Representation that makes the target and state of the nomination immediately evident."""
@@ -52,3 +45,38 @@ class Nomination(ModelReprMixin, models.Model):
"""Set the ordering of nominations to most recent first."""
ordering = ("-inserted_at",)
+
+
+class NominationEntry(ModelReprMixin, models.Model):
+ """A nomination entry created by a single staff member."""
+
+ nomination = models.ForeignKey(
+ Nomination,
+ on_delete=models.CASCADE,
+ help_text="The nomination this entry belongs to.",
+ related_name="entries"
+ )
+ actor = models.ForeignKey(
+ User,
+ on_delete=models.CASCADE,
+ help_text="The staff member that nominated this user.",
+ related_name='nomination_set'
+ )
+ reason = models.TextField(
+ help_text="Why the actor nominated this user.",
+ default="",
+ blank=True
+ )
+ inserted_at = models.DateTimeField(
+ auto_now_add=True,
+ help_text="The creation date of this nomination entry."
+ )
+
+ class Meta:
+ """Meta options for NominationEntry model."""
+
+ verbose_name_plural = "nomination entries"
+
+ # Set default ordering here to latest first
+ # so we don't need to define it everywhere
+ ordering = ("-inserted_at",)