aboutsummaryrefslogtreecommitdiffstats
path: root/pydis_site/apps/api
diff options
context:
space:
mode:
Diffstat (limited to 'pydis_site/apps/api')
-rw-r--r--pydis_site/apps/api/migrations/0053_user_roles_to_array.py24
-rw-r--r--pydis_site/apps/api/migrations/0054_user_invalidate_unknown_role.py21
-rw-r--r--pydis_site/apps/api/models/bot/user.py29
-rw-r--r--pydis_site/apps/api/serializers.py2
-rw-r--r--pydis_site/apps/api/tests/test_users.py2
-rw-r--r--pydis_site/apps/api/viewsets/bot/user.py2
6 files changed, 71 insertions, 9 deletions
diff --git a/pydis_site/apps/api/migrations/0053_user_roles_to_array.py b/pydis_site/apps/api/migrations/0053_user_roles_to_array.py
new file mode 100644
index 00000000..7ff3a548
--- /dev/null
+++ b/pydis_site/apps/api/migrations/0053_user_roles_to_array.py
@@ -0,0 +1,24 @@
+# Generated by Django 2.2.11 on 2020-06-02 13:42
+
+import django.contrib.postgres.fields
+import django.core.validators
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0052_remove_user_avatar_hash'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='user',
+ name='roles',
+ ),
+ migrations.AddField(
+ model_name='user',
+ name='roles',
+ field=django.contrib.postgres.fields.ArrayField(base_field=models.BigIntegerField(validators=[django.core.validators.MinValueValidator(limit_value=0, message='Role IDs cannot be negative.')]), default=list, help_text='IDs of roles the user has on the server', size=None),
+ ),
+ ]
diff --git a/pydis_site/apps/api/migrations/0054_user_invalidate_unknown_role.py b/pydis_site/apps/api/migrations/0054_user_invalidate_unknown_role.py
new file mode 100644
index 00000000..96230015
--- /dev/null
+++ b/pydis_site/apps/api/migrations/0054_user_invalidate_unknown_role.py
@@ -0,0 +1,21 @@
+# Generated by Django 2.2.11 on 2020-06-02 20:08
+
+import django.contrib.postgres.fields
+import django.core.validators
+from django.db import migrations, models
+import pydis_site.apps.api.models.bot.user
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('api', '0053_user_roles_to_array'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='user',
+ name='roles',
+ field=django.contrib.postgres.fields.ArrayField(base_field=models.BigIntegerField(validators=[django.core.validators.MinValueValidator(limit_value=0, message='Role IDs cannot be negative.'), pydis_site.apps.api.models.bot.user._validate_existing_role]), default=list, help_text='IDs of roles the user has on the server', size=None),
+ ),
+ ]
diff --git a/pydis_site/apps/api/models/bot/user.py b/pydis_site/apps/api/models/bot/user.py
index 65e8751e..bff4d642 100644
--- a/pydis_site/apps/api/models/bot/user.py
+++ b/pydis_site/apps/api/models/bot/user.py
@@ -1,3 +1,5 @@
+from django.contrib.postgres.fields import ArrayField
+from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
@@ -5,6 +7,14 @@ from pydis_site.apps.api.models.bot.role import Role
from pydis_site.apps.api.models.utils import ModelReprMixin
+def _validate_existing_role(value: int) -> None:
+ """Validate that a role exists when given in to the user model."""
+ role = Role.objects.filter(id=value)
+
+ if not role:
+ raise ValidationError(f"Role with ID {value} does not exist")
+
+
class User(ModelReprMixin, models.Model):
"""A Discord user."""
@@ -31,9 +41,18 @@ class User(ModelReprMixin, models.Model):
),
help_text="The discriminator of this user, taken from Discord."
)
- roles = models.ManyToManyField(
- Role,
- help_text="Any roles this user has on our server."
+ roles = ArrayField(
+ models.BigIntegerField(
+ validators=(
+ MinValueValidator(
+ limit_value=0,
+ message="Role IDs cannot be negative."
+ ),
+ _validate_existing_role
+ )
+ ),
+ default=list,
+ help_text="IDs of roles the user has on the server"
)
in_guild = models.BooleanField(
default=True,
@@ -51,7 +70,7 @@ class User(ModelReprMixin, models.Model):
This will fall back to the Developers role if the user does not have any roles.
"""
- roles = self.roles.all()
+ roles = Role.objects.filter(id__in=self.roles)
if not roles:
return Role.objects.get(name="Developers")
- return max(self.roles.all())
+ return max(roles)
diff --git a/pydis_site/apps/api/serializers.py b/pydis_site/apps/api/serializers.py
index cc3f167d..f2d5144c 100644
--- a/pydis_site/apps/api/serializers.py
+++ b/pydis_site/apps/api/serializers.py
@@ -229,8 +229,6 @@ class TagSerializer(ModelSerializer):
class UserSerializer(BulkSerializerMixin, ModelSerializer):
"""A class providing (de-)serialization of `User` instances."""
- roles = PrimaryKeyRelatedField(many=True, queryset=Role.objects.all(), required=False)
-
class Meta:
"""Metadata defined for the Django REST Framework."""
diff --git a/pydis_site/apps/api/tests/test_users.py b/pydis_site/apps/api/tests/test_users.py
index 4f563dc6..4c0f6e27 100644
--- a/pydis_site/apps/api/tests/test_users.py
+++ b/pydis_site/apps/api/tests/test_users.py
@@ -146,7 +146,7 @@ class UserModelTests(APISubdomainTestCase):
discriminator=1111,
in_guild=True,
)
- cls.user_with_roles.roles.add(cls.role_bottom, cls.role_top)
+ cls.user_with_roles.roles.extend([cls.role_bottom.id, cls.role_top.id])
cls.user_without_roles = User.objects.create(
id=2,
diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py
index 8f5bccfa..9571b3d7 100644
--- a/pydis_site/apps/api/viewsets/bot/user.py
+++ b/pydis_site/apps/api/viewsets/bot/user.py
@@ -118,4 +118,4 @@ class UserViewSet(BulkCreateModelMixin, ModelViewSet):
"""
serializer_class = UserSerializer
- queryset = User.objects.prefetch_related('roles')
+ queryset = User.objects