From 47f37480285e8c962d90556c9f71ad877d1c510b Mon Sep 17 00:00:00 2001 From: Zubair Shakoor <57657330+zubairshakoorarbisoft@users.noreply.github.com> Date: Wed, 6 Sep 2023 18:13:46 +0500 Subject: [PATCH] fix: Added support for djang42 and codemod applied (#1829) --- .github/workflows/ci.yml | 6 +- CHANGELOG.rst | 4 + Makefile | 2 +- consent/__init__.py | 2 - consent/admin/__init__.py | 16 ++-- enterprise/__init__.py | 4 +- enterprise/admin/__init__.py | 81 ++++++++++++------- enterprise/urls.py | 72 ++++++++++------- enterprise/utils.py | 3 +- enterprise_learner_portal/api/urls.py | 9 ++- integrated_channels/blackboard/__init__.py | 3 - .../blackboard/admin/__init__.py | 6 +- integrated_channels/canvas/__init__.py | 3 - integrated_channels/canvas/admin/__init__.py | 6 +- integrated_channels/cornerstone/__init__.py | 3 - .../cornerstone/admin/__init__.py | 6 +- integrated_channels/degreed/__init__.py | 3 - integrated_channels/degreed/admin/__init__.py | 6 +- integrated_channels/degreed2/__init__.py | 3 - .../degreed2/admin/__init__.py | 6 +- .../integrated_channel/__init__.py | 3 - integrated_channels/moodle/__init__.py | 3 - integrated_channels/moodle/admin/__init__.py | 6 +- .../sap_success_factors/__init__.py | 3 - .../sap_success_factors/admin/__init__.py | 13 +-- integrated_channels/xapi/__init__.py | 3 - integrated_channels/xapi/admin/__init__.py | 6 +- requirements/{celery50.txt => celery53.txt} | 0 .../test_canvas/test_client.py | 4 +- .../test_canvas/test_utils.py | 4 +- .../test_exporters/test_learner_data.py | 3 +- .../test_degreed/test_client.py | 4 +- .../test_exporters/test_learner_data.py | 4 +- .../test_degreed2/test_client.py | 3 +- .../test_exporters/test_learner_data.py | 4 +- .../test_exporters/test_learner_data.py | 2 +- tests/test_middleware.py | 16 ++-- tests/test_migrations.py | 6 ++ tox.ini | 5 +- 39 files changed, 172 insertions(+), 164 deletions(-) rename requirements/{celery50.txt => celery53.txt} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5dedafcdd..5c77c86867 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: fail-fast: false matrix: python-version: ['3.8'] - toxenv: [quality, docs, django32-celery50, django32-pii-annotations] + toxenv: [quality, docs, django32-celery53, django42-celery53, django32-pii-annotations] env: RUNJSHINT: true steps: @@ -37,13 +37,13 @@ jobs: TOXENV: ${{ matrix.toxenv }} run: tox - name: Run code coverage - if: matrix.python-version == '3.8' && matrix.toxenv == 'django32' + if: matrix.python-version == '3.8' && matrix.toxenv == 'django42' uses: codecov/codecov-action@v3 with: flags: unittests fail_ci_if_error: true - name: Run jshint - if: matrix.toxenv=='django32-celery50' # Only run this once as part of tests + if: matrix.toxenv=='django42-celery53' # Only run this once as part of tests run: | npm ci make jshint diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a7ee3ff691..79db34f97e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,10 @@ Change Log Unreleased ---------- +[4.1.8] +-------- +Added support for Django 4.2 + [4.1.7] ------- fix: enterprise api credentials endpoint cleanup. diff --git a/Makefile b/Makefile index ab68322dab..bbe87de9e4 100644 --- a/Makefile +++ b/Makefile @@ -117,7 +117,7 @@ upgrade: requirements check_pins ## update the requirements/*.txt files with the # This section removes django from test.txt to # let tox control the Django version for tests grep -e "^django==" requirements/test.txt > requirements/django.txt - grep -e "^amqp==\|^anyjson==\|^billiard==\|^celery==\|^kombu==\|^click-didyoumean==\|^click-repl==\|^click==\|^prompt-toolkit==\|^vine==" requirements/dev.txt > requirements/celery50.txt + grep -e "^amqp==\|^anyjson==\|^billiard==\|^celery==\|^kombu==\|^click-didyoumean==\|^click-repl==\|^click==\|^prompt-toolkit==\|^vine==" requirements/dev.txt > requirements/celery53.txt sed -i.tmp '/^[d|D]jango==/d' requirements/test.txt sed -i.tmp '/^amqp==/d' requirements/test.txt sed -i.tmp '/^anyjson==/d' requirements/test.txt diff --git a/consent/__init__.py b/consent/__init__.py index 2db5c1cc91..478467aa98 100644 --- a/consent/__init__.py +++ b/consent/__init__.py @@ -12,5 +12,3 @@ """ __version__ = "0.1.0" - -default_app_config = "consent.apps.ConsentConfig" diff --git a/consent/admin/__init__.py b/consent/admin/__init__.py index 4aba438eae..6e2c0f4190 100644 --- a/consent/admin/__init__.py +++ b/consent/admin/__init__.py @@ -94,12 +94,22 @@ def preview(self, consent_page, course_id='', program_uuid=''): url = reverse('grant_data_sharing_permissions') + '?{}'.format(urlencode(params)) return HttpResponseRedirect(url) + @admin.action( + description=_( + "Preview the data sharing consent page rendered in the context of a course enrollment." + ) + ) def preview_as_course(self, request, consent_page): """ Renders data sharing consent page in course context """ return self.preview(consent_page, course_id='course-v1:edX+TestX+Test_Course') + @admin.action( + description=_( + "Preview the data sharing consent page rendered in the context of a program enrollment." + ) + ) def preview_as_program(self, request, consent_page): """ Renders data sharing consent page in program context @@ -107,13 +117,7 @@ def preview_as_program(self, request, consent_page): return self.preview(consent_page, program_uuid='25c10a26-0b00-0000-bd06-7813546c29eb') preview_as_course.label = _("Preview (course)") - preview_as_course.short_description = _( - "Preview the data sharing consent page rendered in the context of a course enrollment." - ) preview_as_program.label = _("Preview (program)") - preview_as_program.short_description = _( - "Preview the data sharing consent page rendered in the context of a program enrollment." - ) class Meta: """ diff --git a/enterprise/__init__.py b/enterprise/__init__.py index 7f024b50d2..57ab7b0f66 100644 --- a/enterprise/__init__.py +++ b/enterprise/__init__.py @@ -2,6 +2,4 @@ Your project description goes here. """ -__version__ = "4.1.7" - -default_app_config = "enterprise.apps.EnterpriseConfig" +__version__ = "4.1.8" diff --git a/enterprise/admin/__init__.py b/enterprise/admin/__init__.py index cdaa16881d..8b94f5e499 100644 --- a/enterprise/admin/__init__.py +++ b/enterprise/admin/__init__.py @@ -139,14 +139,15 @@ class PendingEnterpriseCustomerAdminUserInline(admin.TabularInline): 'get_admin_registration_url', ) + @admin.display( + description='Admin Registration Link' + ) def get_admin_registration_url(self, obj): """ Formats the ``admin_registration_url`` model property as an HTML link. """ return format_html('{0}'.format(obj.admin_registration_url)) - get_admin_registration_url.short_description = 'Admin Registration Link' - @admin.register(EnterpriseCustomerType) class EnterpriseCustomerTypeAdmin(admin.ModelAdmin): @@ -288,6 +289,10 @@ def get_form(self, request, obj=None, change=False, **kwargs): form.user = request.user return form + @admin.display( + description='Enable DSC', + boolean=True, + ) def enable_dsc(self, instance): """ Return True if data sharing consent is enabled for EnterpriseCustomer. @@ -297,9 +302,10 @@ def enable_dsc(self, instance): """ return instance.enable_data_sharing_consent - enable_dsc.boolean = True - enable_dsc.short_description = 'Enable DSC' - + @admin.display( + description='Logo', + boolean=True, + ) def has_logo(self, instance): """ Return True if EnterpriseCustomer has a logo. @@ -313,9 +319,10 @@ def has_logo(self, instance): return has_logo - has_logo.boolean = True - has_logo.short_description = 'Logo' - + @admin.display( + description='Identity provider', + boolean=True, + ) def has_identity_provider(self, instance): """ Return True if EnterpriseCustomer has related identity provider. @@ -325,9 +332,9 @@ def has_identity_provider(self, instance): """ return instance.has_identity_providers - has_identity_provider.boolean = True - has_identity_provider.short_description = 'Identity provider' - + @admin.action( + description="Clear Data Sharing Consent for a Learner." + ) def manage_learners_data_sharing_consent(self, request, obj): """ Object tool handler method - redirects to "Clear Learners Data Sharing Consent" view @@ -336,8 +343,10 @@ def manage_learners_data_sharing_consent(self, request, obj): return HttpResponseRedirect(reverse("admin:" + UrlNames.MANAGE_LEARNERS_DSC, args=(obj.uuid,))) manage_learners_data_sharing_consent.label = "Clear Data Sharing Consent" - manage_learners_data_sharing_consent.short_description = "Clear Data Sharing Consent for a Learner." + @admin.action( + description="Allows managing learners for this Enterprise Customer" + ) def manage_learners(self, request, obj): """ Object tool handler method - redirects to "Manage Learners" view @@ -347,8 +356,10 @@ def manage_learners(self, request, obj): return HttpResponseRedirect(manage_learners_url) manage_learners.label = "Manage Learners" - manage_learners.short_description = "Allows managing learners for this Enterprise Customer" + @admin.action( + description='Transmit courses metadata for this Enterprise Customer' + ) def transmit_courses_metadata(self, request, obj): """ Object tool handler method - redirects to `Transmit Courses Metadata` view. @@ -358,7 +369,6 @@ def transmit_courses_metadata(self, request, obj): return HttpResponseRedirect(transmit_courses_metadata_url) transmit_courses_metadata.label = 'Transmit Courses Metadata' - transmit_courses_metadata.short_description = 'Transmit courses metadata for this Enterprise Customer' def get_urls(self): """ @@ -419,12 +429,14 @@ class Meta: list_display = ('username', 'user_email', 'get_enterprise_customer') search_fields = ('user_id',) + @admin.display( + description='Enterprise Customer' + ) def get_enterprise_customer(self, obj): """ Returns the name of enterprise customer linked with the enterprise customer user. """ return obj.enterprise_customer.name - get_enterprise_customer.short_description = 'Enterprise Customer' def get_search_results(self, request, queryset, search_term): search_term = search_term.strip() @@ -577,22 +589,24 @@ class Meta: 'enterprise_customer__name', ) + @admin.display( + description='Enterprise Customer' + ) def get_enterprise_customer(self, obj): """ Returns the name of the associated EnterpriseCustomer. """ return obj.enterprise_customer.name - get_enterprise_customer.short_description = 'Enterprise Customer' - + @admin.display( + description='Admin Registration Link' + ) def get_admin_registration_url(self, obj): """ Formats the ``admin_registration_url`` model property as an HTML link. """ return format_html('{0}'.format(obj.admin_registration_url)) - get_admin_registration_url.short_description = 'Admin Registration Link' - @admin.register(EnrollmentNotificationEmailTemplate) class EnrollmentNotificationEmailTemplateAdmin(DjangoObjectActions, admin.ModelAdmin): @@ -625,6 +639,11 @@ def preview(self, obj, preview_type): preview_url = reverse("admin:" + UrlNames.PREVIEW_EMAIL_TEMPLATE, args=(obj.pk, preview_type)) return HttpResponseRedirect(preview_url) + @admin.action( + description=_( + "Preview the HTML template rendered in the context of a course enrollment." + ) + ) def preview_as_course(self, request, obj): """ Redirect to preview the HTML template in the context of a course. @@ -632,10 +651,12 @@ def preview_as_course(self, request, obj): return self.preview(obj, 'course') preview_as_course.label = _("Preview (course)") - preview_as_course.short_description = _( - "Preview the HTML template rendered in the context of a course enrollment." - ) + @admin.action( + description=_( + "Preview the HTML template rendered in the context of a program enrollment." + ) + ) def preview_as_program(self, request, obj): """ Redirect to preview the HTML template in the context of a program. @@ -643,9 +664,6 @@ def preview_as_program(self, request, obj): return self.preview(obj, 'program') preview_as_program.label = _("Preview (program)") - preview_as_program.short_description = _( - "Preview the HTML template rendered in the context of a program enrollment." - ) @admin.register(EnterpriseCourseEnrollment) @@ -780,6 +798,9 @@ def get_urls(self): 'include_exec_ed_2u_courses', ) + @admin.display( + description='Preview Catalog Courses' + ) def discovery_query_url(self, obj): """ Return discovery url for preview. @@ -794,8 +815,6 @@ def has_delete_permission(self, request, obj=None): return False readonly_fields = ('discovery_query_url', 'uuid') - discovery_query_url.allow_tags = True - discovery_query_url.short_description = 'Preview Catalog Courses' @admin.register(EnterpriseCustomerCatalog) @@ -835,6 +854,9 @@ class Media: 'publish_audit_enrollment_urls', ) + @admin.display( + description='Preview Catalog Courses' + ) def preview_catalog_url(self, obj): """ Return enterprise catalog url for preview. @@ -847,14 +869,15 @@ def preview_catalog_url(self, obj): ) readonly_fields = ('preview_catalog_url',) - preview_catalog_url.short_description = 'Preview Catalog Courses' + @admin.display( + description='UUID' + ) def uuid_nowrap(self, obj): """ Inject html for disabling wrap for uuid """ return format_html('{uuid}'.format(uuid=obj.uuid)) - uuid_nowrap.short_description = 'UUID' def get_form(self, request, obj=None, change=False, **kwargs): form = super().get_form(request, obj, change, **kwargs) diff --git a/enterprise/urls.py b/enterprise/urls.py index f2b79bf961..ff8035537e 100644 --- a/enterprise/urls.py +++ b/enterprise/urls.py @@ -3,8 +3,7 @@ """ from django.conf import settings -from django.conf.urls import include -from django.urls import re_path +from django.urls import include, re_path from enterprise.constants import COURSE_KEY_URL_PATTERN from enterprise.heartbeat.views import heartbeat @@ -48,34 +47,51 @@ ENTERPRISE_ROUTER, name='enterprise_course_run_enrollment_page' ), - re_path(r'^enterprise/(?P[^/]+)/program/(?P[^/]+)/enroll/$', ENTERPRISE_ROUTER, - name='enterprise_program_enrollment_page' - ), - re_path(r'^enterprise/api/', include('enterprise.api.urls'), - name='enterprise_api' - ), - re_path(r'^enterprise/heartbeat/', heartbeat, - name='enterprise_heartbeat', - ), + re_path( + r'^enterprise/(?P[^/]+)/program/(?P[^/]+)/enroll/$', + ENTERPRISE_ROUTER, + name='enterprise_program_enrollment_page' + ), + re_path( + r'^enterprise/api/', + include('enterprise.api.urls'), + name='enterprise_api' + ), + re_path( + r'^enterprise/heartbeat/', heartbeat, + name='enterprise_heartbeat', + ), ] # Because ROOT_URLCONF points here, we are including the urls from the other apps here for now. urlpatterns += [ - re_path('', include('consent.urls'), - name='consent' - ), - re_path(r'^cornerstone/', include('integrated_channels.cornerstone.urls'), - name='cornerstone' - ), - re_path(r'^canvas/', include('integrated_channels.canvas.urls'), - name='canvas', - ), - re_path(r'^blackboard/', include('integrated_channels.blackboard.urls'), - name='blackboard', - ), - re_path(r'^enterprise_learner_portal/', include('enterprise_learner_portal.urls'), - name='enterprise_learner_portal_api' - ), - re_path(r'^integrated_channels/api/', include('integrated_channels.api.urls') - ), + re_path( + '', + include('consent.urls'), + name='consent' + ), + re_path( + r'^cornerstone/', + include('integrated_channels.cornerstone.urls'), + name='cornerstone' + ), + re_path( + r'^canvas/', + include('integrated_channels.canvas.urls'), + name='canvas', + ), + re_path( + r'^blackboard/', + include('integrated_channels.blackboard.urls'), + name='blackboard', + ), + re_path( + r'^enterprise_learner_portal/', + include('enterprise_learner_portal.urls'), + name='enterprise_learner_portal_api' + ), + re_path( + r'^integrated_channels/api/', + include('integrated_channels.api.urls') + ), ] diff --git a/enterprise/utils.py b/enterprise/utils.py index 577dcd1bbf..0ac1e1bb3d 100644 --- a/enterprise/utils.py +++ b/enterprise/utils.py @@ -27,7 +27,6 @@ from django.http import Http404 from django.shortcuts import get_object_or_404 from django.urls import reverse -from django.utils import timezone from django.utils.dateparse import parse_datetime from django.utils.html import format_html from django.utils.text import slugify @@ -2289,7 +2288,7 @@ def parse_lms_api_datetime(datetime_string, datetime_format=LMS_API_DATETIME_FOR # Note that if we're using the default LMS_API_DATETIME_FORMAT, it ends in 'Z', # which denotes UTC for ISO-8661. if date_time.tzinfo is None: - date_time = date_time.replace(tzinfo=timezone.utc) + date_time = date_time.replace(tzinfo=datetime.timezone.utc) return date_time diff --git a/enterprise_learner_portal/api/urls.py b/enterprise_learner_portal/api/urls.py index 8dbebeba7d..5eaecef295 100644 --- a/enterprise_learner_portal/api/urls.py +++ b/enterprise_learner_portal/api/urls.py @@ -2,9 +2,12 @@ URL definitions for enterprise_learner_portal API endpoint. """ -from django.conf.urls import include -from django.urls import path +from django.urls import include, path urlpatterns = [ - path('v1/', include('enterprise_learner_portal.api.v1.urls'), name='v1') + path( + 'v1/', + include('enterprise_learner_portal.api.v1.urls'), + name='v1' + ) ] diff --git a/integrated_channels/blackboard/__init__.py b/integrated_channels/blackboard/__init__.py index 121b50e60c..acdee8122c 100644 --- a/integrated_channels/blackboard/__init__.py +++ b/integrated_channels/blackboard/__init__.py @@ -3,6 +3,3 @@ """ __version__ = "0.0.1" - -default_app_config = ("integrated_channels.blackboard.apps." - "BlackboardConfig") diff --git a/integrated_channels/blackboard/admin/__init__.py b/integrated_channels/blackboard/admin/__init__.py index cff999e5f9..5db9403257 100644 --- a/integrated_channels/blackboard/admin/__init__.py +++ b/integrated_channels/blackboard/admin/__init__.py @@ -82,6 +82,9 @@ def customer_oauth_authorization_url(self, obj): else: return None + @admin.action( + description="Force content metadata transmission for this Enterprise Customer" + ) def force_content_metadata_transmission(self, request, obj): """ Updates the modified time of the customer record to retransmit courses metadata @@ -106,9 +109,6 @@ def force_content_metadata_transmission(self, request, obj): "/admin/blackboard/blackboardenterprisecustomerconfiguration" ) force_content_metadata_transmission.label = "Force content metadata transmission" - force_content_metadata_transmission.short_description = ( - "Force content metadata transmission for this Enterprise Customer" - ) @admin.register(BlackboardLearnerDataTransmissionAudit) diff --git a/integrated_channels/canvas/__init__.py b/integrated_channels/canvas/__init__.py index 9423885f05..b1b37747cd 100644 --- a/integrated_channels/canvas/__init__.py +++ b/integrated_channels/canvas/__init__.py @@ -3,6 +3,3 @@ """ __version__ = "0.0.1" - -default_app_config = ("integrated_channels.canvas.apps." - "CanvasConfig") diff --git a/integrated_channels/canvas/admin/__init__.py b/integrated_channels/canvas/admin/__init__.py index 4a0c475813..fab5df5520 100644 --- a/integrated_channels/canvas/admin/__init__.py +++ b/integrated_channels/canvas/admin/__init__.py @@ -66,6 +66,9 @@ def customer_oauth_authorization_url(self, obj): else: return None + @admin.action( + description="Force content metadata transmission for this Enterprise Customer" + ) def force_content_metadata_transmission(self, request, obj): """ Updates the modified time of the customer record to retransmit courses metadata @@ -90,9 +93,6 @@ def force_content_metadata_transmission(self, request, obj): "/admin/canvas/canvasenterprisecustomerconfiguration" ) force_content_metadata_transmission.label = "Force content metadata transmission" - force_content_metadata_transmission.short_description = ( - "Force content metadata transmission for this Enterprise Customer" - ) @admin.register(CanvasLearnerDataTransmissionAudit) diff --git a/integrated_channels/cornerstone/__init__.py b/integrated_channels/cornerstone/__init__.py index 55d0166147..dcf7cd24e2 100644 --- a/integrated_channels/cornerstone/__init__.py +++ b/integrated_channels/cornerstone/__init__.py @@ -3,6 +3,3 @@ """ __version__ = "0.1.0" - -default_app_config = ("integrated_channels.cornerstone.apps." - "CornerstoneConfig") diff --git a/integrated_channels/cornerstone/admin/__init__.py b/integrated_channels/cornerstone/admin/__init__.py index 8edd01a41a..cb9c791e49 100644 --- a/integrated_channels/cornerstone/admin/__init__.py +++ b/integrated_channels/cornerstone/admin/__init__.py @@ -72,6 +72,9 @@ def enterprise_customer_name(self, obj): """ return obj.enterprise_customer.name + @admin.action( + description="Force content metadata transmission for this Enterprise Customer" + ) def force_content_metadata_transmission(self, request, obj): """ Updates the modified time of the customer record to retransmit courses metadata @@ -96,9 +99,6 @@ def force_content_metadata_transmission(self, request, obj): "/admin/cornerstone/cornerstoneenterprisecustomerconfiguration" ) force_content_metadata_transmission.label = "Force content metadata transmission" - force_content_metadata_transmission.short_description = ( - "Force content metadata transmission for this Enterprise Customer" - ) @admin.register(CornerstoneLearnerDataTransmissionAudit) diff --git a/integrated_channels/degreed/__init__.py b/integrated_channels/degreed/__init__.py index e05bf873af..e5ac1a15de 100644 --- a/integrated_channels/degreed/__init__.py +++ b/integrated_channels/degreed/__init__.py @@ -3,6 +3,3 @@ """ __version__ = "0.1.0" - -default_app_config = ("integrated_channels.degreed.apps." - "DegreedConfig") diff --git a/integrated_channels/degreed/admin/__init__.py b/integrated_channels/degreed/admin/__init__.py index 6b3f65e066..003c5f049f 100644 --- a/integrated_channels/degreed/admin/__init__.py +++ b/integrated_channels/degreed/admin/__init__.py @@ -76,6 +76,9 @@ def enterprise_customer_name(self, obj): """ return obj.enterprise_customer.name + @admin.action( + description="Force content metadata transmission for this Enterprise Customer" + ) def force_content_metadata_transmission(self, request, obj): """ Updates the modified time of the customer record to retransmit courses metadata @@ -101,9 +104,6 @@ def force_content_metadata_transmission(self, request, obj): ) force_content_metadata_transmission.label = "Force content metadata transmission" - force_content_metadata_transmission.short_description = ( - "Force content metadata transmission for this Enterprise Customer" - ) @admin.register(DegreedLearnerDataTransmissionAudit) diff --git a/integrated_channels/degreed2/__init__.py b/integrated_channels/degreed2/__init__.py index 3f4c8a4523..6938444cac 100644 --- a/integrated_channels/degreed2/__init__.py +++ b/integrated_channels/degreed2/__init__.py @@ -4,6 +4,3 @@ """ __version__ = "0.0.1" - -default_app_config = ("integrated_channels.degreed2.apps." - "Degreed2Config") diff --git a/integrated_channels/degreed2/admin/__init__.py b/integrated_channels/degreed2/admin/__init__.py index 3db51fe7b0..d883d051a1 100644 --- a/integrated_channels/degreed2/admin/__init__.py +++ b/integrated_channels/degreed2/admin/__init__.py @@ -56,6 +56,9 @@ def enterprise_customer_name(self, obj): """ return obj.enterprise_customer.name + @admin.action( + description="Force content metadata transmission for this Enterprise Customer" + ) def force_content_metadata_transmission(self, request, obj): """ Updates the modified time of the customer record to retransmit courses metadata @@ -78,9 +81,6 @@ def force_content_metadata_transmission(self, request, obj): ) return HttpResponseRedirect('/admin/degreed2/degreed2enterprisecustomerconfiguration') force_content_metadata_transmission.label = "Force content metadata transmission" - force_content_metadata_transmission.short_description = ( - "Force content metadata transmission for this Enterprise Customer" - ) @admin.register(Degreed2LearnerDataTransmissionAudit) diff --git a/integrated_channels/integrated_channel/__init__.py b/integrated_channels/integrated_channel/__init__.py index 3a814f28da..1d910ddb59 100644 --- a/integrated_channels/integrated_channel/__init__.py +++ b/integrated_channels/integrated_channel/__init__.py @@ -3,6 +3,3 @@ """ __version__ = "0.1.0" - -default_app_config = ("integrated_channels.integrated_channel.apps." - "IntegratedChannelConfig") diff --git a/integrated_channels/moodle/__init__.py b/integrated_channels/moodle/__init__.py index 8d7a60ded7..51eb20f9bd 100644 --- a/integrated_channels/moodle/__init__.py +++ b/integrated_channels/moodle/__init__.py @@ -3,6 +3,3 @@ """ __version__ = "0.1.0" - -default_app_config = ("integrated_channels.moodle.apps." - "MoodleConfig") diff --git a/integrated_channels/moodle/admin/__init__.py b/integrated_channels/moodle/admin/__init__.py index 856e7550f5..81156462a5 100644 --- a/integrated_channels/moodle/admin/__init__.py +++ b/integrated_channels/moodle/admin/__init__.py @@ -46,6 +46,9 @@ class MoodleEnterpriseCustomerConfigurationAdmin(DjangoObjectActions, admin.Mode form = MoodleEnterpriseCustomerConfigurationForm change_actions = ('force_content_metadata_transmission',) + @admin.action( + description="Force content metadata transmission for this Enterprise Customer" + ) def force_content_metadata_transmission(self, request, obj): """ Updates the modified time of the customer record to retransmit courses metadata @@ -70,9 +73,6 @@ def force_content_metadata_transmission(self, request, obj): "/admin/moodle/moodleenterprisecustomerconfiguration" ) force_content_metadata_transmission.label = "Force content metadata transmission" - force_content_metadata_transmission.short_description = ( - "Force content metadata transmission for this Enterprise Customer" - ) @admin.register(MoodleLearnerDataTransmissionAudit) diff --git a/integrated_channels/sap_success_factors/__init__.py b/integrated_channels/sap_success_factors/__init__.py index e404acaabc..cdf89f0ba8 100644 --- a/integrated_channels/sap_success_factors/__init__.py +++ b/integrated_channels/sap_success_factors/__init__.py @@ -3,6 +3,3 @@ """ __version__ = "0.1.0" - -default_app_config = ("integrated_channels.sap_success_factors.apps." - "SAPSuccessFactorsConfig") diff --git a/integrated_channels/sap_success_factors/admin/__init__.py b/integrated_channels/sap_success_factors/admin/__init__.py index d553a4b6b6..be8cb305af 100644 --- a/integrated_channels/sap_success_factors/admin/__init__.py +++ b/integrated_channels/sap_success_factors/admin/__init__.py @@ -92,6 +92,10 @@ def enterprise_customer_name(self, obj): """ return obj.enterprise_customer.name + @admin.display( + description="Has Access Token?", + boolean=True, + ) def has_access_token(self, obj): """ Confirms the presence and validity of the access token for the SAP SuccessFactors client instance @@ -116,9 +120,9 @@ def has_access_token(self, obj): return False return bool(access_token and expires_at) - has_access_token.boolean = True - has_access_token.short_description = "Has Access Token?" - + @admin.action( + description="Force content metadata transmission for this Enterprise Customer" + ) def force_content_metadata_transmission(self, request, obj): """ Updates the modified time of the customer record to retransmit courses metadata @@ -143,9 +147,6 @@ def force_content_metadata_transmission(self, request, obj): "/admin/sap_success_factors/sapsuccessfactorsenterprisecustomerconfiguration" ) force_content_metadata_transmission.label = "Force content metadata transmission" - force_content_metadata_transmission.short_description = ( - "Force content metadata transmission for this Enterprise Customer" - ) @admin.register(SapSuccessFactorsLearnerDataTransmissionAudit) diff --git a/integrated_channels/xapi/__init__.py b/integrated_channels/xapi/__init__.py index e1f24df291..67c435231c 100644 --- a/integrated_channels/xapi/__init__.py +++ b/integrated_channels/xapi/__init__.py @@ -3,6 +3,3 @@ """ __version__ = "0.1.0" - -default_app_config = ("integrated_channels.xapi.apps." - "XAPIConfig") diff --git a/integrated_channels/xapi/admin/__init__.py b/integrated_channels/xapi/admin/__init__.py index 23914537ca..c5cf425529 100644 --- a/integrated_channels/xapi/admin/__init__.py +++ b/integrated_channels/xapi/admin/__init__.py @@ -52,6 +52,9 @@ def enterprise_customer_name(self, obj): """ return obj.enterprise_customer.name + @admin.action( + description="Force content metadata transmission for this Enterprise Customer" + ) def force_content_metadata_transmission(self, request, obj): """ Updates the modified time of the customer record to retransmit courses metadata @@ -74,6 +77,3 @@ def force_content_metadata_transmission(self, request, obj): ) return HttpResponseRedirect("/admin/xapi/xapilrsconfiguration/") force_content_metadata_transmission.label = "Force content metadata transmission" - force_content_metadata_transmission.short_description = ( - "Force content metadata transmission for this Enterprise Customer" - ) diff --git a/requirements/celery50.txt b/requirements/celery53.txt similarity index 100% rename from requirements/celery50.txt rename to requirements/celery53.txt diff --git a/tests/test_integrated_channels/test_canvas/test_client.py b/tests/test_integrated_channels/test_canvas/test_client.py index be85a2dbb2..a7944aaf81 100644 --- a/tests/test_integrated_channels/test_canvas/test_client.py +++ b/tests/test_integrated_channels/test_canvas/test_client.py @@ -14,15 +14,13 @@ from freezegun import freeze_time from requests.models import Response -from django.utils import timezone - from integrated_channels.canvas.client import MESSAGE_WHEN_COURSE_WAS_DELETED, CanvasAPIClient from integrated_channels.canvas.utils import CanvasUtil from integrated_channels.exceptions import ClientError from integrated_channels.integrated_channel.client import IntegratedChannelHealthStatus from test_utils import factories -NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=timezone.utc) +NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc) NOW_TIMESTAMP_FORMATTED = NOW.strftime('%F') diff --git a/tests/test_integrated_channels/test_canvas/test_utils.py b/tests/test_integrated_channels/test_canvas/test_utils.py index 1cbd39d6ad..6898747db5 100644 --- a/tests/test_integrated_channels/test_canvas/test_utils.py +++ b/tests/test_integrated_channels/test_canvas/test_utils.py @@ -10,14 +10,12 @@ import pytest from requests.models import Response -from django.utils import timezone - from integrated_channels.canvas.utils import CanvasUtil from integrated_channels.exceptions import ClientError from integrated_channels.utils import refresh_session_if_expired from test_utils import factories -NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=timezone.utc) +NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc) NOW_TIMESTAMP_FORMATTED = NOW.strftime('%F') diff --git a/tests/test_integrated_channels/test_cornerstone/test_exporters/test_learner_data.py b/tests/test_integrated_channels/test_cornerstone/test_exporters/test_learner_data.py index a0a98164e9..964f9810f7 100644 --- a/tests/test_integrated_channels/test_cornerstone/test_exporters/test_learner_data.py +++ b/tests/test_integrated_channels/test_cornerstone/test_exporters/test_learner_data.py @@ -14,7 +14,6 @@ from requests.compat import urljoin from django.core.management import call_command -from django.utils import timezone from enterprise.api_client import lms as lms_api from integrated_channels.cornerstone.exporters.learner_data import CornerstoneLearnerExporter @@ -32,7 +31,7 @@ class TestCornerstoneLearnerExporter(unittest.TestCase): Tests of CornerstoneLearnerExporter class. """ - NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=timezone.utc) + NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc) def setUp(self): self.user = factories.UserFactory() diff --git a/tests/test_integrated_channels/test_degreed/test_client.py b/tests/test_integrated_channels/test_degreed/test_client.py index 5a4aade85f..4588586a92 100644 --- a/tests/test_integrated_channels/test_degreed/test_client.py +++ b/tests/test_integrated_channels/test_degreed/test_client.py @@ -12,13 +12,11 @@ import responses from freezegun import freeze_time -from django.utils import timezone - from integrated_channels.degreed.client import DegreedAPIClient from integrated_channels.exceptions import ClientError from test_utils import factories -NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=timezone.utc) +NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc) NOW_TIMESTAMP_FORMATTED = NOW.strftime('%F') diff --git a/tests/test_integrated_channels/test_degreed/test_exporters/test_learner_data.py b/tests/test_integrated_channels/test_degreed/test_exporters/test_learner_data.py index b7f4ba71a9..b70466f4f8 100644 --- a/tests/test_integrated_channels/test_degreed/test_exporters/test_learner_data.py +++ b/tests/test_integrated_channels/test_degreed/test_exporters/test_learner_data.py @@ -11,8 +11,6 @@ from freezegun import freeze_time from pytest import mark -from django.utils import timezone - from integrated_channels.degreed.exporters.learner_data import DegreedLearnerExporter from test_utils import factories from test_utils.fake_catalog_api import setup_course_catalog_api_client_mock @@ -25,7 +23,7 @@ class TestDegreedLearnerExporter(unittest.TestCase): Tests of DegreedLearnerExporter class. """ - NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=timezone.utc) + NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc) NOW_TIMESTAMP = 1483326245000 def setUp(self): diff --git a/tests/test_integrated_channels/test_degreed2/test_client.py b/tests/test_integrated_channels/test_degreed2/test_client.py index 579dabc21e..d35193e5ee 100644 --- a/tests/test_integrated_channels/test_degreed2/test_client.py +++ b/tests/test_integrated_channels/test_degreed2/test_client.py @@ -15,13 +15,12 @@ from six.moves.urllib.parse import urljoin from django.apps.registry import apps -from django.utils import timezone from integrated_channels.degreed2.client import Degreed2APIClient from integrated_channels.exceptions import ClientError from test_utils import factories -NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=timezone.utc) +NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc) NOW_TIMESTAMP_FORMATTED = NOW.strftime('%F') app_config = apps.get_app_config("degreed2") diff --git a/tests/test_integrated_channels/test_degreed2/test_exporters/test_learner_data.py b/tests/test_integrated_channels/test_degreed2/test_exporters/test_learner_data.py index 2ec4aeb7a9..e251ba21ee 100644 --- a/tests/test_integrated_channels/test_degreed2/test_exporters/test_learner_data.py +++ b/tests/test_integrated_channels/test_degreed2/test_exporters/test_learner_data.py @@ -12,8 +12,6 @@ from mock.mock import MagicMock from pytest import mark -from django.utils import timezone - from integrated_channels.degreed2.exporters.learner_data import Degreed2LearnerExporter from test_utils import factories from test_utils.fake_catalog_api import setup_course_catalog_api_client_mock @@ -26,7 +24,7 @@ class TestDegreed2LearnerExporter(unittest.TestCase): Tests of DegreedLearnerExporter class. """ - NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=timezone.utc) + NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc) NOW_TIMESTAMP = 1483326245000 def setUp(self): diff --git a/tests/test_integrated_channels/test_integrated_channel/test_exporters/test_learner_data.py b/tests/test_integrated_channels/test_integrated_channel/test_exporters/test_learner_data.py index fe94da8b39..05ea465134 100644 --- a/tests/test_integrated_channels/test_integrated_channel/test_exporters/test_learner_data.py +++ b/tests/test_integrated_channels/test_integrated_channel/test_exporters/test_learner_data.py @@ -44,7 +44,7 @@ class TestLearnerExporter(unittest.TestCase): """ # Use these tz-aware datetimes in tests - NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=timezone.utc) + NOW = datetime.datetime(2017, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc) NOW_TIMESTAMP = 1483326245000 TOMORROW = NOW + datetime.timedelta(days=1) YESTERDAY = NOW + datetime.timedelta(days=-1) diff --git a/tests/test_middleware.py b/tests/test_middleware.py index ef533eb473..edc328719a 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -10,7 +10,6 @@ from django.contrib.sessions.middleware import SessionMiddleware from django.test.client import Client, RequestFactory -from django.utils.translation import LANGUAGE_SESSION_KEY from enterprise.middleware import EnterpriseLanguagePreferenceMiddleware from test_utils.factories import ( @@ -39,8 +38,9 @@ def setUp(self): self.mock_imports() super().setUp() - self.middleware = EnterpriseLanguagePreferenceMiddleware() - self.session_middleware = SessionMiddleware() + self.mock_response = mock.Mock() + self.middleware = EnterpriseLanguagePreferenceMiddleware(self.mock_response) + self.session_middleware = SessionMiddleware(self.mock_response) self.user = UserFactory.create() self.anonymous_user = AnonymousUserFactory() self.request = RequestFactory().get('/somewhere') @@ -82,7 +82,6 @@ def test_preference_setting_changes_cookie(self, lang_pref_out): self.middleware.process_request(self.request) assert getattr(self.request, '_anonymous_user_cookie_lang', None) == lang_pref_out - assert LANGUAGE_SESSION_KEY not in self.request.session def test_real_user_extracted_from_request(self): """ @@ -96,7 +95,6 @@ def test_real_user_extracted_from_request(self): # Make sure the real user is used for setting the language cookie assert getattr(self.request, '_anonymous_user_cookie_lang', None) == self.enterprise_customer.default_language - assert LANGUAGE_SESSION_KEY not in self.request.session def test_cookie_not_set_for_anonymous_user(self): """ @@ -108,7 +106,6 @@ def test_cookie_not_set_for_anonymous_user(self): # Make sure the set cookie is not called for anonymous users assert getattr(self.request, '_anonymous_user_cookie_lang', None) is None - assert LANGUAGE_SESSION_KEY not in self.request.session def test_cookie_not_set_for_non_enterprise_learners(self): """ @@ -120,7 +117,6 @@ def test_cookie_not_set_for_non_enterprise_learners(self): # Make sure the set cookie is not called for anonymous users assert getattr(self.request, '_anonymous_user_cookie_lang', None) is None - assert LANGUAGE_SESSION_KEY not in self.request.session def test_cookie_when_there_is_no_request_user(self): """ @@ -128,14 +124,14 @@ def test_cookie_when_there_is_no_request_user(self): """ # Hide the real user and masquerade as a fake user, fake user does not belong to any enterprise customer. request = RequestFactory().get('/somewhere') - session_middleware = SessionMiddleware() + self.mock_response = mock.Mock() + session_middleware = SessionMiddleware(self.mock_response) session_middleware.process_request(request) self.middleware.process_request(request) # Make sure the set cookie is not called for anonymous users assert getattr(self.request, '_anonymous_user_cookie_lang', None) is None - assert LANGUAGE_SESSION_KEY not in self.request.session def test_errors_are_handled(self): """ @@ -149,7 +145,6 @@ def test_errors_are_handled(self): # Make sure the set cookie is not called for anonymous users # pylint: disable=protected-access,no-member assert self.request._anonymous_user_cookie_lang == self.enterprise_customer.default_language - assert LANGUAGE_SESSION_KEY not in self.request.session def test_cookie_not_set_for_mobile_requests(self): """ @@ -161,4 +156,3 @@ def test_cookie_not_set_for_mobile_requests(self): # Make sure the set cookie is not called for anonymous users assert getattr(self.request, '_anonymous_user_cookie_lang', None) is None - assert LANGUAGE_SESSION_KEY not in self.request.session diff --git a/tests/test_migrations.py b/tests/test_migrations.py index 45fb1e8c02..0fbdc02ba5 100644 --- a/tests/test_migrations.py +++ b/tests/test_migrations.py @@ -1,13 +1,19 @@ """ Tests for migrations, especially potentially risky data migrations. """ +from importlib.metadata import version from io import StringIO +import pytest + from django.core.management import call_command from django.test.testcases import TestCase from django.test.utils import override_settings +GET_DJANGO_VERSION = int(version('django').split('.')[0]) + +@pytest.mark.skipif(GET_DJANGO_VERSION > 3, reason="django4.2 brings new migrations, so only run for dj32 for now.") class MigrationTests(TestCase): """ Runs migration tests using Django Command interface. diff --git a/tox.ini b/tox.ini index 3fe86e9fa0..7b1e7eee0b 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py38-django{32}-celery{50}, django{32}-pii-annotations +envlist = py38-django{32,42}-celery{53}, django{32}-pii-annotations [doc8] max-line-length = 120 @@ -27,7 +27,8 @@ setenv = TOXENV={envname} deps = django32: Django>=3.2,<4.0 - celery50: -r{toxinidir}/requirements/celery50.txt + django42: Django>=4.2,<4.3 + celery53: -r{toxinidir}/requirements/celery53.txt -r{toxinidir}/requirements/test.txt commands = py.test -Wd {posargs}