Repository: python-discord/site

Issue:
Django - API: Slight 'Beautification' and Minor Mistakes
- [ ] Rename auto migrations?
- [x] Tags view set's docstring incorrectly uses `members` for some routes.
- [x] Sort models alphabetically in `models.py`.
- [x] A class in `test_users` is incorrectly named `UnauthedDocumentationLinkAPITests`.


Discussion:
>  Rename auto migrations?

I believe this will mess with local setups because Django uses the name to reference the migrations in the `django_migrations` table:
```sql
$ psql -d pysite
psql (10.5)
Type "help" for help.

pysite=# SELECT * FROM django_migrations;
 id |     app      |                     name                     |            applied            
----+--------------+----------------------------------------------+-------------------------------
  1 | contenttypes | 0001_initial                                 | 2018-08-11 23:34:13.996961+02
  2 | auth         | 0001_initial                                 | 2018-08-11 23:34:14.114469+02
  3 | admin        | 0001_initial                                 | 2018-08-11 23:34:14.165471+02
  4 | admin        | 0002_logentry_remove_auto_add                | 2018-08-11 23:34:14.17783+02
  5 | admin        | 0003_logentry_add_action_flag_choices        | 2018-08-11 23:34:14.187902+02
  6 | contenttypes | 0002_remove_content_type_name                | 2018-08-11 23:34:14.216703+02
  7 | auth         | 0002_alter_permission_name_max_length        | 2018-08-11 23:34:14.225567+02
  8 | auth         | 0003_alter_user_email_max_length             | 2018-08-11 23:34:14.237763+02
  9 | auth         | 0004_alter_user_username_opts                | 2018-08-11 23:34:14.24922+02
 10 | auth         | 0005_alter_user_last_login_null              | 2018-08-11 23:34:14.261605+02
 11 | auth         | 0006_require_contenttypes_0002               | 2018-08-11 23:34:14.264454+02
 12 | auth         | 0007_alter_validators_add_error_messages     | 2018-08-11 23:34:14.277805+02
 13 | auth         | 0008_alter_user_username_max_length          | 2018-08-11 23:34:14.292841+02
 14 | auth         | 0009_alter_user_last_name_max_length         | 2018-08-11 23:34:14.306871+02
 15 | sessions     | 0001_initial                                 | 2018-08-11 23:34:14.321943+02
 16 | api          | 0001_initial                                 | 2018-08-15 19:28:37.395305+02
 17 | authtoken    | 0001_initial                                 | 2018-08-15 20:10:38.536288+02
 18 | authtoken    | 0002_auto_20160226_1747                      | 2018-08-15 20:10:38.623051+02
 21 | api          | 0004_user                                    | 2018-09-01 20:13:49.004345+02
 22 | api          | 0005_rolemembership                          | 2018-09-01 20:13:49.024801+02
 23 | api          | 0006_rename_role_membership_backref_to_roles | 2018-09-01 20:13:49.069511+02
 26 | api          | 0006_tag                                     | 2018-09-07 19:34:39.889443+02
-- ...
```

In order to fix it up, users would have to fake run the migration locally. That being said, we should probably do it before we go live.

>  Tags view set's docstring incorrectly uses members for some routes.
>
>  A class in test_users is incorrectly named UnauthedDocumentationLinkAPITests.

Ah, the joys of copy-pasting...

>  Sort models alphabetically in models.py.

This messes with the string format tests because the way we test them messes with how Django resolves some of the foreign key fields. We should probably look into it regardless.

Resolving patch:
diff --git a/api/models.py b/api/models.py
--- a/api/models.py
+++ b/api/models.py
@@ -60,6 +60,50 @@ def __str__(self):
         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 @@ def __str__(self):
         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 @@ def __str__(self):
         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/viewsets.py b/api/viewsets.py
--- a/api/viewsets.py
+++ b/api/viewsets.py
@@ -506,7 +506,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 +524,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 +542,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


Test patch:
diff --git a/api/tests/test_users.py b/api/tests/test_users.py
--- a/api/tests/test_users.py
+++ b/api/tests/test_users.py
@@ -4,7 +4,7 @@
 from ..models import Role, User
 
 
-class UnauthedDocumentationLinkAPITests(APISubdomainTestCase):
+class UnauthedUserAPITests(APISubdomainTestCase):
     def setUp(self):
         super().setUp()
         self.client.force_authenticate(user=None)