diff options
Diffstat (limited to 'api')
| -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 | 
