diff options
-rw-r--r-- | api/models.py | 110 | ||||
-rw-r--r-- | api/tests/test_users.py | 2 | ||||
-rw-r--r-- | api/urls.py | 6 | ||||
-rw-r--r-- | api/viewsets.py | 106 |
4 files changed, 160 insertions, 64 deletions
diff --git a/api/models.py b/api/models.py index 3387e9be..21b5975a 100644 --- a/api/models.py +++ b/api/models.py @@ -60,6 +60,50 @@ class OffTopicChannelName(ModelReprMixin, models.Model): return self.name +class Role(ModelReprMixin, models.Model): + """A role on our Discord server.""" + + id = models.BigIntegerField( # noqa + primary_key=True, + validators=( + MinValueValidator( + limit_value=0, + message="Role IDs cannot be negative." + ), + ), + help_text="The role ID, taken from Discord." + ) + name = models.CharField( + max_length=100, + help_text="The role name, taken from Discord." + ) + colour = models.IntegerField( + validators=( + MinValueValidator( + limit_value=0, + message="Colour hex cannot be negative." + ), + ), + help_text="The integer value of the colour of this role from Discord." + ) + permissions = models.IntegerField( + validators=( + MinValueValidator( + limit_value=0, + message="Role permissions cannot be negative." + ), + MaxValueValidator( + limit_value=2 << 32, + message="Role permission bitset exceeds value of having all permissions" + ) + ), + help_text="The integer value of the permission bitset of this role from Discord." + ) + + def __str__(self): + return self.name + + class SnakeFact(ModelReprMixin, models.Model): """A snake fact used by the bot's snake cog.""" @@ -126,48 +170,24 @@ class SpecialSnake(ModelReprMixin, models.Model): return self.name -class Role(ModelReprMixin, models.Model): - """A role on our Discord server.""" +class Tag(ModelReprMixin, models.Model): + """A tag providing (hopefully) useful information.""" - id = models.BigIntegerField( # noqa - primary_key=True, - validators=( - MinValueValidator( - limit_value=0, - message="Role IDs cannot be negative." - ), - ), - help_text="The role ID, taken from Discord." - ) - name = models.CharField( + title = models.CharField( max_length=100, - help_text="The role name, taken from Discord." - ) - colour = models.IntegerField( - validators=( - MinValueValidator( - limit_value=0, - message="Colour hex cannot be negative." - ), + help_text=( + "The title of this tag, shown in searches and providing " + "a quick overview over what this embed contains." ), - help_text="The integer value of the colour of this role from Discord." + primary_key=True ) - permissions = models.IntegerField( - validators=( - MinValueValidator( - limit_value=0, - message="Role permissions cannot be negative." - ), - MaxValueValidator( - limit_value=2 << 32, - message="Role permission bitset exceeds value of having all permissions" - ) - ), - help_text="The integer value of the permission bitset of this role from Discord." + embed = pgfields.JSONField( + help_text="The actual embed shown by this tag.", + validators=(validate_tag_embed,) ) def __str__(self): - return self.name + return self.title class User(ModelReprMixin, models.Model): @@ -217,26 +237,6 @@ class User(ModelReprMixin, models.Model): return f"{self.name}#{self.discriminator}" -class Tag(ModelReprMixin, models.Model): - """A tag providing (hopefully) useful information.""" - - title = models.CharField( - max_length=100, - help_text=( - "The title of this tag, shown in searches and providing " - "a quick overview over what this embed contains." - ), - primary_key=True - ) - embed = pgfields.JSONField( - help_text="The actual embed shown by this tag.", - validators=(validate_tag_embed,) - ) - - def __str__(self): - return self.title - - class Infraction(ModelReprMixin, models.Model): """An infraction for a Discord user.""" diff --git a/api/tests/test_users.py b/api/tests/test_users.py index 8dadcbdb..90bc3d30 100644 --- a/api/tests/test_users.py +++ b/api/tests/test_users.py @@ -4,7 +4,7 @@ from .base import APISubdomainTestCase from ..models import Role, User -class UnauthedDocumentationLinkAPITests(APISubdomainTestCase): +class UnauthedUserAPITests(APISubdomainTestCase): def setUp(self): super().setUp() self.client.force_authenticate(user=None) diff --git a/api/urls.py b/api/urls.py index af275381..7d6a4f7d 100644 --- a/api/urls.py +++ b/api/urls.py @@ -4,7 +4,7 @@ from rest_framework.routers import DefaultRouter from .views import HealthcheckView from .viewsets import ( DocumentationLinkViewSet, InfractionViewSet, - OffTopicChannelNameViewSet, + OffTopicChannelNameViewSet, RoleViewSet, SnakeFactViewSet, SnakeIdiomViewSet, SnakeNameViewSet, SpecialSnakeViewSet, TagViewSet, UserViewSet @@ -27,6 +27,10 @@ bot_router.register( base_name='offtopicchannelname' ) bot_router.register( + 'roles', + RoleViewSet +) +bot_router.register( 'snake-facts', SnakeFactViewSet ) diff --git a/api/viewsets.py b/api/viewsets.py index 2784bbad..ab62f8a7 100644 --- a/api/viewsets.py +++ b/api/viewsets.py @@ -14,7 +14,7 @@ from rest_framework_bulk import BulkCreateModelMixin from .models import ( DocumentationLink, Infraction, - OffTopicChannelName, + OffTopicChannelName, Role, SnakeFact, SnakeIdiom, SnakeName, SpecialSnake, Tag, User @@ -22,9 +22,10 @@ from .models import ( from .serializers import ( DocumentationLinkSerializer, ExpandedInfractionSerializer, InfractionSerializer, OffTopicChannelNameSerializer, - SnakeFactSerializer, SnakeIdiomSerializer, - SnakeNameSerializer, SpecialSnakeSerializer, - TagSerializer, UserSerializer + RoleSerializer, SnakeFactSerializer, + SnakeIdiomSerializer, SnakeNameSerializer, + SpecialSnakeSerializer, TagSerializer, + UserSerializer ) @@ -319,6 +320,97 @@ class OffTopicChannelNameViewSet(DestroyModelMixin, ViewSet): return Response(serialized.data) +class RoleViewSet(ModelViewSet): + """ + View providing CRUD access to the roles on our server, used + by the bot to keep a mirror of our server's roles on the site. + + ## Routes + ### GET /bot/roles + Returns all roles in the database. + + #### Response format + >>> [ + ... { + ... 'id': 267628507062992896, + ... 'name': "Admins", + ... 'colour': 1337, + ... 'permissions': 8 + ... } + ... ] + + #### Status codes + - 200: returned on success + + ### GET /bot/roles/<snowflake:int> + Gets a single role by ID. + + #### Response format + >>> { + ... 'id': 267628507062992896, + ... 'name': "Admins", + ... 'colour': 1337, + ... 'permissions': 8 + ... } + + #### Status codes + - 200: returned on success + - 404: if a role with the given `snowflake` could not be found + + ### POST /bot/roles + Adds a single new role. + + #### Request body + >>> { + ... 'id': int, + ... 'name': str, + ... 'colour': int, + ... 'permissions': int, + ... } + + #### Status codes + - 201: returned on success + - 400: if the body format is invalid + + ### PUT /bot/roles/<snowflake:int> + Update the role with the given `snowflake`. + All fields in the request body are required. + + #### Request body + >>> { + ... 'id': int, + ... 'name': str, + ... 'colour': int, + ... 'permissions': int + ... } + + #### Status codes + - 200: returned on success + - 400: if the request body was invalid + + ### PATCH /bot/roles/<snowflake:int> + Update the role with the given `snowflake`. + All fields in the request body are required. + + >>> { + ... 'id': int, + ... 'name': str, + ... 'colour': int, + ... 'permissions': int + ... } + + ### DELETE /bot/roles/<snowflake:int> + Deletes the role with the given `snowflake`. + + #### Status codes + - 204: returned on success + - 404: if a role with the given `snowflake` does not exist + """ + + queryset = Role.objects.all() + serializer_class = RoleSerializer + + class SnakeFactViewSet(ListModelMixin, GenericViewSet): """ View providing snake facts created by the Pydis community in the first code jam. @@ -506,7 +598,7 @@ class TagViewSet(ModelViewSet): - 201: returned on success - 400: if one of the given fields is invalid - ### PUT /bot/members/<title:str> + ### PUT /bot/tags/<title:str> Update the tag with the given `title`. #### Request body @@ -524,7 +616,7 @@ class TagViewSet(ModelViewSet): - 400: if the request body was invalid, see response body for details - 404: if the tag with the given `title` could not be found - ### PATCH /bot/members/<title:str> + ### PATCH /bot/tags/<title:str> Update the tag with the given `title`. #### Request body @@ -542,7 +634,7 @@ class TagViewSet(ModelViewSet): - 400: if the request body was invalid, see response body for details - 404: if the tag with the given `title` could not be found - ### DELETE /bot/members/<title:str> + ### DELETE /bot/tags/<title:str> Deletes the tag with the given `title`. #### Status codes |