diff --git a/app.json b/app.json index 3b7526f66..7be017ad5 100644 --- a/app.json +++ b/app.json @@ -409,10 +409,6 @@ "description": "The SL tracking ID", "required": false }, - "STATUS_TOKEN": { - "description": "Token to access the status API.", - "required": true - }, "USE_X_FORWARDED_HOST": { "description": "Set HOST header to original domain accessed by user", "required": false diff --git a/applications/__init__.py b/applications/__init__.py index 891b6e15d..cd1e1174f 100644 --- a/applications/__init__.py +++ b/applications/__init__.py @@ -1,3 +1 @@ """Initialize applications app""" - -default_app_config = "applications.apps.ApplicationConfig" diff --git a/applications/admin.py b/applications/admin.py index d86a62916..5e24c7612 100644 --- a/applications/admin.py +++ b/applications/admin.py @@ -10,30 +10,42 @@ from django.utils.safestring import mark_safe from mitol.common.admin import TimestampedModelAdmin -from applications import models +from applications.models import ( + ApplicationStep, + ApplicationStepSubmission, + BootcampRunApplicationStep, + BootcampApplication, + VideoInterviewSubmission, + QuizSubmission, + ApplicantLetter, + Interview, +) from ecommerce.models import Order from main.utils import get_field_names +@admin.register(ApplicationStep) class ApplicationStepAdmin(admin.ModelAdmin): """Admin for ApplicationStep""" - model = models.ApplicationStep + model = ApplicationStep list_display = ("id", "get_bootcamp_title", "submission_type", "step_order") ordering = ("bootcamp", "step_order") + @admin.display( + description="Bootcamp", + ordering="bootcamp__title", + ) def get_bootcamp_title(self, obj): """Returns the bootcamp title""" return obj.bootcamp.title - get_bootcamp_title.short_description = "Bootcamp" - get_bootcamp_title.admin_order_field = "bootcamp__title" - +@admin.register(BootcampRunApplicationStep) class BootcampRunApplicationStepAdmin(admin.ModelAdmin): """Admin for BootcampRunApplicationStep""" - model = models.BootcampRunApplicationStep + model = BootcampRunApplicationStep list_display = ( "id", "get_run_display_title", @@ -53,27 +65,30 @@ def get_queryset(self, request): """Overrides base queryset""" return super().get_queryset(request).select_related("bootcamp_run__bootcamp") + @admin.display( + description="Bootcamp Run", + ordering="bootcamp_run__title", + ) def get_run_display_title(self, obj): """Returns the bootcamp run display title""" return obj.bootcamp_run.display_title - get_run_display_title.short_description = "Bootcamp Run" - get_run_display_title.admin_order_field = "bootcamp_run__title" - + @admin.display( + description="Submission Type", + ordering="application_step__submission_type", + ) def get_submission_type(self, obj): """Returns the application step submission type""" return obj.application_step.submission_type - get_submission_type.short_description = "Submission Type" - get_submission_type.admin_order_field = "application_step__submission_type" - + @admin.display( + description="Step Order", + ordering="application_step__step_order", + ) def get_step_order(self, obj): """Returns the application step order""" return obj.application_step.step_order - get_step_order.short_description = "Step Order" - get_step_order.admin_order_field = "application_step__step_order" - class OrderInline(admin.StackedInline): """Inline form for Order""" @@ -90,10 +105,11 @@ def has_add_permission(self, request, obj=None): return False +@admin.register(BootcampApplication) class BootcampApplicationAdmin(TimestampedModelAdmin): """Admin for BootcampApplication""" - model = models.BootcampApplication + model = BootcampApplication include_timestamps_in_list = True inlines = [OrderInline] list_display = ("id", "get_user_email", "get_run_display_title", "state") @@ -114,25 +130,27 @@ def get_queryset(self, request): .select_related("user", "bootcamp_run__bootcamp") ) + @admin.display( + description="User", + ordering="user__email", + ) def get_user_email(self, obj): """Returns the user email""" return obj.user.email - get_user_email.short_description = "User" - get_user_email.admin_order_field = "user__email" - + @admin.display( + description="Bootcamp Run", + ordering="bootcamp_run__title", + ) def get_run_display_title(self, obj): """Returns the bootcamp run display title""" return obj.bootcamp_run.display_title - get_run_display_title.short_description = "Bootcamp Run" - get_run_display_title.admin_order_field = "bootcamp_run__title" - class AppStepSubmissionInline(GenericTabularInline): """Admin class for ApplicationStepSubmission""" - model = models.ApplicationStepSubmission + model = ApplicationStepSubmission max_num = 1 raw_id_fields = ("bootcamp_application", "run_application_step") @@ -170,6 +188,10 @@ def get_queryset(self, request): ) ) + @admin.display( + description="Application User", + ordering="app_step_submission__bootcamp_application__user__email", + ) def get_user_email(self, obj): """Returns the user email""" app_step_submissions = obj.app_step_submissions.all() @@ -179,11 +201,10 @@ def get_user_email(self, obj): else app_step_submissions[0].bootcamp_application.user.email ) - get_user_email.short_description = "Application User" - get_user_email.admin_order_field = ( - "app_step_submission__bootcamp_application__user__email" + @admin.display( + description="App Bootcamp Run", + ordering="app_step_submission__bootcamp_application__bootcamp_run__title", ) - def get_run_display_title(self, obj): """Returns the bootcamp run display title""" app_step_submissions = obj.app_step_submissions.all() @@ -193,11 +214,7 @@ def get_run_display_title(self, obj): else app_step_submissions[0].bootcamp_application.bootcamp_run.display_title ) - get_run_display_title.short_description = "App Bootcamp Run" - get_run_display_title.admin_order_field = ( - "app_step_submission__bootcamp_application__bootcamp_run__title" - ) - + @admin.display(description="Submission") def app_step_submission_link(self, obj): """Returns a link to the related bootcamp application""" app_step_submissions = obj.app_step_submissions.all() @@ -208,7 +225,7 @@ def app_step_submission_link(self, obj): 'Submission ({})'.format( reverse( "admin:applications_{}_change".format( - models.ApplicationStepSubmission._meta.model_name + ApplicationStepSubmission._meta.model_name ), args=(app_step_submission.id,), ), # pylint: disable=protected-access @@ -216,19 +233,19 @@ def app_step_submission_link(self, obj): ) ) - app_step_submission_link.short_description = "Submission" - +@admin.register(VideoInterviewSubmission) class VideoInterviewSubmissionAdmin(SubmissionTypeAdmin): """Admin class for VideoInterviewSubmission""" - model = models.VideoInterviewSubmission + model = VideoInterviewSubmission raw_id_fields = ("interview",) def get_list_display(self, request): return tuple(super().get_list_display(request) or ()) + ("interview_link",) + @admin.display(description="Interview") def interview_link(self, obj): """Returns a link to the related interview record""" if not hasattr(obj, "interview") or obj.interview is None: @@ -236,20 +253,19 @@ def interview_link(self, obj): return mark_safe( 'Interview ({})'.format( reverse( - "admin:jobma_{}_change".format(models.Interview._meta.model_name), + "admin:jobma_{}_change".format(Interview._meta.model_name), args=(obj.interview.id,), ), # pylint: disable=protected-access obj.interview.id, ) ) - interview_link.short_description = "Interview" - +@admin.register(QuizSubmission) class QuizSubmissionAdmin(SubmissionTypeAdmin): """Admin for QuizSubmission""" - model = models.QuizSubmission + model = QuizSubmission def get_list_display(self, request): return tuple(super().get_list_display(request) or ()) + ("started_date",) @@ -272,10 +288,11 @@ def clean_object_id(self): return object_id +@admin.register(ApplicationStepSubmission) class ApplicationStepSubmissionAdmin(TimestampedModelAdmin): """Admin for ApplicationStepSubmission""" - model = models.ApplicationStepSubmission + model = ApplicationStepSubmission form = ApplicationStepSubmissionForm list_display = ( "id", @@ -313,6 +330,7 @@ def get_readonly_fields(self, request, obj=None): return tuple(self.readonly_fields or ()) + ("content_type", "object_id") return self.readonly_fields + @admin.display(description="submission object") def submission_content_obj_link(self, obj): """Returns a link to the content object""" if obj.content_object is None: @@ -329,27 +347,28 @@ def submission_content_obj_link(self, obj): ) ) - submission_content_obj_link.short_description = "submission object" - + @admin.display( + description="User", + ordering="user__email", + ) def get_user_email(self, obj): """Returns the user email""" return obj.bootcamp_application.user.email - get_user_email.short_description = "User" - get_user_email.admin_order_field = "user__email" - + @admin.display( + description="Bootcamp Run", + ordering="bootcamp_run__title", + ) def get_run_display_title(self, obj): """Returns the bootcamp run display title""" return obj.bootcamp_application.bootcamp_run.display_title - get_run_display_title.short_description = "Bootcamp Run" - get_run_display_title.admin_order_field = "bootcamp_run__title" - +@admin.register(ApplicantLetter) class ApplicantLetterAdmin(TimestampedModelAdmin): """Admin for ApplicantLetter""" - model = models.ApplicantLetter + model = ApplicantLetter list_display = ("id", "letter_type", "get_user_email", "get_run_display_title") list_filter = ("letter_type",) raw_id_fields = ("application",) @@ -358,27 +377,20 @@ class ApplicantLetterAdmin(TimestampedModelAdmin): "application__bootcamp_run__title", "application__bootcamp_run__bootcamp__title", ) - readonly_fields = get_field_names(models.ApplicantLetter) + readonly_fields = get_field_names(ApplicantLetter) + @admin.display( + description="User", + ordering="user__email", + ) def get_user_email(self, obj): """Returns the user email""" return obj.application.user.email - get_user_email.short_description = "User" - get_user_email.admin_order_field = "user__email" - + @admin.display( + description="Bootcamp Run", + ordering="bootcamp_run__title", + ) def get_run_display_title(self, obj): """Returns the bootcamp run display title""" return obj.application.bootcamp_run.display_title - - get_run_display_title.short_description = "Bootcamp Run" - get_run_display_title.admin_order_field = "bootcamp_run__title" - - -admin.site.register(models.ApplicationStep, ApplicationStepAdmin) -admin.site.register(models.BootcampRunApplicationStep, BootcampRunApplicationStepAdmin) -admin.site.register(models.BootcampApplication, BootcampApplicationAdmin) -admin.site.register(models.VideoInterviewSubmission, VideoInterviewSubmissionAdmin) -admin.site.register(models.QuizSubmission, QuizSubmissionAdmin) -admin.site.register(models.ApplicationStepSubmission, ApplicationStepSubmissionAdmin) -admin.site.register(models.ApplicantLetter, ApplicantLetterAdmin) diff --git a/applications/urls.py b/applications/urls.py index b8b658475..b0475246b 100644 --- a/applications/urls.py +++ b/applications/urls.py @@ -3,7 +3,7 @@ """ from django.urls import path -from django.conf.urls import url, include +from django.urls import include from rest_framework import routers from applications.views import ( @@ -20,9 +20,9 @@ router.register(r"submissions", ReviewSubmissionViewSet, basename="submissions_api") urlpatterns = [ - url(r"^api/", include(router.urls)), - url( - r"^api/applications/(?P\d+)/resume/$", + path("api/", include(router.urls)), + path( + "api/applications//resume/", UploadResumeView.as_view(), name="upload-resume", ), diff --git a/authentication/middleware.py b/authentication/middleware.py index 9993d4e94..66cf5a453 100644 --- a/authentication/middleware.py +++ b/authentication/middleware.py @@ -1,7 +1,7 @@ """Authentication middleware""" +from urllib.parse import quote from django.shortcuts import redirect -from django.utils.http import urlquote from social_core.exceptions import SocialAuthBaseException from social_django.middleware import SocialAuthExceptionMiddleware @@ -31,6 +31,6 @@ def process_exception(self, request, exception): if url: url += ("?" in url and "&" or "?") + "message={0}&backend={1}".format( - urlquote(message), backend_name + quote(message), backend_name ) return redirect(url) diff --git a/authentication/middleware_test.py b/authentication/middleware_test.py index 61baef1a3..f5ec0e8ff 100644 --- a/authentication/middleware_test.py +++ b/authentication/middleware_test.py @@ -2,7 +2,7 @@ from django.contrib.sessions.middleware import SessionMiddleware from django.shortcuts import reverse -from django.utils.http import urlquote +from urllib.parse import quote from rest_framework import status from social_core.exceptions import AuthAlreadyAssociated from social_django.utils import load_backend, load_strategy @@ -23,7 +23,7 @@ def test_process_exception(mocker, rf, settings): settings.DEBUG = False request = rf.get(reverse("social:complete", args=("email",))) # social_django depends on request.sesssion, so use the middleware to set that - SessionMiddleware().process_request(request) + SessionMiddleware(get_response=mocker.Mock()).process_request(request) strategy = load_strategy(request) backend = load_backend(strategy, "email", None) request.social_strategy = strategy @@ -34,7 +34,7 @@ def test_process_exception(mocker, rf, settings): result = middleware.process_exception(request, error) assert result.status_code == status.HTTP_302_FOUND assert result.url == "{}?message={}&backend={}".format( - reverse("login"), urlquote(error.__str__()), backend.name + reverse("login"), quote(error.__str__()), backend.name ) @@ -43,7 +43,7 @@ def test_process_exception_non_auth_error(mocker, rf, settings): settings.DEBUG = False request = rf.get(reverse("social:complete", args=("email",))) # social_django depends on request.sesssion, so use the middleware to set that - SessionMiddleware().process_request(request) + SessionMiddleware(get_response=mocker.Mock()).process_request(request) strategy = load_strategy(request) backend = load_backend(strategy, "email", None) request.social_strategy = strategy diff --git a/authentication/pipeline/user_test.py b/authentication/pipeline/user_test.py index cb277e25a..8e6669d77 100644 --- a/authentication/pipeline/user_test.py +++ b/authentication/pipeline/user_test.py @@ -46,10 +46,10 @@ def validate_email_auth_request_not_email_backend(mocker): "has_user,expected", [(True, {"flow": SocialAuthState.FLOW_LOGIN}), (False, {})] ) @pytest.mark.django_db -def test_validate_email_auth_request(rf, has_user, expected): +def test_validate_email_auth_request(rf, has_user, expected, mocker): """Test that validate_email_auth_request returns correctly given the input""" request = rf.post("/complete/email") - middleware = SessionMiddleware() + middleware = SessionMiddleware(get_response=mocker.Mock()) middleware.process_request(request) request.session.save() strategy = load_strategy(request) @@ -105,7 +105,7 @@ def test_user_password_not_email_backend(mocker): @pytest.mark.parametrize("user_password", ["abc123", "def456"]) -def test_user_password_login(rf, user, user_password): +def test_user_password_login(rf, user, user_password, mocker): """Tests that user_password works for login case""" request_password = "abc123" user.set_password(user_password) @@ -113,7 +113,7 @@ def test_user_password_login(rf, user, user_password): request = rf.post( "/complete/email", {"password": request_password, "email": user.email} ) - middleware = SessionMiddleware() + middleware = SessionMiddleware(get_response=mocker.Mock()) middleware.process_request(request) request.session.save() strategy = load_strategy(request) @@ -141,7 +141,7 @@ def test_user_password_login(rf, user, user_password): ) -def test_user_password_not_login(rf, user): +def test_user_password_not_login(rf, user, mocker): """ Tests that user_password performs denies authentication for an existing user if password not provided regardless of auth_type @@ -149,7 +149,7 @@ def test_user_password_not_login(rf, user): user.set_password("abc123") user.save() request = rf.post("/complete/email", {"email": user.email}) - middleware = SessionMiddleware() + middleware = SessionMiddleware(get_response=mocker.Mock()) middleware.process_request(request) request.session.save() strategy = load_strategy(request) @@ -165,12 +165,12 @@ def test_user_password_not_login(rf, user): ) -def test_user_password_not_exists(rf): +def test_user_password_not_exists(rf, mocker): """Tests that user_password raises auth error for nonexistent user""" request = rf.post( "/complete/email", {"password": "abc123", "email": "doesntexist@localhost"} ) - middleware = SessionMiddleware() + middleware = SessionMiddleware(get_response=mocker.Mock()) middleware.process_request(request) request.session.save() strategy = load_strategy(request) diff --git a/authentication/views.py b/authentication/views.py index d798c00a6..43ccc7092 100644 --- a/authentication/views.py +++ b/authentication/views.py @@ -41,7 +41,7 @@ def get_serializer_cls(self): # pragma: no cover def post(self, request, backend_name=EmailAuth.name): """Processes a request""" - if request.session.get("is_hijacked_user", False): + if bool(request.session.get("hijack_history")): return Response(status=status.HTTP_403_FORBIDDEN) serializer_cls = self.get_serializer_cls() @@ -83,7 +83,7 @@ def get_serializer_cls(self): def post(self, request, backend_name=EmailAuth.name): """Verify recaptcha response before proceeding""" - if request.session.get("is_hijacked_user", False): + if bool(request.session.get("hijack_history")): return Response(status=status.HTTP_403_FORBIDDEN) if settings.RECAPTCHA_SITE_KEY: r = requests.post( diff --git a/authentication/views_test.py b/authentication/views_test.py index 55c029381..10cb1d52a 100644 --- a/authentication/views_test.py +++ b/authentication/views_test.py @@ -829,7 +829,7 @@ def test_login_email_error(client, mocker): def test_login_email_hijacked(client, user, admin_user): """Test that a 403 response is returned for email login view if user is hijacked""" client.force_login(admin_user) - client.post("/hijack/{}/".format(user.id)) + client.post("/hijack/acquire/", {"user_pk": user.id}) response = client.post( reverse("psa-login-email"), {"flow": SocialAuthState.FLOW_LOGIN, "email": "anything@example.com"}, @@ -840,7 +840,7 @@ def test_login_email_hijacked(client, user, admin_user): def test_register_email_hijacked(client, user, admin_user): """Test that a 403 response is returned for email register view if user is hijacked""" client.force_login(admin_user) - client.post("/hijack/{}/".format(user.id)) + client.post("/hijack/acquire/", {"user_pk": user.id}) response = client.post( reverse("psa-register-email"), {"flow": SocialAuthState.FLOW_LOGIN, "email": "anything@example.com"}, diff --git a/cms/__init__.py b/cms/__init__.py index df7b240ba..850a660df 100644 --- a/cms/__init__.py +++ b/cms/__init__.py @@ -1,3 +1 @@ """Initialize cms app""" - -default_app_config = "cms.apps.CMSConfig" diff --git a/compliance/admin.py b/compliance/admin.py index 22a486413..2acb11daf 100644 --- a/compliance/admin.py +++ b/compliance/admin.py @@ -13,6 +13,7 @@ from .models import ExportsInquiryLog +@admin.register(ExportsInquiryLog) class ExportsInquiryLogAdmin(admin.ModelAdmin): """Admin for ExportsInquiryLog""" @@ -33,6 +34,7 @@ def country(self, instance): """generate country name from pycountry""" return pycountry.countries.get(alpha_2=instance.user.legal_address.country).name + @admin.action(description="Manually approve selected records") def manually_approve_inquiry(self, request, queryset): """Admin action to manually approve export compliance inquiry records""" eligible_objects = queryset.exclude( @@ -42,8 +44,6 @@ def manually_approve_inquiry(self, request, queryset): ensure_active_user(obj.user) eligible_objects.update(computed_result=RESULT_MANUALLY_APPROVED) - manually_approve_inquiry.short_description = "Manually approve selected records" - def has_add_permission(self, request): # We want to allow this while debugging return settings.DEBUG @@ -51,6 +51,3 @@ def has_add_permission(self, request): def has_delete_permission(self, request, obj=None): # We want to allow this while debugging return settings.DEBUG - - -admin.site.register(ExportsInquiryLog, ExportsInquiryLogAdmin) diff --git a/ecommerce/admin.py b/ecommerce/admin.py index ddbfbe649..9f787925b 100644 --- a/ecommerce/admin.py +++ b/ecommerce/admin.py @@ -12,6 +12,7 @@ from applications import models as application_models +@admin.register(Line) class LineAdmin(TimestampedModelAdmin): """Admin for Line""" @@ -41,6 +42,7 @@ def has_add_permission(self, request, obj=None): return False +@admin.register(Order) class OrderAdmin(TimestampedModelAdmin): """Admin for Order""" @@ -78,13 +80,15 @@ def get_queryset(self, request): """Overrides base queryset""" return super().get_queryset(request).select_related("user") + @admin.display( + description="User", + ordering="user__email", + ) def get_user_email(self, obj): """Returns the user email""" return obj.user.email - get_user_email.short_description = "User" - get_user_email.admin_order_field = "user__email" - + @admin.display(description="Application") def application_link(self, obj): """Returns a link to the related application""" if not hasattr(obj, "application") or obj.application is None: @@ -101,9 +105,8 @@ def application_link(self, obj): ) ) - application_link.short_description = "Application" - +@admin.register(OrderAudit) class OrderAuditAdmin(admin.ModelAdmin): """Admin for OrderAudit""" @@ -117,6 +120,7 @@ def has_delete_permission(self, request, obj=None): return False +@admin.register(Receipt) class ReceiptAdmin(TimestampedModelAdmin): """Admin for Receipt""" @@ -136,24 +140,27 @@ def get_queryset(self, request): """Overrides base queryset""" return super().get_queryset(request).select_related("order__user") + @admin.display( + description="User", + ordering="order__user__email", + ) def get_user_email(self, obj): """Returns the user email""" if obj.order is None: return None return obj.order.user.email - get_user_email.short_description = "User" - get_user_email.admin_order_field = "order__user__email" - + @admin.display( + description="Status", + ordering="order__status", + ) def get_order_status(self, obj): """Returns the order status""" if obj.order is None: return None return obj.order.status - get_order_status.short_description = "Status" - get_order_status.admin_order_field = "order__status" - + @admin.display(description="Order") def order_link(self, obj): """Returns a link to the related order""" if obj.order is None: @@ -168,9 +175,8 @@ def order_link(self, obj): ) ) - order_link.short_description = "Order" - +@admin.register(WireTransferReceipt) class WireTransferReceiptAdmin(TimestampedModelAdmin): """Admin for WireTransferReceipt""" @@ -193,24 +199,27 @@ def get_queryset(self, request): """Overrides base queryset""" return super().get_queryset(request).select_related("order__user") + @admin.display( + description="User", + ordering="order__user__email", + ) def get_user_email(self, obj): """Returns the user email""" if obj.order is None: return None return obj.order.user.email - get_user_email.short_description = "User" - get_user_email.admin_order_field = "order__user__email" - + @admin.display( + description="Status", + ordering="order__status", + ) def get_order_status(self, obj): """Returns the order status""" if obj.order is None: return None return obj.order.status - get_order_status.short_description = "Status" - get_order_status.admin_order_field = "order__status" - + @admin.display(description="Order") def order_link(self, obj): """Returns a link to the related order""" if obj.order is None: @@ -224,12 +233,3 @@ def order_link(self, obj): obj.order.id, ) ) - - order_link.short_description = "Order" - - -admin.site.register(Line, LineAdmin) -admin.site.register(Order, OrderAdmin) -admin.site.register(OrderAudit, OrderAuditAdmin) -admin.site.register(Receipt, ReceiptAdmin) -admin.site.register(WireTransferReceipt, WireTransferReceiptAdmin) diff --git a/ecommerce/migrations/0001_initial.py b/ecommerce/migrations/0001_initial.py index 4e773f084..a1283b12b 100644 --- a/ecommerce/migrations/0001_initial.py +++ b/ecommerce/migrations/0001_initial.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals from django.conf import settings -import django.contrib.postgres.fields.jsonb from django.db import migrations, models import django.db.models.deletion @@ -91,15 +90,11 @@ class Migration(migrations.Migration): ("updated_on", models.DateTimeField(auto_now=True)), ( "data_before", - django.contrib.postgres.fields.jsonb.JSONField( - blank=True, null=True - ), + models.JSONField(blank=True, null=True), ), ( "data_after", - django.contrib.postgres.fields.jsonb.JSONField( - blank=True, null=True - ), + models.JSONField(blank=True, null=True), ), ( "acting_user", @@ -134,7 +129,7 @@ class Migration(migrations.Migration): ), ("created_on", models.DateTimeField(auto_now_add=True)), ("updated_on", models.DateTimeField(auto_now=True)), - ("data", django.contrib.postgres.fields.jsonb.JSONField()), + ("data", models.JSONField()), ( "order", models.ForeignKey( diff --git a/ecommerce/migrations/0010_wire_transfers.py b/ecommerce/migrations/0010_wire_transfers.py index 07a7b977d..69e00556e 100644 --- a/ecommerce/migrations/0010_wire_transfers.py +++ b/ecommerce/migrations/0010_wire_transfers.py @@ -1,6 +1,5 @@ # Generated by Django 2.2.13 on 2020-07-15 19:33 -import django.contrib.postgres.fields.jsonb from django.db import migrations, models import django.db.models.deletion @@ -37,7 +36,7 @@ class Migration(migrations.Migration): ("created_on", models.DateTimeField(auto_now_add=True)), ("updated_on", models.DateTimeField(auto_now=True)), ("wire_transfer_id", models.IntegerField()), - ("data", django.contrib.postgres.fields.jsonb.JSONField()), + ("data", models.JSONField()), ( "order", models.ForeignKey( diff --git a/ecommerce/urls.py b/ecommerce/urls.py index 60d519919..fe41e0df8 100644 --- a/ecommerce/urls.py +++ b/ecommerce/urls.py @@ -2,8 +2,7 @@ URLs for ecommerce """ -from django.conf.urls import url -from django.urls import path +from django.urls import path, re_path from ecommerce.views import ( CheckoutDataView, @@ -17,27 +16,27 @@ urlpatterns = [ - url(r"^api/v0/payment/$", PaymentView.as_view(), name="create-payment"), - url( - r"^api/v0/order_fulfillment/$", + path("api/v0/payment/", PaymentView.as_view(), name="create-payment"), + path( + "api/v0/order_fulfillment/", OrderFulfillmentView.as_view(), name="order-fulfillment", ), - url( + re_path( r"^api/v0/bootcamps/(?P[-\w.]+)/$", UserBootcampRunList.as_view(), name="bootcamp-run-list", ), - url( + re_path( r"^api/v0/bootcamps/(?P[-\w.]+)/(?P[\d]+)/$", UserBootcampRunDetail.as_view(), name="bootcamp-run-detail", ), - url( - r"statement/(?P[0-9]+)/$", + path( + "statement//", UserBootcampRunStatement.as_view(), name="bootcamp-run-statement", ), - url(r"api/orders/(?P[0-9]+)/$", OrderView.as_view(), name="order-api"), + path("api/orders//", OrderView.as_view(), name="order-api"), path("api/checkout/", CheckoutDataView.as_view(), name="checkout-data-detail"), ] diff --git a/jobma/admin.py b/jobma/admin.py index 3f1db6a2f..845fb7c42 100644 --- a/jobma/admin.py +++ b/jobma/admin.py @@ -7,6 +7,7 @@ from jobma.models import Interview, Job, InterviewAudit +@admin.register(Interview) class InterviewAdmin(admin.ModelAdmin): """Admin for Interview""" @@ -29,21 +30,24 @@ def get_fields(self, request, obj=None): fields.insert(applicant_index + 1, "status") return fields + @admin.display( + description="Applicant", + ordering="applicant__email", + ) def get_applicant_email(self, obj): """Returns the user email""" return obj.applicant.email - get_applicant_email.short_description = "Applicant" - get_applicant_email.admin_order_field = "applicant__email" - + @admin.display( + description="Job Title", + ordering="job__job_title", + ) def get_job_title(self, obj): """Returns the job title""" return obj.job.job_title - get_job_title.short_description = "Job Title" - get_job_title.admin_order_field = "job__job_title" - +@admin.register(Job) class JobAdmin(admin.ModelAdmin): """Admin for Job""" @@ -58,14 +62,16 @@ def get_queryset(self, request): """Overrides base queryset""" return super().get_queryset(request).select_related("run__bootcamp") + @admin.display( + description="Bootcamp Run", + ordering="run__title", + ) def get_run_display_title(self, obj): """Returns the bootcamp run display title""" return obj.run.display_title - get_run_display_title.short_description = "Bootcamp Run" - get_run_display_title.admin_order_field = "run__title" - +@admin.register(InterviewAudit) class InterviewAuditAdmin(admin.ModelAdmin): """Admin for Interview Audit model""" @@ -79,8 +85,3 @@ def has_delete_permission(self, request, obj=None): def has_change_permission(self, request, obj=None): return False - - -admin.site.register(Interview, InterviewAdmin) -admin.site.register(Job, JobAdmin) -admin.site.register(InterviewAudit, InterviewAuditAdmin) diff --git a/jobma/migrations/0001_initial.py b/jobma/migrations/0001_initial.py index 346f8d885..132f04769 100644 --- a/jobma/migrations/0001_initial.py +++ b/jobma/migrations/0001_initial.py @@ -1,7 +1,6 @@ # Generated by Django 2.2.10 on 2020-05-01 16:29 from django.conf import settings -import django.contrib.postgres.fields.jsonb from django.db import migrations, models import django.db.models.deletion @@ -88,15 +87,11 @@ class Migration(migrations.Migration): ("updated_on", models.DateTimeField(auto_now=True)), ( "data_before", - django.contrib.postgres.fields.jsonb.JSONField( - blank=True, null=True - ), + models.JSONField(blank=True, null=True), ), ( "data_after", - django.contrib.postgres.fields.jsonb.JSONField( - blank=True, null=True - ), + models.JSONField(blank=True, null=True), ), ( "acting_user", @@ -133,15 +128,11 @@ class Migration(migrations.Migration): ("updated_on", models.DateTimeField(auto_now=True)), ( "data_before", - django.contrib.postgres.fields.jsonb.JSONField( - blank=True, null=True - ), + models.JSONField(blank=True, null=True), ), ( "data_after", - django.contrib.postgres.fields.jsonb.JSONField( - blank=True, null=True - ), + models.JSONField(blank=True, null=True), ), ( "acting_user", diff --git a/jobma/urls.py b/jobma/urls.py index 44d33d705..92d752506 100644 --- a/jobma/urls.py +++ b/jobma/urls.py @@ -1,12 +1,12 @@ """urls for jobma""" -from django.conf.urls import url +from django.urls import path from jobma.views import JobmaWebhookView urlpatterns = [ - url( - r"api/v0/jobma_webhook/(?P\d+)/$", + path( + "api/v0/jobma_webhook//", JobmaWebhookView.as_view(), name="jobma-webhook", ) diff --git a/klasses/__init__.py b/klasses/__init__.py index f23d9ed8c..e1d7b8317 100644 --- a/klasses/__init__.py +++ b/klasses/__init__.py @@ -1,3 +1 @@ """Initialize klasses app""" - -default_app_config = "klasses.apps.KlassesConfig" diff --git a/klasses/admin.py b/klasses/admin.py index a402a636c..9c59e5dc1 100644 --- a/klasses/admin.py +++ b/klasses/admin.py @@ -5,13 +5,20 @@ from django.contrib import admin from mitol.common.admin import TimestampedModelAdmin -from klasses import models +from klasses.models import ( + Bootcamp, + BootcampRun, + BootcampRunCertificate, + BootcampRunEnrollment, + Installment, + PersonalPrice, +) class BootcampRunInline(admin.StackedInline): """Admin Inline for BootcampRun objects""" - model = models.BootcampRun + model = BootcampRun extra = 1 show_change_link = True @@ -19,15 +26,16 @@ class BootcampRunInline(admin.StackedInline): class InstallmentInline(admin.StackedInline): """Admin Inline for Installment objects""" - model = models.Installment + model = Installment extra = 1 show_change_link = True +@admin.register(Bootcamp) class BootcampAdmin(admin.ModelAdmin): """Admin for Bootcamp""" - model = models.Bootcamp + model = Bootcamp list_display = ( "title", "readable_id", @@ -39,10 +47,11 @@ class BootcampAdmin(admin.ModelAdmin): inlines = [BootcampRunInline] +@admin.register(BootcampRun) class BootcampRunAdmin(admin.ModelAdmin): """Admin for BootcampRun""" - model = models.BootcampRun + model = BootcampRun list_display = ( "display_title", "bootcamp_run_id", @@ -60,10 +69,11 @@ class BootcampRunAdmin(admin.ModelAdmin): inlines = [InstallmentInline] +@admin.register(BootcampRunEnrollment) class BootcampRunEnrollmentAdmin(TimestampedModelAdmin): """Admin for BootcampRunEnrollment""" - model = models.BootcampRunEnrollment + model = BootcampRunEnrollment include_created_on_in_list = True list_display = ( "id", @@ -96,18 +106,20 @@ def get_queryset(self, request): .select_related("user", "bootcamp_run__bootcamp") ) + @admin.display( + description="User", + ordering="user__email", + ) def get_user_email(self, obj): """Returns the user email""" return obj.user.email - get_user_email.short_description = "User" - get_user_email.admin_order_field = "user__email" - +@admin.register(Installment) class InstallmentAdmin(admin.ModelAdmin): """Admin for Installment""" - model = models.Installment + model = Installment list_display = ("id", "bootcamp_run", "deadline", "amount") raw_id_fields = ("bootcamp_run",) search_fields = ( @@ -116,10 +128,11 @@ class InstallmentAdmin(admin.ModelAdmin): ) +@admin.register(PersonalPrice) class PersonalPriceAdmin(admin.ModelAdmin): """Admin for PersonalPrice""" - model = models.PersonalPrice + model = PersonalPrice list_display = ("id", "get_user_email", "bootcamp_run", "price") list_filter = ("bootcamp_run__bootcamp",) raw_id_fields = ("bootcamp_run", "user") @@ -141,18 +154,20 @@ def get_queryset(self, request): .select_related("user", "bootcamp_run__bootcamp") ) + @admin.display( + description="User", + ordering="user__email", + ) def get_user_email(self, obj): """Returns the user email""" return obj.user.email - get_user_email.short_description = "User" - get_user_email.admin_order_field = "user__email" - +@admin.register(BootcampRunCertificate) class BootcampRunCertificateAdmin(TimestampedModelAdmin): """Admin for BootcampRunCertificate""" - model = models.BootcampRunCertificate + model = BootcampRunCertificate include_timestamps_in_list = True list_display = ["uuid", "get_user_email", "bootcamp_run", "get_revoked_state"] search_fields = [ @@ -168,24 +183,18 @@ def get_queryset(self, request): "user", "bootcamp_run" ) + @admin.display( + description="Active", + boolean=True, + ) def get_revoked_state(self, obj): """return the revoked state""" return obj.is_revoked is not True - get_revoked_state.short_description = "Active" - get_revoked_state.boolean = True - + @admin.display( + description="User", + ordering="user__email", + ) def get_user_email(self, obj): """Returns the user email""" return obj.user.email - - get_user_email.short_description = "User" - get_user_email.admin_order_field = "user__email" - - -admin.site.register(models.Bootcamp, BootcampAdmin) -admin.site.register(models.BootcampRun, BootcampRunAdmin) -admin.site.register(models.Installment, InstallmentAdmin) -admin.site.register(models.PersonalPrice, PersonalPriceAdmin) -admin.site.register(models.BootcampRunEnrollment, BootcampRunEnrollmentAdmin) -admin.site.register(models.BootcampRunCertificate, BootcampRunCertificateAdmin) diff --git a/klasses/migrations/0004_admission_cache.py b/klasses/migrations/0004_admission_cache.py index a8cf7fd2a..3cb6bcef0 100644 --- a/klasses/migrations/0004_admission_cache.py +++ b/klasses/migrations/0004_admission_cache.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals from django.conf import settings -import django.contrib.postgres.fields.jsonb from django.db import migrations, models import django.db.models.deletion @@ -27,7 +26,7 @@ class Migration(migrations.Migration): verbose_name="ID", ), ), - ("data", django.contrib.postgres.fields.jsonb.JSONField()), + ("data", models.JSONField()), ( "klass", models.ForeignKey( diff --git a/klasses/migrations/0026_add_bootcamprunenrollmentaudit_defer_enrollment_field.py b/klasses/migrations/0026_add_bootcamprunenrollmentaudit_defer_enrollment_field.py index 6372dc8e4..1762839ac 100644 --- a/klasses/migrations/0026_add_bootcamprunenrollmentaudit_defer_enrollment_field.py +++ b/klasses/migrations/0026_add_bootcamprunenrollmentaudit_defer_enrollment_field.py @@ -1,7 +1,6 @@ # Generated by Django 2.2.18 on 2021-04-26 09:07 from django.conf import settings -import django.contrib.postgres.fields.jsonb from django.db import migrations, models import django.db.models.deletion @@ -39,15 +38,11 @@ class Migration(migrations.Migration): ("updated_on", models.DateTimeField(auto_now=True)), ( "data_before", - django.contrib.postgres.fields.jsonb.JSONField( - blank=True, null=True - ), + models.JSONField(blank=True, null=True), ), ( "data_after", - django.contrib.postgres.fields.jsonb.JSONField( - blank=True, null=True - ), + models.JSONField(blank=True, null=True), ), ( "acting_user", diff --git a/klasses/models_test.py b/klasses/models_test.py index c999b96ad..d10b229af 100644 --- a/klasses/models_test.py +++ b/klasses/models_test.py @@ -138,7 +138,7 @@ def test_bootcamp_run_is_payable(future_start_date, expected_result): bootcamp_run = None if future_start_date is None: start_date = None - bootcamp_run = BootcampRunFactory.build(start_date=start_date) + bootcamp_run = BootcampRunFactory.create(start_date=start_date) elif future_start_date: start_date = now_in_utc() + timedelta(days=10) else: diff --git a/mail/urls.py b/mail/urls.py index 6683e00b6..1e6aa8fbd 100644 --- a/mail/urls.py +++ b/mail/urls.py @@ -1,7 +1,7 @@ """URL configurations for mail""" from django.conf import settings -from django.conf.urls import url +from django.urls import path from mail.views import EmailDebuggerView @@ -9,5 +9,5 @@ if settings.DEBUG: urlpatterns += [ - url(r"^__emaildebugger__/$", EmailDebuggerView.as_view(), name="email-debugger") + path("__emaildebugger__/", EmailDebuggerView.as_view(), name="email-debugger") ] diff --git a/mail/v2/verification_api_test.py b/mail/v2/verification_api_test.py index 992d1a4a4..18d704bb4 100644 --- a/mail/v2/verification_api_test.py +++ b/mail/v2/verification_api_test.py @@ -24,7 +24,7 @@ def test_send_verification_email(mocker, rf): email = "test@localhost" request = rf.post(reverse("social:complete", args=("email",)), {"email": email}) # social_django depends on request.sesssion, so use the middleware to set that - SessionMiddleware().process_request(request) + SessionMiddleware(get_response=mocker.Mock()).process_request(request) strategy = load_strategy(request) backend = load_backend(strategy, EmailAuth.name, None) code = mocker.Mock(code="abc") diff --git a/main/hijack_support_middleware.py b/main/hijack_support_middleware.py new file mode 100644 index 000000000..a431b750d --- /dev/null +++ b/main/hijack_support_middleware.py @@ -0,0 +1,18 @@ +from django.utils.deprecation import MiddlewareMixin + + +class HijackSupportMiddleware(MiddlewareMixin): + """Middleware to support HijackMiddleware""" + + def process_request(self, request): + """ + HijackMiddleware needs the session to be in accessed state in order to work properly. However, It doesn't work properly + with our current architecture and django-hijack implementation because when the request reaches HijackMiddleware the + session is not in accessed state. As a result it is unable to add the notification in DOM. + + This middleware is written to ensure that the request session has accessed=True when the request reaches HijackMiddleware. + + We will probably need to add a more robust solution to django-hijack package. + """ + if hasattr(request, "session"): + request.session.get("hijack_history", []) diff --git a/main/middleware_test.py b/main/middleware_test.py index 822578e35..09b83fb39 100644 --- a/main/middleware_test.py +++ b/main/middleware_test.py @@ -15,11 +15,11 @@ ], ) def test_cacheless_api_middleware( - rf, view, cache_value, cacheable_endpoints_cache_value + rf, view, cache_value, cacheable_endpoints_cache_value, mocker ): """Tests that the response has a cache-control header for API URLs""" request = rf.get(reverse(view)) - middleware = CachelessAPIMiddleware() + middleware = CachelessAPIMiddleware(get_response=mocker.Mock()) assert ( middleware.process_response(request, {}).get("Cache-Control", None) == cache_value diff --git a/main/settings.py b/main/settings.py index aed1711df..62f0d4c6c 100644 --- a/main/settings.py +++ b/main/settings.py @@ -127,13 +127,10 @@ "django.contrib.humanize", "rest_framework", "rest_framework.authtoken", - "server_status", "social_django", "mathfilters", - # Hijack "hijack", - "compat", - "hijack_admin", + "hijack.contrib.admin", # other third party APPS # wagtail "wagtail.contrib.forms", @@ -195,6 +192,8 @@ "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", + "hijack.middleware.HijackUserMiddleware", + "main.hijack_support_middleware.HijackSupportMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "social_django.middleware.SocialAuthExceptionMiddleware", @@ -401,8 +400,7 @@ WSGI_APPLICATION = "main.wsgi.application" # Hijack -HIJACK_ALLOW_GET_REQUESTS = True -HIJACK_LOGOUT_REDIRECT_URL = "/admin/auth/user" +HIJACK_INSERT_BEFORE = "" # Database # https://github.com/kennethreitz/dj-database-url @@ -443,7 +441,6 @@ USE_I18N = True -USE_L10N = True USE_TZ = True @@ -683,15 +680,6 @@ LOGGING["loggers"]["ui"]["handlers"] = ["console"] LOGGING["loggers"]["django"]["handlers"] = ["console"] -# server-status -STATUS_TOKEN = get_string( - name="STATUS_TOKEN", - default="", - description="Token to access the status API.", - required=True, -) -HEALTH_CHECK = ["CELERY", "REDIS", "POSTGRES", "ELASTIC_SEARCH"] - ADWORDS_CONVERSION_ID = get_string( name="ADWORDS_CONVERSION_ID", default="", description="Id for adwords conversion" ) diff --git a/main/templates/base.html b/main/templates/base.html index d0a6436b8..049576e3d 100644 --- a/main/templates/base.html +++ b/main/templates/base.html @@ -3,7 +3,7 @@ {% spaceless %} {% load static %} - {% load hijack_tags %} + {% load hijack %} {% include "gtm_head.html" %} @@ -17,11 +17,6 @@ type="text/css" href="{% url 'background-images-css' %}" /> - - {% hijack_notification %} {% include "gtm_body.html" %} {% latest_notification %} {% block headercontent %} diff --git a/main/urls.py b/main/urls.py index dc93dc58b..f54cb4126 100644 --- a/main/urls.py +++ b/main/urls.py @@ -3,7 +3,7 @@ """ from django.conf import settings -from django.conf.urls import url +from django.urls import re_path from django.conf.urls.static import static from django.urls import re_path, include, path from django.contrib import admin @@ -16,23 +16,22 @@ from main.views import react, BackgroundImagesCSSView, cms_login_redirect_view -root_urlpatterns = [url("", include(wagtail_urls))] +root_urlpatterns = [path("", include(wagtail_urls))] urlpatterns = ( [ - url(r"^status/", include("server_status.urls")), - url(r"^admin/", admin.site.urls), - url(r"^hijack/", include("hijack.urls", namespace="hijack")), - url("", include("applications.urls")), - url("", include("ecommerce.urls")), - url("", include("social_django.urls", namespace="social")), + path("admin/", admin.site.urls), + path("hijack/", include("hijack.urls")), + path("", include("applications.urls")), + path("", include("ecommerce.urls")), + path("", include("social_django.urls", namespace="social")), path("", include("authentication.urls")), path("", include("mail.urls")), path("", include("profiles.urls")), path("", include("klasses.urls")), - url("", include("jobma.urls")), - url(r"^logout/$", auth_views.LogoutView.as_view(), name="logout"), - url( + path("", include("jobma.urls")), + path("logout/", auth_views.LogoutView.as_view(), name="logout"), + re_path( r"^background-images\.css$", BackgroundImagesCSSView.as_view(), name="background-images-css", @@ -40,7 +39,7 @@ # named routes mapped to the react app path("signin/", react, name="login"), path("signin/password/", react, name="login-password"), - re_path(r"^signin/forgot-password/$", react, name="password-reset"), + path("signin/forgot-password/", react, name="password-reset"), path( "signin/forgot-password/confirm///", react, @@ -75,9 +74,9 @@ name="wagtailimages_serve", ), re_path(r"^cms/login", cms_login_redirect_view, name="wagtailadmin_login"), - re_path(r"^cms/", include(wagtailadmin_urls)), - re_path(r"^documents/", include(wagtaildocs_urls)), - re_path(r"^idp/", include("djangosaml2idp.urls")), + path("cms/", include(wagtailadmin_urls)), + path("documents/", include(wagtaildocs_urls)), + path("idp/", include("djangosaml2idp.urls")), ] + root_urlpatterns + ( diff --git a/poetry.lock b/poetry.lock index a66a9e50f..81e71ff21 100644 --- a/poetry.lock +++ b/poetry.lock @@ -919,19 +919,19 @@ static3 = "*" [[package]] name = "django" -version = "3.2.25" -description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." +version = "4.2.13" +description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "Django-3.2.25-py3-none-any.whl", hash = "sha256:a52ea7fcf280b16f7b739cec38fa6d3f8953a5456986944c3ca97e79882b4e38"}, - {file = "Django-3.2.25.tar.gz", hash = "sha256:7ca38a78654aee72378594d63e51636c04b8e28574f5505dff630895b5472777"}, + {file = "Django-4.2.13-py3-none-any.whl", hash = "sha256:a17fcba2aad3fc7d46fdb23215095dbbd64e6174bf4589171e732b18b07e426a"}, + {file = "Django-4.2.13.tar.gz", hash = "sha256:837e3cf1f6c31347a1396a3f6b65688f2b4bb4a11c580dcb628b5afe527b68a5"}, ] [package.dependencies] -asgiref = ">=3.3.2,<4" -pytz = "*" -sqlparse = ">=0.2.2" +asgiref = ">=3.6.0,<4" +sqlparse = ">=0.3.1" +tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] @@ -973,30 +973,17 @@ dev = ["black", "flake8", "therapist", "tox", "twine"] [[package]] name = "django-classy-tags" -version = "1.0.0" +version = "4.1.0" description = "Class based template tags for Django" optional = false -python-versions = "*" -files = [ - {file = "django-classy-tags-1.0.0.tar.gz", hash = "sha256:ad6a25fc2b58a098f00d86bd5e5dad47922f5ca4e744bc3cccb7b4be5bc35eb1"}, -] - -[package.dependencies] -django = ">=1.11" -six = "*" - -[[package]] -name = "django-compat" -version = "1.0.15" -description = "For- and backwards compatibility layer for Django 1.4, 1.7, 1.8, 1.9, 1.10, and 1.11" -optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "django-compat-1.0.15.tar.gz", hash = "sha256:3ac9a3bedc56b9365d9eb241bc5157d0c193769bf995f9a78dc1bc24e7c2331b"}, + {file = "django-classy-tags-4.1.0.tar.gz", hash = "sha256:c8d9d1aa2fa6e71c4d866df4dd11d23a69b8d25bbb750b2490a17b161774ee59"}, + {file = "django_classy_tags-4.1.0-py3-none-any.whl", hash = "sha256:1c784cf1bac49c20a77b8f7d1541867c64076642a160a847ff449588d4e01e55"}, ] [package.dependencies] -six = ">=1.10.0" +django = ">=3.2" [[package]] name = "django-debug-toolbar" @@ -1040,34 +1027,20 @@ files = [ [[package]] name = "django-hijack" -version = "2.3.0" +version = "3.4.5" description = "django-hijack allows superusers to hijack (=login as) and work on behalf of another user." optional = false python-versions = "*" files = [ - {file = "django-hijack-2.3.0.tar.gz", hash = "sha256:216de6ff863b5f48314795083e96267ff0829ff7f7180c26ca3c17d8a134e1cf"}, - {file = "django_hijack-2.3.0-py3-none-any.whl", hash = "sha256:8b820b6fe605cf2f3b50817985d7245285a18c027b7e3eb424d18b7908ecd2e1"}, + {file = "django-hijack-3.4.5.tar.gz", hash = "sha256:7e45b1de786bdc130628e4230b359dde6d8744ecd3bcd668d2b27c5d614a071c"}, + {file = "django_hijack-3.4.5-py3-none-any.whl", hash = "sha256:129cbe75444b163135871a947d38ffb72181f4f2583544703fc9efe083c9ddad"}, ] [package.dependencies] -django = ">=2.2" - -[[package]] -name = "django-hijack-admin" -version = "2.1.10" -description = "Django admin integration for Django Hijack (https://github.com/arteria/django-hijack/)" -optional = false -python-versions = "*" -files = [ - {file = "django-hijack-admin-2.1.10.tar.gz", hash = "sha256:330f9be331ada831248c9cee5a21202aea70fb9911b443249ce4c28d57d9e2e3"}, -] - -[package.dependencies] -django-compat = ">=1.0.13" -django-hijack = ">=2.1.5" +django = ">=3.2" [package.extras] -dev = ["flake8"] +test = ["pytest", "pytest-cov", "pytest-django"] [[package]] name = "django-ipware" @@ -1141,20 +1114,6 @@ files = [ Django = ">=2.2" redis = ">=3.0.0" -[[package]] -name = "django-server-status" -version = "0.7.3" -description = "Monitor server status with a healthcheck." -optional = false -python-versions = "*" -files = [ - {file = "django-server-status-0.7.3.tar.gz", hash = "sha256:9126e20d78c88f62ffe382c1a5c73f1206ba8dca07a8039e81e3f35f1f75941a"}, - {file = "django_server_status-0.7.3-py3-none-any.whl", hash = "sha256:2a018c731504a3c82d45717bca011c4f6b1d547f5384c9b0a04b439e9e5c3552"}, -] - -[package.dependencies] -django = "*" - [[package]] name = "django-storages" version = "1.14.3" @@ -1230,17 +1189,17 @@ files = [ [[package]] name = "djangorestframework" -version = "3.15.1" +version = "3.15.2" description = "Web APIs for Django, made easy." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "djangorestframework-3.15.1-py3-none-any.whl", hash = "sha256:3ccc0475bce968608cf30d07fb17d8e52d1d7fc8bfe779c905463200750cbca6"}, - {file = "djangorestframework-3.15.1.tar.gz", hash = "sha256:f88fad74183dfc7144b2756d0d2ac716ea5b4c7c9840995ac3bfd8ec034333c1"}, + {file = "djangorestframework-3.15.2-py3-none-any.whl", hash = "sha256:2b8871b062ba1aefc2de01f773875441a961fefbf79f5eed1e32b2f096944b20"}, + {file = "djangorestframework-3.15.2.tar.gz", hash = "sha256:36fe88cd2d6c6bec23dca9804bab2ba5517a8bb9d8f47ebc68981b56840107ad"}, ] [package.dependencies] -django = ">=3.0" +django = ">=4.2" [[package]] name = "djangorestframework-serializer-extensions" diff --git a/profiles/admin.py b/profiles/admin.py index 56fb0eea3..fa4e7d13a 100644 --- a/profiles/admin.py +++ b/profiles/admin.py @@ -6,7 +6,7 @@ from django.contrib.auth.admin import UserAdmin as ContribUserAdmin from django.contrib.auth import get_user_model from django.utils.translation import gettext_lazy as _ -from hijack_admin.admin import HijackUserAdminMixin +from hijack.contrib.admin import HijackUserAdminMixin from profiles.models import LegalAddress, Profile @@ -51,7 +51,7 @@ def has_delete_permission(self, request, obj=None): return True -class UserAdmin(ContribUserAdmin, HijackUserAdminMixin): +class UserAdmin(ContribUserAdmin): """Admin views for user""" fieldsets = ( @@ -71,7 +71,7 @@ class UserAdmin(ContribUserAdmin, HijackUserAdminMixin): }, ), ) - list_display = ("username", "email", "is_staff", "hijack_field", "last_login") + list_display = ("username", "email", "is_staff", "last_login") list_filter = ("is_staff", "is_superuser", "is_active", "groups") search_fields = ("username", "email") ordering = ("email",) diff --git a/profiles/migrations/0004_profile_smapply_user_data.py b/profiles/migrations/0004_profile_smapply_user_data.py index 6bd9e06d8..4972dca9d 100644 --- a/profiles/migrations/0004_profile_smapply_user_data.py +++ b/profiles/migrations/0004_profile_smapply_user_data.py @@ -2,8 +2,7 @@ # Generated by Django 1.11.20 on 2019-09-13 18:42 from __future__ import unicode_literals -import django.contrib.postgres.fields.jsonb -from django.db import migrations +from django.db import migrations, models class Migration(migrations.Migration): @@ -13,6 +12,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name="profile", name="smapply_user_data", - field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, null=True), + field=models.JSONField(blank=True, null=True), ) ] diff --git a/profiles/migrations/0005_profile_smapply_demographic_data.py b/profiles/migrations/0005_profile_smapply_demographic_data.py index 0b3dbb0ab..282bdf71c 100644 --- a/profiles/migrations/0005_profile_smapply_demographic_data.py +++ b/profiles/migrations/0005_profile_smapply_demographic_data.py @@ -2,8 +2,7 @@ # Generated by Django 1.11.20 on 2019-09-23 17:26 from __future__ import unicode_literals -import django.contrib.postgres.fields.jsonb -from django.db import migrations +from django.db import migrations, models class Migration(migrations.Migration): @@ -13,6 +12,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name="profile", name="smapply_demographic_data", - field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, null=True), + field=models.JSONField(blank=True, null=True), ) ] diff --git a/profiles/urls.py b/profiles/urls.py index 3f19cfa55..67096ad52 100644 --- a/profiles/urls.py +++ b/profiles/urls.py @@ -1,6 +1,6 @@ """User url routes""" -from django.conf.urls import include +from django.urls import include from django.urls import path from rest_framework import routers diff --git a/pyproject.toml b/pyproject.toml index 490a0efa6..2d57486e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,28 +33,24 @@ authors = ["MIT ODL"] [tool.poetry.dependencies] python = "3.10.13" -django = "^3.2.25" -celery = {extras = ["redis"], version = "^5.2.7"} +django = "^4.2.13" +celery = {extras = ["redis"], version = "^5.3.6"} boto3 = "^1.16.63" dj-database-url = "^0.5.0" django-anymail = {extras = ["mailgun"], version = "^8.4"} dj-static = "^0.0.6" django-cache-memoize = "^0.2.0" -django-classy-tags = "^1.0.0" -django-compat = "^1.0.15" -django-hijack = "^2.1.10" -django-hijack-admin = "^2.1.7" +django-classy-tags = "^4.1.0" +django-hijack = "^3.4.5" django-filter = "^23.4" django-fsm = "^2.8.0" django-ipware = "^4.0.0" django-mathfilters = "^1.0.0" django-redis = "^5.0.0" -django-server-status = "^0.7.3" django-webpack-loader = "^0.7.0" -djangorestframework = "^3.11.2" +djangorestframework = "^3.15.2" djangorestframework-serializer-extensions = "^2.0.0" djangosaml2idp = { git = "https://github.com/OTA-Insight/djangosaml2idp.git", rev = "0b4325782a6fd2c034677b5923041b5df10087ec" } # pragma: allowlist secret -djoser = "^2.1.0" dynamic-rest = "^2.1.2" html5lib = "^1.1" hubspot-api-client = "^6.1.0" @@ -98,7 +94,7 @@ pdbpp = "^0.10.2" pip-tools = "^7.1.0" pylint = "~2.17.0" pylint-django = "~2.5.0" -pytest = "^7.0.0" +pytest = "^7.4.4" pytest-cov = "^2.6.1" pytest-env = "^0.8.0" pytest-django = "^4.0.0"