kopia lustrzana https://github.com/wagtail/wagtail
Add purge_revisions management command
* Fix typo in publish_scheduled_pages dry run * Add purge_revisions to docs * Resolves #5192pull/6015/head
rodzic
52cb7ab77b
commit
30c398c91a
|
@ -22,6 +22,7 @@ Changelog
|
|||
* Add ability to replace the default Wagtail logo in the userbar, via `branding_logo` block (Meteor0id)
|
||||
* Remove sticky footer on small devices, so that content is not blocked and more easily editable (Saeed Tahmasebi)
|
||||
* Add ``alt`` property to ``ImageRenditionField`` api representation (Liam Mullens)
|
||||
* Add ``purge_revisions`` management command to purge old page revisions (Jacob Topp-Mugglestone, Tom Dyson)
|
||||
* Fix: Support IPv6 domain (Alex Gleason, Coen van der Kamp)
|
||||
* Fix: Ensure link to add a new user works when no users are visible in the users list (LB (Ben Johnston))
|
||||
* Fix: `AbstractEmailForm` saved submission fields are now aligned with the email content fields, `form.cleaned_data` will be used instead of `form.fields` (Haydn Greatnews)
|
||||
|
|
|
@ -48,6 +48,20 @@ Options:
|
|||
This is the **id** of the page to move pages to.
|
||||
|
||||
|
||||
.. _purge_revisions:
|
||||
|
||||
purge_revisions
|
||||
---------------
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ manage.py purge_revisions [--days=<number of days>]
|
||||
|
||||
This command deletes old page revisions which are not in moderation, live, approved to go live, or the latest
|
||||
revision for a page. If the ``days`` argument is supplied, only revisions older than the specified number of
|
||||
days will be deleted.
|
||||
|
||||
|
||||
.. _update_index:
|
||||
|
||||
update_index
|
||||
|
|
|
@ -31,6 +31,7 @@ Other features
|
|||
* Remove sticky footer on small devices, so that content is not blocked and more easily editable (Saeed Tahmasebi)
|
||||
* Add ability to replace the default Wagtail logo in the userbar, via ``branding_logo`` block (Meteor0id)
|
||||
* Add `alt` property to `ImageRenditionField` api representation (Liam Mullens)
|
||||
* Add `purge_revisions` management command to purge old page revisions (Jacob Topp-Mugglestone, Tom Dyson)
|
||||
|
||||
|
||||
Bug fixes
|
||||
|
|
|
@ -21,7 +21,7 @@ class Command(BaseCommand):
|
|||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--dryrun', action='store_true', dest='dryrun', default=False,
|
||||
help="Dry run -- dont't change anything.")
|
||||
help="Dry run -- don't change anything.")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
dryrun = False
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
|
||||
from wagtail.core.models import PageRevision
|
||||
|
||||
try:
|
||||
from wagtail.core.models import WorkflowState
|
||||
workflow_support = True
|
||||
except ImportError:
|
||||
workflow_support = False
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Delete page revisions which are not the latest revision for a page, published or scheduled to be published, or in moderation'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--days', type=int, help="Only delete revisions older than this number of days")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
days = options.get('days')
|
||||
|
||||
revisions_deleted = purge_revisions(days=days)
|
||||
|
||||
if revisions_deleted:
|
||||
self.stdout.write(self.style.SUCCESS('Successfully deleted %s revisions' % revisions_deleted))
|
||||
else:
|
||||
self.stdout.write("No revisions deleted")
|
||||
|
||||
|
||||
def purge_revisions(days=None):
|
||||
# exclude revisions which have been submitted for moderation in the old system
|
||||
purgeable_revisions = PageRevision.objects.exclude(
|
||||
submitted_for_moderation=True
|
||||
).exclude(
|
||||
# and exclude revisions with an approved_go_live_at date
|
||||
approved_go_live_at__isnull=False)
|
||||
|
||||
if workflow_support:
|
||||
purgeable_revisions = purgeable_revisions.exclude(
|
||||
# and exclude revisions linked to an in progress workflow state
|
||||
task_states__workflow_state__status=WorkflowState.STATUS_IN_PROGRESS
|
||||
)
|
||||
|
||||
if days:
|
||||
purgeable_until = timezone.now() - timezone.timedelta(days=days)
|
||||
# only include revisions which were created before the cut off date
|
||||
purgeable_revisions = purgeable_revisions.filter(created_at__lt=purgeable_until)
|
||||
|
||||
deleted_revisions_count = 0
|
||||
|
||||
for revision in purgeable_revisions:
|
||||
# don't delete the latest revision for any page
|
||||
if not revision.is_latest_revision():
|
||||
revision.delete()
|
||||
deleted_revisions_count += 1
|
||||
|
||||
return deleted_revisions_count
|
|
@ -1,6 +1,7 @@
|
|||
from datetime import timedelta
|
||||
from io import StringIO
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core import management
|
||||
from django.db import models
|
||||
from django.test import TestCase
|
||||
|
@ -332,3 +333,92 @@ class TestPublishScheduledPagesCommand(TestCase):
|
|||
|
||||
p = Page.objects.get(slug='hello-world')
|
||||
self.assertFalse(PageRevision.objects.filter(page=p, submitted_for_moderation=True).exists())
|
||||
|
||||
|
||||
class TestPurgeRevisionsCommand(TestCase):
|
||||
fixtures = ['test.json']
|
||||
|
||||
def setUp(self):
|
||||
# Find root page
|
||||
self.root_page = Page.objects.get(id=2)
|
||||
self.page = SimplePage(
|
||||
title="Hello world!",
|
||||
slug="hello-world",
|
||||
content="hello",
|
||||
live=False,
|
||||
)
|
||||
self.root_page.add_child(instance=self.page)
|
||||
self.page.refresh_from_db()
|
||||
|
||||
def run_command(self, days=None):
|
||||
if days:
|
||||
days_input = '--days=' + str(days)
|
||||
return management.call_command('purge_revisions', days_input, stdout=StringIO())
|
||||
return management.call_command('purge_revisions', stdout=StringIO())
|
||||
|
||||
def test_latest_revision_not_purged(self):
|
||||
|
||||
revision_1 = self.page.save_revision()
|
||||
|
||||
revision_2 = self.page.save_revision()
|
||||
|
||||
self.run_command()
|
||||
|
||||
# revision 1 should be deleted, revision 2 should not be
|
||||
self.assertNotIn(revision_1, PageRevision.objects.filter(page=self.page))
|
||||
self.assertIn(revision_2, PageRevision.objects.filter(page=self.page))
|
||||
|
||||
|
||||
def test_revisions_in_moderation_not_purged(self):
|
||||
|
||||
self.page.save_revision(submitted_for_moderation=True)
|
||||
|
||||
revision = self.page.save_revision()
|
||||
|
||||
self.run_command()
|
||||
|
||||
self.assertTrue(PageRevision.objects.filter(page=self.page, submitted_for_moderation=True).exists())
|
||||
|
||||
try:
|
||||
from wagtail.core.models import Task, Workflow, WorkflowTask
|
||||
workflow = Workflow.objects.create(name='test_workflow')
|
||||
task_1 = Task.objects.create(name='test_task_1')
|
||||
user = get_user_model().objects.first()
|
||||
WorkflowTask.objects.create(workflow=workflow, task=task_1, sort_order=1)
|
||||
workflow.start(self.page, user)
|
||||
self.page.save_revision()
|
||||
self.run_command()
|
||||
# even though no longer the latest revision, the old revision should stay as it is
|
||||
# attached to an in progress workflow
|
||||
self.assertIn(revision, PageRevision.objects.filter(page=self.page))
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def test_revisions_with_approve_go_live_not_purged(self):
|
||||
|
||||
approved_revision = self.page.save_revision(approved_go_live_at=timezone.now() + timedelta(days=1))
|
||||
|
||||
self.page.save_revision()
|
||||
|
||||
self.run_command()
|
||||
|
||||
self.assertIn(approved_revision, PageRevision.objects.filter(page=self.page))
|
||||
|
||||
def test_purge_revisions_with_date_cutoff(self):
|
||||
|
||||
old_revision = self.page.save_revision()
|
||||
|
||||
self.page.save_revision()
|
||||
|
||||
self.run_command(days=30)
|
||||
|
||||
# revision should not be deleted, as it is younger than 30 days
|
||||
self.assertIn(old_revision, PageRevision.objects.filter(page=self.page))
|
||||
|
||||
old_revision.created_at = timezone.now() - timedelta(days=31)
|
||||
old_revision.save()
|
||||
|
||||
self.run_command(days=30)
|
||||
|
||||
# revision is now older than 30 days, so should be deleted
|
||||
self.assertNotIn(old_revision, PageRevision.objects.filter(page=self.page))
|
||||
|
|
Ładowanie…
Reference in New Issue