Skip to content

Commit

Permalink
fix: [FGC-7] - Data migration populate expiry records with a fixed da…
Browse files Browse the repository at this point in the history
…te (#40)
  • Loading branch information
Aiky30 authored Nov 24, 2021
1 parent 83e264e commit 1177ac2
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 8 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Changelog

unreleased
==========
# feat: Data migration now has a fixed date option that allows the user running the command to provide a datetime and provide a custom format
* fix: CSV Export contains the polymorphic content type when it shouldn't

0.0.6 (2021-11-23)
Expand Down Expand Up @@ -31,5 +32,4 @@ unreleased

0.0.1 (2021-10-04)
==================

* Initial release
14 changes: 14 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ Run::

python manage.py create_existing_versions_expiry_records


Options
--expiry_date A datetime string: 2030-05-30
--expiry_date_format Defaults to: %Y-%m-%d

To bypass the default behaviour you can force all expiry records created to use a date provided as a string.
A format can also be provided if the user supplied date needs to add a time or more information to the Python datetime.strptime function.

Run::

python manage.py create_existing_versions_expiry_records --expiry_date 2030-05-30 --expiry_date_format %Y-%m-%d



Testing
=======

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from django.core.management.base import BaseCommand
from datetime import datetime

from django.core.management.base import BaseCommand, CommandError

from djangocms_versioning.models import Version

Expand All @@ -9,7 +11,7 @@
class Command(BaseCommand):
help = 'Creates Default Content Expiry entries'

def _populate_existing_version_content_expiry_records(self):
def _populate_existing_version_content_expiry_records(self, forced_expiry_date):
"""
Create any content expiry records for versions in the system
"""
Expand All @@ -22,9 +24,13 @@ def _populate_existing_version_content_expiry_records(self):
self.stdout.write(self.style.WARNING(f"No content found for version: {version.pk}"))
continue

# Use the modified date because this is the date that a published
# version was published which is what really matters for Expired content!
expiry_date = get_future_expire_date(version, version.modified)
# Use a fixed date
if forced_expiry_date:
expiry_date = forced_expiry_date
else:
# Otherwise: Use the modified date because this is the date that a published
# version was published which is what really matters for Expired content!
expiry_date = get_future_expire_date(version, version.modified)

expiry = ContentExpiry.objects.create(
created_by=version.created_by,
Expand All @@ -33,11 +39,50 @@ def _populate_existing_version_content_expiry_records(self):
)

self.stdout.write(
f"Content Expiry: {expiry.pk} created for version: {version.pk}")
f"Content Expiry: {expiry.pk} created for version: {version.pk}"
)

def _validate_user_supplied_date(self, expiry_date_string, expiry_date_format):
"""
Ensure that the date supplied is valid.
"""
self.stdout.write(
f"Formatting user supplied date: {expiry_date_string} using the format: {expiry_date_format}"
)

try:
date = datetime.strptime(expiry_date_string, expiry_date_format)
except ValueError:
raise CommandError(
f"This is an incorrect date string: {expiry_date_string} for the format: {expiry_date_format}"
)

return date

def add_arguments(self, parser):
parser.add_argument(
'--expiry_date',
nargs='?',
help="A fixed date to force all expiry records to use."
)
parser.add_argument(
'--expiry_date_format',
nargs='?',
default="%Y-%m-%d",
help="The format that the expiry_date is provided. "
"Uses strptime with the default format: %Y-%m-%d e.g. 2030-03-30"
)

def handle(self, *args, **options):
self.stdout.write(f"Starting {__name__}")

self._populate_existing_version_content_expiry_records()
expiry_date = None
expiry_date_string = options['expiry_date']
expiry_date_format = options['expiry_date_format']

if expiry_date_string:
expiry_date = self._validate_user_supplied_date(expiry_date_string, expiry_date_format)

self._populate_existing_version_content_expiry_records(expiry_date)

self.stdout.write(self.style.SUCCESS(f"Finished {__name__}"))
182 changes: 182 additions & 0 deletions tests/test_management_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
from datetime import datetime
from io import StringIO

from django.core.management import call_command
from django.core.management.base import CommandError
from django.test import TestCase
from django.utils import timezone

from cms.test_utils.testcases import CMSTestCase

import factory
from djangocms_versioning.models import Version
from djangocms_versioning.signals import post_version_operation, pre_version_operation

from djangocms_content_expiry.test_utils.polls.factories import PollVersionFactory
from djangocms_content_expiry.test_utils.polymorphic_project.factories import (
ProjectContentVersionFactory,
)
from djangocms_content_expiry.utils import get_default_duration_for_version


