diff --git a/Pipfile b/Pipfile index d289f87b..b2304448 100644 --- a/Pipfile +++ b/Pipfile @@ -42,3 +42,4 @@ ipython = "*" requests = "*" unittest-xml-reporting = "*" django-silk = "*" +wagtail-autocomplete = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 733f7269..cd7f05dc 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c121d2faf04bfe61080cc0929a103e26bb0895462882e1e92dbde3276579408c" + "sha256": "9948afb7cfaa5a744d4ef5e5e7d66597806f45f2714dbb0ba4e6eb819b274240" }, "pipfile-spec": 6, "requires": { @@ -48,18 +48,18 @@ }, "boto3": { "hashes": [ - "sha256:11dc492682cf2a4f8ff397b0a109837340ef93e77ca2e65715ce24ecf043717c", - "sha256:ca97e1d591fe4214bac09cf347a8425061d9eecc456c147692749e383a0f3dfe" + "sha256:15d3910eb1acfcdaa6aa8a64f3ed956ada1b5f3f9a8f2f127fd786036cb2afa5", + "sha256:d46f7c8c586c9c293f1a1eead56c18b82fcc3eec4dcebd4686aad4a675fd45b8" ], "index": "pypi", - "version": "==1.16.51" + "version": "==1.16.54" }, "botocore": { "hashes": [ - "sha256:76c0ce78fd2a7e9e08d038f2bba2ce10bee08e04546c7812a9654edb2dc4d496", - "sha256:b204c5b477b043c7f61cba5db479c6b25f684f7409b71a8ecdb5a6b3f57b5cb4" + "sha256:bba883f97c6657df941598150bf8a5a88bb976b7de53ec41ad3e518cfe8931d3", + "sha256:edfe213f3b01467605754ba1d46c6ac3b8a4be721fdf879d45c2132a99b4ac49" ], - "version": "==1.19.51" + "version": "==1.19.54" }, "certifi": { "hashes": [ @@ -176,9 +176,10 @@ }, "django-treebeard": { "hashes": [ - "sha256:83aebc34a9f06de7daaec330d858d1c47887e81be3da77e3541fe7368196dd8a" + "sha256:214ae3ab331a7de11fb055a2015c201e34f3fa14255b667e1e07752231a7a398", + "sha256:f50e4eea146f7af6702decf7ef198ac1eee1fb9bb4af2c5dba276c3c48f76623" ], - "version": "==4.3.1" + "version": "==4.4" }, "djangorestframework": { "hashes": [ @@ -205,10 +206,10 @@ }, "faker": { "hashes": [ - "sha256:bd56ab94b9ae45df3cdb6ef3ca3c2be2617e6a640699deb74394143d220faf04", - "sha256:d70983d5e623976e9e8987e9a39e8d55378e66049f393db35ea9a37b3190085f" + "sha256:3d8ba3e4a3700962a1bf5599a43797b286d1ac52b3dd90c1e8a2625f73c46bd6", + "sha256:eb14d0c6b8f7c9902bb07dedc2ad405237edbf808d4ead9f17b9567e586cabee" ], - "version": "==5.4.0" + "version": "==5.6.0" }, "future": { "hashes": [ @@ -452,10 +453,10 @@ }, "pygments": { "hashes": [ - "sha256:ccf3acacf3782cbed4a989426012f1c535c9a90d3a7fc3f16d231b9372d2b716", - "sha256:f275b6c0909e5dafd2d6269a656aa90fa58ebf4a74f8fcf9053195d226b24a08" + "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435", + "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337" ], - "version": "==2.7.3" + "version": "==2.7.4" }, "pyparsing": { "hashes": [ @@ -544,17 +545,17 @@ }, "s3transfer": { "hashes": [ - "sha256:2482b4259524933a022d59da830f51bd746db62f047d6eb213f2f8855dcb8a13", - "sha256:921a37e2aefc64145e7b73d50c71bb4f26f46e4c9f414dc648c6245ff92cf7db" + "sha256:1e28620e5b444652ed752cf87c7e0cb15b0e578972568c6609f0f18212f259ed", + "sha256:7fdddb4f22275cf1d32129e21f056337fd2a80b6ccef1664528145b72c49e6d2" ], - "version": "==0.3.3" + "version": "==0.3.4" }, "sendgrid": { "hashes": [ - "sha256:4c04a660d25448d8d64092a8b0e4aa6eb18d70f358219ce45895a8067f967833", - "sha256:850d37a45ce96a24435061a1e3333faf9a2d31fc6287b496867c8eee7a2486c7" + "sha256:499a4910623c03e73cb27bd9ef7cadd0968eb2c811afd5c83cfb517f76163f65", + "sha256:5a87682dba540b706683d4b4a3a605e11fbe24f340ecff5fd502bfb17dfa7ef8" ], - "version": "==6.4.8" + "version": "==6.5.0" }, "sentry-sdk": { "hashes": [ @@ -632,7 +633,6 @@ "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08", "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473" ], - "markers": "python_version != '3.4'", "version": "==1.26.2" }, "wagtail": { @@ -643,6 +643,13 @@ "index": "pypi", "version": "==2.5" }, + "wagtail-autocomplete": { + "hashes": [ + "sha256:5f8ddf16d3ca365af4ad0f09e8f45d9e982ca854dc1b084a8a30f66b00a7739d" + ], + "index": "pypi", + "version": "==0.6" + }, "wagtail-factories": { "hashes": [ "sha256:2198e791854ef3883812f532a4d1b364aae1c68abc58a48b8ecec8c61e4a151f", @@ -697,11 +704,11 @@ }, "awscli": { "hashes": [ - "sha256:5db80229f1991cb31e87c5ccf71f76365fcce7fe4a150dd201e95f54605cee29", - "sha256:7643ddaf4434e428de360d4529bc9ee0d76d7da922768d30291db601f96cdcc9" + "sha256:1d256f75e7ad534aba01f111c34eeeb09291b1acbe9d83a10c4199c703f78a0f", + "sha256:4a381957a37710f2ef3a6303bab7d7d6ed2bd0222aed83695dbcec021acccdfa" ], "index": "pypi", - "version": "==1.18.211" + "version": "==1.18.214" }, "backcall": { "hashes": [ @@ -712,10 +719,10 @@ }, "botocore": { "hashes": [ - "sha256:76c0ce78fd2a7e9e08d038f2bba2ce10bee08e04546c7812a9654edb2dc4d496", - "sha256:b204c5b477b043c7f61cba5db479c6b25f684f7409b71a8ecdb5a6b3f57b5cb4" + "sha256:bba883f97c6657df941598150bf8a5a88bb976b7de53ec41ad3e518cfe8931d3", + "sha256:edfe213f3b01467605754ba1d46c6ac3b8a4be721fdf879d45c2132a99b4ac49" ], - "version": "==1.19.51" + "version": "==1.19.54" }, "certifi": { "hashes": [ @@ -981,10 +988,10 @@ }, "pygments": { "hashes": [ - "sha256:ccf3acacf3782cbed4a989426012f1c535c9a90d3a7fc3f16d231b9372d2b716", - "sha256:f275b6c0909e5dafd2d6269a656aa90fa58ebf4a74f8fcf9053195d226b24a08" + "sha256:bc9591213a8f0e0ca1a5e68a479b4887fdc3e75d0774e5c71c31920c427de435", + "sha256:df49d09b498e83c1a73128295860250b0b7edd4c723a32e9bc0d295c7c2ec337" ], - "version": "==2.7.3" + "version": "==2.7.4" }, "python-dateutil": { "hashes": [ @@ -1037,10 +1044,10 @@ }, "s3transfer": { "hashes": [ - "sha256:2482b4259524933a022d59da830f51bd746db62f047d6eb213f2f8855dcb8a13", - "sha256:921a37e2aefc64145e7b73d50c71bb4f26f46e4c9f414dc648c6245ff92cf7db" + "sha256:1e28620e5b444652ed752cf87c7e0cb15b0e578972568c6609f0f18212f259ed", + "sha256:7fdddb4f22275cf1d32129e21f056337fd2a80b6ccef1664528145b72c49e6d2" ], - "version": "==0.3.3" + "version": "==0.3.4" }, "six": { "hashes": [ @@ -1075,7 +1082,6 @@ "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08", "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473" ], - "markers": "python_version != '3.4'", "version": "==1.26.2" }, "wcwidth": { diff --git a/server/assignments/admin.py b/server/assignments/admin.py index 5f0774f7..4d692aca 100644 --- a/server/assignments/admin.py +++ b/server/assignments/admin.py @@ -7,6 +7,7 @@ from assignments.models import Assignment, StudentSubmission, SubmissionFeedback @admin.register(Assignment) class AssignmentAdmin(admin.ModelAdmin): list_display = ('title', 'module', 'deleted', 'owner', ) + autocomplete_fields = ('owner',) @admin.register(StudentSubmission) diff --git a/server/assignments/models.py b/server/assignments/models.py index 1ef64be8..32aefc57 100644 --- a/server/assignments/models.py +++ b/server/assignments/models.py @@ -3,6 +3,7 @@ from django.db import models from django_extensions.db.models import TimeStampedModel from wagtail.admin.edit_handlers import FieldPanel from wagtail.snippets.models import register_snippet +from wagtailautocomplete.edit_handlers import AutocompletePanel @register_snippet @@ -22,7 +23,7 @@ class Assignment(TimeStampedModel): FieldPanel('assignment'), FieldPanel('solution'), FieldPanel('module'), - FieldPanel('owner'), + AutocompletePanel('owner') ] def __str__(self): diff --git a/server/core/settings.py b/server/core/settings.py index 586e4133..9550cf7a 100644 --- a/server/core/settings.py +++ b/server/core/settings.py @@ -72,6 +72,7 @@ INSTALLED_APPS = [ 'wagtail.admin', 'wagtail.core', 'wagtail.api.v2', + 'wagtailautocomplete', 'taggit', 'modelcluster', diff --git a/server/core/urls.py b/server/core/urls.py index 6a95b795..2eef0195 100644 --- a/server/core/urls.py +++ b/server/core/urls.py @@ -6,6 +6,7 @@ from django.urls import re_path from django.views.generic import RedirectView from wagtail.admin import urls as wagtailadmin_urls from wagtail.core import urls as wagtail_urls +from wagtailautocomplete.urls.admin import urlpatterns as autocomplete_admin_urls from core import views @@ -16,6 +17,7 @@ urlpatterns = [ url(r'^statistics/', include('statistics.urls', namespace='statistics')), # wagtail + url(r'^admin/autocomplete/', include(autocomplete_admin_urls)), url(r'^cms/', include(wagtailadmin_urls)), # graphql backend diff --git a/server/users/admin.py b/server/users/admin.py index d59f867d..1b6832d5 100644 --- a/server/users/admin.py +++ b/server/users/admin.py @@ -47,8 +47,10 @@ class CustomUserAdmin(UserAdmin): add_form = CustomUserCreationForm form = CustomUserChangeForm model = User - list_display = ('username', 'first_name', 'last_name', 'school_classes_list') - list_filter = ('school_classes',) + list_display = ('username', 'first_name', 'last_name', 'school_classes_list', 'is_superuser') + list_filter = ('school_classes', 'is_superuser') + ordering = ['pk'] + search_fields = ('username', 'first_name', 'last_name') inlines = [ SchoolClassInline, diff --git a/server/users/models.py b/server/users/models.py index de10a6c7..1e405e7d 100644 --- a/server/users/models.py +++ b/server/users/models.py @@ -26,6 +26,12 @@ class User(AbstractUser): license_expiry_date = models.DateField(blank=False, null=True, default=None) onboarding_visited = models.BooleanField(default=False) + # for wagtail autocomplete + autocomplete_search_field = 'username' + + def autocomplete_label(self): + return self.username + objects = UserManager() def get_role_permissions(self): @@ -103,6 +109,8 @@ class User(AbstractUser): def full_name(self): return self.get_full_name() + class Meta: + ordering = ['pk',] class SchoolClass(models.Model): name = models.CharField(max_length=100, blank=False, null=False, unique=True)