From bd85f4d750de5c9e4db178ac11d40b31a4dc6e27 Mon Sep 17 00:00:00 2001 From: Josh Peng Yu Date: Wed, 6 Mar 2024 07:53:02 +0000 Subject: [PATCH] feat: initial fix for django 4.2 --- CHANGELOG.rst | 4 + djangocms_moderation/__init__.py | 1 - djangocms_moderation/admin.py | 78 +++++++++++++------ djangocms_moderation/admin_actions.py | 4 +- djangocms_moderation/views.py | 2 +- tests/__init__.py | 7 ++ tests/test_forms.py | 12 +-- tests/test_models.py | 22 +++--- tests/test_views.py | 4 +- tests/utils/app_1/__init__.py | 1 - tests/utils/app_2/__init__.py | 1 - tests/utils/moderated_polls/__init__.py | 1 - .../versioned_none_moderated_app/__init__.py | 3 - 13 files changed, 87 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 78b3f434..1217aef0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,10 @@ Unreleased ========== * fix: Treebeard support improved by inheriting a treebeard template +* Python 3.10 support added +* Python 3.7 support removed +* Django 4.2 support added +* Django CMS 4.1 support added 2.1.6 (2022-09-07) ================== diff --git a/djangocms_moderation/__init__.py b/djangocms_moderation/__init__.py index 1e525f4c..9389d356 100644 --- a/djangocms_moderation/__init__.py +++ b/djangocms_moderation/__init__.py @@ -1,3 +1,2 @@ __version__ = "2.1.6" -default_app_config = "djangocms_moderation.apps.ModerationConfig" diff --git a/djangocms_moderation/admin.py b/djangocms_moderation/admin.py index 460bb8ee..95a9eb16 100644 --- a/djangocms_moderation/admin.py +++ b/djangocms_moderation/admin.py @@ -73,12 +73,17 @@ def has_add_permission(self, request): def has_delete_permission(self, request, obj=None): return False + @admin.display( + description=_("Status") + ) def show_user(self, obj): _name = obj.get_by_user_name() return gettext("By {user}").format(user=_name) - show_user.short_description = _("Status") + @admin.display( + description=_("Form Submission") + ) def form_submission(self, obj): instance = get_form_submission_for_step( obj.moderation_request, obj.step_approved @@ -96,7 +101,6 @@ def form_submission(self, obj): '{}', url, obj.step_approved.role.name ) - form_submission.short_description = _("Form Submission") def get_readonly_fields(self, request, obj=None): if obj.user_can_moderate(request.user) or obj.user_is_author(request.user): @@ -107,6 +111,7 @@ def get_readonly_fields(self, request, obj=None): return self.fields +@admin.register(ModerationRequestTreeNode) class ModerationRequestTreeAdmin(TreeAdmin): """ This admin is purely for the change list of Moderation Requests using the treebeard nodes to @@ -177,6 +182,9 @@ def get_list_display(self, request): ] return list_display + @admin.display( + description=_("actions") + ) def list_display_actions(self, obj): """Display links to state change endpoints """ @@ -184,7 +192,6 @@ def list_display_actions(self, obj): "", "{}", ((action(obj),) for action in self.get_list_display_actions()) ) - list_display_actions.short_description = _("actions") def get_list_display_actions(self): actions = [] @@ -210,6 +217,9 @@ def _get_configured_fields(self, request): return fields + @admin.display( + description=_('ID') + ) def get_id(self, obj): return format_html( '{id}', @@ -219,22 +229,30 @@ def get_id(self, obj): ), id=obj.moderation_request_id, ) - get_id.short_description = _('ID') + @admin.display( + description=_('Content type') + ) def get_content_type(self, obj): return ContentType.objects.get_for_model( obj.moderation_request.version.versionable.grouper_model ) - get_content_type.short_description = _('Content type') + @admin.display( + description=_('Title') + ) def get_title(self, obj): return obj.moderation_request.version.content - get_title.short_description = _('Title') + @admin.display( + description=_('Author') + ) def get_version_author(self, obj): return obj.moderation_request.version.created_by - get_version_author.short_description = _('Author') + @admin.display( + description=_("Preview") + ) def get_preview_link(self, obj): content = obj.moderation_request.version.content if is_editable_model(content.__class__): @@ -254,8 +272,10 @@ def get_preview_link(self, obj): object_preview_url, ) - get_preview_link.short_description = _("Preview") + @admin.display( + description=_('Reviewer') + ) def get_reviewer(self, obj): last_action = obj.moderation_request.get_last_action() if not last_action: @@ -264,7 +284,6 @@ def get_reviewer(self, obj): next_step = obj.moderation_request.get_next_required() return next_step.role.name return last_action._get_user_name(last_action.by_user) - get_reviewer.short_description = _('Reviewer') def get_status(self, obj): # We can have moderation requests without any action (e.g. the @@ -466,6 +485,7 @@ def _traverse_moderation_nodes(node_item): return HttpResponseRedirect(redirect_url) +@admin.register(ModerationRequest) class ModerationRequestAdmin(admin.ModelAdmin): class Media: js = ('admin/js/jquery.init.js', 'djangocms_moderation/js/actions.js',) @@ -813,11 +833,13 @@ def changelist_view(self, request, extra_context=None): return tree_node_admin.changelist_view(request, extra_context) +@admin.register(Role) class RoleAdmin(admin.ModelAdmin): list_display = ["name", "user", "group", "confirmation_page"] fields = ["name", "user", "group", "confirmation_page"] +@admin.register(CollectionComment) class CollectionCommentAdmin(admin.ModelAdmin): list_display = ["date_created", "message", "author"] fields = ["collection", "message", "author"] @@ -900,6 +922,7 @@ def get_readonly_fields(self, request, obj=None): return self.list_display +@admin.register(RequestComment) class RequestCommentAdmin(admin.ModelAdmin): list_display = ["date_created", "message", "get_author"] fields = ["moderation_request", "message", "author"] @@ -907,10 +930,12 @@ class RequestCommentAdmin(admin.ModelAdmin): class Media: css = {"all": ("djangocms_moderation/css/comments_changelist.css",)} + @admin.display( + description=_("User") + ) def get_author(self, obj): return obj.author_name - get_author.short_description = _("User") def get_changeform_initial_data(self, request): data = {"author": request.user} @@ -990,6 +1015,7 @@ def get_extra(self, request, obj=None, **kwargs): return 1 +@admin.register(Workflow) class WorkflowAdmin(admin.ModelAdmin): inlines = [WorkflowStepInline] list_display = ["name", "is_default"] @@ -1002,6 +1028,7 @@ class WorkflowAdmin(admin.ModelAdmin): ] +@admin.register(ModerationCollection) class ModerationCollectionAdmin(admin.ModelAdmin): class Media: js = ("admin/js/jquery.init.js", "djangocms_moderation/js/actions.js",) @@ -1033,11 +1060,16 @@ def get_list_display(self, request): def job_id(self, obj): return obj.pk + @admin.display( + description=_('reviewers') + ) def commaseparated_reviewers(self, obj): reviewers = self.model.objects.reviewers(obj) return ", ".join(map(get_user_model().get_full_name, reviewers)) - commaseparated_reviewers.short_description = _('reviewers') + @admin.display( + description=_("actions") + ) def list_display_actions(self, obj): """Display links to state change endpoints """ @@ -1045,7 +1077,6 @@ def list_display_actions(self, obj): "", "{}", ((action(obj),) for action in self.get_list_display_actions()) ) - list_display_actions.short_description = _("actions") def get_list_display_actions(self): actions = [self.get_edit_link, self.get_requests_link] @@ -1136,6 +1167,7 @@ def has_delete_permission(self, request, obj=None): return False +@admin.register(ConfirmationPage) class ConfirmationPageAdmin(PlaceholderAdminMixin, admin.ModelAdmin): view_on_site = True @@ -1153,6 +1185,7 @@ def _url(regex, fn, name, **kwargs): return url_patterns + super().get_urls() +@admin.register(ConfirmationFormSubmission) class ConfirmationFormSubmissionAdmin(admin.ModelAdmin): list_display = ["moderation_request", "for_step", "submitted_at"] fields = [ @@ -1178,16 +1211,23 @@ def change_view(self, request, object_id, form_url="", extra_context=None): request, object_id, form_url, extra_context=extra_context ) + @admin.display( + description=_("Request") + ) def moderation_request(self, obj): return obj.moderation_request_id - moderation_request.short_description = _("Request") + @admin.display( + description=_("By User") + ) def show_user(self, obj): return obj.get_by_user_name() - show_user.short_description = _("By User") + @admin.display( + description=_("Form Data") + ) def form_data(self, obj): data = obj.get_form_data() return format_html_join( @@ -1199,15 +1239,5 @@ def form_data(self, obj): ), ) - form_data.short_description = _("Form Data") -admin.site.register(ModerationRequestTreeNode, ModerationRequestTreeAdmin) -admin.site.register(ModerationRequest, ModerationRequestAdmin) -admin.site.register(CollectionComment, CollectionCommentAdmin) -admin.site.register(RequestComment, RequestCommentAdmin) -admin.site.register(ModerationCollection, ModerationCollectionAdmin) -admin.site.register(Role, RoleAdmin) -admin.site.register(Workflow, WorkflowAdmin) -admin.site.register(ConfirmationPage, ConfirmationPageAdmin) -admin.site.register(ConfirmationFormSubmission, ConfirmationFormSubmissionAdmin) diff --git a/djangocms_moderation/admin_actions.py b/djangocms_moderation/admin_actions.py index 07fc3eea..926e1282 100644 --- a/djangocms_moderation/admin_actions.py +++ b/djangocms_moderation/admin_actions.py @@ -148,14 +148,14 @@ def add_items_to_collection(modeladmin, request, queryset): args=(), ), version_ids=",".join(version_ids), - return_to_url=request.META.get("HTTP_REFERER", ""), + return_to_url=request.headers.get("referer", ""), ) return HttpResponseRedirect(admin_url) else: modeladmin.message_user( request, _("No suitable items found to add to moderation collection") ) - return HttpResponseRedirect(request.META.get("HTTP_REFERER", "")) + return HttpResponseRedirect(request.headers.get("referer", "")) add_items_to_collection.short_description = _("Add to moderation collection") diff --git a/djangocms_moderation/views.py b/djangocms_moderation/views.py index 03f899e3..6519006b 100644 --- a/djangocms_moderation/views.py +++ b/djangocms_moderation/views.py @@ -6,7 +6,7 @@ from django.shortcuts import get_object_or_404, render from django.urls import reverse from django.utils.decorators import method_decorator -from django.utils.http import is_safe_url +from django.utils.http import url_has_allowed_host_and_scheme from django.utils.translation import gettext_lazy as _, ngettext from django.views.generic import FormView diff --git a/tests/__init__.py b/tests/__init__.py index e69de29b..a03ec337 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,7 @@ +import django + + +if django.VERSION < (4, 2): # TODO: remove when dropping support for Django < 4.2 + from django.test.testcases import TransactionTestCase + + TransactionTestCase.assertQuerySetEqual = TransactionTestCase.assertQuerysetEqual diff --git a/tests/test_forms.py b/tests/test_forms.py index 571e591f..73d8adc4 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -31,7 +31,7 @@ def test_form_init_approved_action(self): ) field_moderator = form.fields["moderator"] self.assertEqual(field_moderator.empty_label, "Any Role 2") - self.assertQuerysetEqual( + self.assertQuerySetEqual( field_moderator.queryset, User.objects.filter(pk__in=[self.user2.pk]), transform=lambda x: x, @@ -48,7 +48,7 @@ def test_form_init_cancelled_action(self): active_request=self.moderation_request1, ) field_moderator = form.fields["moderator"] - self.assertQuerysetEqual(field_moderator.queryset, User.objects.none()) + self.assertQuerySetEqual(field_moderator.queryset, User.objects.none()) self.assertIsInstance(field_moderator.widget, HiddenInput) def test_form_init_rejected_action(self): @@ -61,7 +61,7 @@ def test_form_init_rejected_action(self): active_request=self.moderation_request1, ) field_moderator = form.fields["moderator"] - self.assertQuerysetEqual(field_moderator.queryset, User.objects.none()) + self.assertQuerySetEqual(field_moderator.queryset, User.objects.none()) self.assertIsInstance(field_moderator.widget, HiddenInput) def test_form_save(self): @@ -155,7 +155,7 @@ def test_add_items_to_collection(self): form = CollectionItemsForm(data=data, user=self.user) self.assertTrue(form.is_valid()) versions = form.clean_versions() - self.assertQuerysetEqual( + self.assertQuerySetEqual( versions, Version.objects.filter(pk__in=[pg1_version.pk, pg2_version.pk]), transform=lambda x: x, @@ -172,7 +172,7 @@ def test_attempt_add_with_item_already_in_collection(self): form = CollectionItemsForm(data=data, user=self.user) self.assertTrue(form.is_valid()) versions = form.clean_versions() - self.assertQuerysetEqual( + self.assertQuerySetEqual( versions, Version.objects.filter(pk__in=[pg_version.pk]), transform=lambda x: x, @@ -253,7 +253,7 @@ def test_collection_choice_should_be_limited_to_current_user_and_collecting_stat if not form.is_valid(): self.assertIn("collection", form.errors) - self.assertQuerysetEqual( + self.assertQuerySetEqual( form.fields["collection"].queryset, ModerationCollection.objects.filter( pk__in=[collection1.pk, collection2.pk] diff --git a/tests/test_models.py b/tests/test_models.py index b00b6bfa..fd8c5ed0 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -43,7 +43,7 @@ def test_user_is_assigned(self): def test_get_users_queryset(self): # with user role = Role.objects.create(name="New Role 1", user=self.user) - self.assertQuerysetEqual( + self.assertQuerySetEqual( role.get_users_queryset(), User.objects.filter(pk=self.user.pk), transform=lambda x: x, @@ -51,7 +51,7 @@ def test_get_users_queryset(self): ) # with group role = Role.objects.create(name="New Role 2", group=self.group) - self.assertQuerysetEqual( + self.assertQuerySetEqual( role.get_users_queryset(), User.objects.filter(pk__in=[self.user2.pk, self.user3.pk]), transform=lambda x: x, @@ -128,7 +128,7 @@ def test_get_last_action(self): ) def test_get_pending_steps(self): - self.assertQuerysetEqual( + self.assertQuerySetEqual( self.moderation_request3.get_pending_steps(), WorkflowStep.objects.filter(pk__in=[self.wf3st2.pk]), transform=lambda x: x, @@ -142,7 +142,7 @@ def test_get_pending_steps(self): # ... so all the steps are now pending as we need to re-moderate the # resubmitted request - self.assertQuerysetEqual( + self.assertQuerySetEqual( self.moderation_request3.get_pending_steps(), WorkflowStep.objects.filter(workflow=self.wf3), transform=lambda x: x, @@ -150,13 +150,13 @@ def test_get_pending_steps(self): ) def test_get_pending_required_steps(self): - self.assertQuerysetEqual( + self.assertQuerySetEqual( self.moderation_request1.get_pending_required_steps(), WorkflowStep.objects.filter(pk__in=[self.wf1st1.pk, self.wf1st3.pk]), transform=lambda x: x, ordered=False, ) - self.assertQuerysetEqual( + self.assertQuerySetEqual( self.moderation_request3.get_pending_required_steps(), WorkflowStep.objects.none(), transform=lambda x: x, @@ -164,7 +164,7 @@ def test_get_pending_required_steps(self): ) # Lets test with archived action - self.assertQuerysetEqual( + self.assertQuerySetEqual( self.moderation_request2.get_pending_required_steps(), WorkflowStep.objects.none(), transform=lambda x: x, @@ -176,7 +176,7 @@ def test_get_pending_required_steps(self): last_action.is_archived = True last_action.save() - self.assertQuerysetEqual( + self.assertQuerySetEqual( self.moderation_request2.get_pending_required_steps(), WorkflowStep.objects.filter(pk=last_action.step_approved.pk), transform=lambda x: x, @@ -717,13 +717,13 @@ def test_add_version_duplicate_with_same_parent(self): moderation_request, added_items = self.collection.add_version(version, parent) self.assertEqual(ModerationRequest.objects.all().count(), 2) - self.assertQuerysetEqual( + self.assertQuerySetEqual( ModerationRequest.objects.all(), [parent.moderation_request.pk, child.moderation_request.pk], transform=lambda o: o.pk ) self.assertEqual(ModerationRequestTreeNode.objects.all().count(), 2) - self.assertQuerysetEqual( + self.assertQuerySetEqual( ModerationRequestTreeNode.objects.all(), [parent.pk, child.pk], transform=lambda o: o.pk @@ -746,7 +746,7 @@ def test_add_version_duplicate_with_different_parent(self): moderation_request, added_items = self.collection.add_version(version, parent) self.assertEqual(ModerationRequest.objects.all().count(), 3) - self.assertQuerysetEqual( + self.assertQuerySetEqual( ModerationRequest.objects.all(), [root.moderation_request.pk, child.moderation_request.pk, parent.moderation_request.pk], transform=lambda o: o.pk diff --git a/tests/test_views.py b/tests/test_views.py index b7ecee19..a590fb25 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -638,7 +638,7 @@ def test_initial_form_values_when_collection_id_passed(self): self.assertEqual( response.context["form"].initial["collection"], str(collection.pk) ) - self.assertQuerysetEqual( + self.assertQuerySetEqual( response.context["form"].initial["versions"], [pg_version.pk, poll_version.pk], transform=lambda o: o.pk, @@ -654,7 +654,7 @@ def test_initial_form_values_when_collection_id_not_passed(self): self.assertEqual(response.status_code, 200) self.assertEqual(len(response.context["form"].initial.keys()), 1) - self.assertQuerysetEqual( + self.assertQuerySetEqual( response.context["form"].initial["versions"], [pg_version.pk, poll_version.pk], transform=lambda o: o.pk, diff --git a/tests/utils/app_1/__init__.py b/tests/utils/app_1/__init__.py index 03f81427..e69de29b 100644 --- a/tests/utils/app_1/__init__.py +++ b/tests/utils/app_1/__init__.py @@ -1 +0,0 @@ -default_app_config = "tests.utils.app_1.apps.App1Config" diff --git a/tests/utils/app_2/__init__.py b/tests/utils/app_2/__init__.py index ff4e78c0..e69de29b 100644 --- a/tests/utils/app_2/__init__.py +++ b/tests/utils/app_2/__init__.py @@ -1 +0,0 @@ -default_app_config = "tests.utils.app_2.apps.App2Config" diff --git a/tests/utils/moderated_polls/__init__.py b/tests/utils/moderated_polls/__init__.py index d70b54ee..e69de29b 100644 --- a/tests/utils/moderated_polls/__init__.py +++ b/tests/utils/moderated_polls/__init__.py @@ -1 +0,0 @@ -default_app_config = "tests.utils.moderated_polls.apps.PollsConfig" diff --git a/tests/utils/versioned_none_moderated_app/__init__.py b/tests/utils/versioned_none_moderated_app/__init__.py index dc0b47c0..e69de29b 100644 --- a/tests/utils/versioned_none_moderated_app/__init__.py +++ b/tests/utils/versioned_none_moderated_app/__init__.py @@ -1,3 +0,0 @@ -default_app_config = ( - "tests.utils.versioned_none_moderated_app.apps.VersionedNoneModeratedAppConfig" -)