class CreateExpiryRecordsDefaultLogicTestCase(TestCase):

def setUp(self):
self.out = StringIO()

def test_basic_command_output(self):
"""
The command should provide messages to the user when starting and when it is finished,
"""
call_command("create_existing_versions_expiry_records", stdout=self.out)

self.assertIn(
"Starting djangocms_content_expiry.management.commands.create_existing_versions_expiry_records",
self.out.getvalue()
)
self.assertIn(
"Finished djangocms_content_expiry.management.commands.create_existing_versions_expiry_records",
self.out.getvalue()
)

@factory.django.mute_signals(pre_version_operation, post_version_operation)
def test_default_logic(self):
"""
By default all expiry records will use a default expiry date
"""
poll_content_versions = PollVersionFactory.create_batch(5, content__language="en")
project_content_versions = ProjectContentVersionFactory.create_batch(5)

# A sanity check to ensure that the models don't have expiry records attached
# because we are adding them in the command!
self.assertFalse(hasattr(poll_content_versions[0], "contentexpiry"))
self.assertFalse(hasattr(project_content_versions[0], "contentexpiry"))

call_command(
"create_existing_versions_expiry_records",
stdout=self.out,
)

versions = Version.objects.all()

self.assertEqual(len(versions), 10)

for version in versions:
expected_date = version.modified + get_default_duration_for_version(version)

self.assertEqual(version.contentexpiry.expires, expected_date)


class CreateExpiryRecordsDateOverrideLogicTestCase(CMSTestCase):

def setUp(self):
self.out = StringIO()

def test_date_options_valid_date_default_format(self):
"""
When a valid date string is supplied an informative message is supplied
stating that it is valid
"""
date = "2100-02-22"

call_command(
"create_existing_versions_expiry_records",
expiry_date=date,
stdout=self.out,
)

self.assertIn(
f"Formatting user supplied date: {date} using the format: %Y-%m-%d",
self.out.getvalue()
)

def test_date_options_invalid_date_default_format(self):
"""
When a date string is supplied that doesn't match the default format string an
informative error message should be shown to the user
"""
date = "210-02-22"

with self.assertRaisesMessage(
CommandError,
f"This is an incorrect date string: {date} for the format: %Y-%m-%d"
):

call_command(
"create_existing_versions_expiry_records",
expiry_date=date,
stdout=self.out,
)

def test_date_options_valid_date_supplied_format(self):
"""
When a valid date string is supplied an informative message is supplied
stating that it is valid
"""
date = "22022100"
date_format = "%d%m%Y"

call_command(
"create_existing_versions_expiry_records",
expiry_date=date,
expiry_date_format=date_format,
stdout=self.out,
)

self.assertIn(
f"Formatting user supplied date: {date} using the format: {date_format}",
self.out.getvalue()
)

def test_date_options_invalid_date_supplied_format(self):
"""
When a date string is supplied that doesn't match the default format string an
informative error message should be shown to the user
"""
date = "210-02-22"
date_format = "%d%m%Y"

with self.assertRaisesMessage(
CommandError,
f"This is an incorrect date string: {date} for the format: {date_format}"
):

call_command(
"create_existing_versions_expiry_records",
expiry_date=date,
expiry_date_format=date_format,
stdout=self.out,
)

@factory.django.mute_signals(pre_version_operation, post_version_operation)
def test_date_supplied_import_logic(self):
"""
When a date is supplied to the command all content expiry records
should expire on that exact date and time
"""
date = "2100-02-22"
date_format = "%Y-%m-%d"
poll_content_versions = PollVersionFactory.create_batch(5, content__language="en")
project_content_versions = ProjectContentVersionFactory.create_batch(5)

# A sanity check to ensure that the models don't have expiry records attached
# because we are adding them in the command!
self.assertFalse(hasattr(poll_content_versions[0], "contentexpiry"))
self.assertFalse(hasattr(project_content_versions[0], "contentexpiry"))

call_command(
"create_existing_versions_expiry_records",
expiry_date=date,
expiry_date_format=date_format,
stdout=self.out,
)

versions = Version.objects.all()

self.assertEqual(len(versions), 10)

for version in versions:
expected_date = datetime.strptime(date, date_format)
expected_date = timezone.make_aware(expected_date)

self.assertEqual(version.contentexpiry.expires, expected_date)

0 comments on commit 1177ac2

Please sign in to comment.