Skip to content

Commit 7e41d8a

Browse files
fsbraunAiky30
andauthored
fix: deletion of version objects blocked by source fields (#320)
* fix: deletion of version objects blocked by source fields * Add: Option to turn deletion on or off, test for migrations * Fix flake8 issues with migration test * Update docs * Add tests for setting * Fix isort * Fix codeql warning * Update test_settings.py * Update docs/settings.rst Co-authored-by: Andrew Aikman <[email protected]> * Update docs/settings.rst Co-authored-by: Andrew Aikman <[email protected]> * Fix: move setting to conf.py * Update test * isort tests --------- Co-authored-by: Andrew Aikman <[email protected]>
1 parent 6d062b2 commit 7e41d8a

File tree

11 files changed

+142
-5
lines changed

11 files changed

+142
-5
lines changed

djangocms_versioning/apps.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
class VersioningConfig(AppConfig):
77
name = "djangocms_versioning"
88
verbose_name = _("django CMS Versioning")
9+
default_auto_field = 'django.db.models.AutoField'
910

1011
def ready(self):
1112
from cms.models import contentmodels, fields

djangocms_versioning/conf.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@
1212
DEFAULT_USER = getattr(
1313
settings, "DJANGOCMS_VERSIONING_DEFAULT_USER", None
1414
)
15+
16+
ALLOW_DELETING_VERSIONS = getattr(
17+
settings, "DJANGOCMS_VERSIONING_ALLOW_DELETING_VERSIONS", False
18+
)

djangocms_versioning/migrations/0003_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class Migration(migrations.Migration):
2929
),
3030
),
3131
("label", models.TextField()),
32-
("created", models.DateTimeField(auto_now_add=True)),
32+
("created", models.DateTimeField(auto_now_add=True, verbose_name="Created")),
3333
("object_id", models.PositiveIntegerField()),
3434
(
3535
"content_type",

djangocms_versioning/migrations/0014_version_source.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
from __future__ import unicode_literals
44

55
from django.db import migrations, models
6-
import django.db.models.deletion
6+
7+
import djangocms_versioning.models
78

89

910
class Migration(migrations.Migration):
@@ -17,7 +18,7 @@ class Migration(migrations.Migration):
1718
field=models.ForeignKey(
1819
blank=True,
1920
null=True,
20-
on_delete=django.db.models.deletion.PROTECT,
21+
on_delete=djangocms_versioning.models.allow_deleting_versions,
2122
to="djangocms_versioning.Version",
2223
verbose_name="source",
2324
),

djangocms_versioning/migrations/0015_version_modified.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ class Migration(migrations.Migration):
1414
migrations.AddField(
1515
model_name="version",
1616
name="modified",
17-
field=models.DateTimeField(default=django.utils.timezone.now),
17+
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name="Modified"),
1818
)
1919
]

djangocms_versioning/models.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
from django_fsm import FSMField, can_proceed, transition
1212

13+
from djangocms_versioning.conf import ALLOW_DELETING_VERSIONS
14+
1315
from . import constants, versionables
1416
from .conditions import Conditions, in_state
1517
from .operations import send_post_version_operation, send_pre_version_operation
@@ -21,6 +23,13 @@
2123
emit_content_change = None
2224

2325

26+
def allow_deleting_versions(collector, field, sub_objs, using):
27+
if ALLOW_DELETING_VERSIONS:
28+
models.SET_NULL(collector, field, sub_objs, using)
29+
else:
30+
models.PROTECT(collector, field, sub_objs, using)
31+
32+
2433
class VersionQuerySet(models.QuerySet):
2534
def get_for_content(self, content_object):
2635
"""Returns Version object corresponding to provided content object
@@ -85,7 +94,7 @@ class Version(models.Model):
8594
"self",
8695
null=True,
8796
blank=True,
88-
on_delete=models.PROTECT,
97+
on_delete=allow_deleting_versions,
8998
verbose_name=_("source"),
9099
)
91100
objects = VersionQuerySet.as_manager()

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Welcome to "djangocms-versioning"'s documentation!
1515
api/signals
1616
api/customizing_version_list
1717
api/management_commands
18+
settings
1819

1920
.. toctree::
2021
:maxdepth: 2

docs/settings.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Settings for djangocms Versioning
2+
=================================
3+
4+
5+
.. py:attribute:: DJANGOCMS_VERSIONING_ALLOW_DELETING_VERSIONS
6+
7+
Defaults to ``False``
8+
9+
This setting controls if the ``source`` field of a ``Version`` object is
10+
protected. It is protected by default which implies that Django will not allow a user
11+
to delete a version object which itself is a source for another version object.
12+
This implies that the corresponding content and grouper objects cannot be
13+
deleted either.
14+
15+
This is to protect the record of how different versions have come about.
16+
17+
If set to ``True`` users can delete version objects if the have the appropriate
18+
rights. Set this to ``True`` if you want users to be able to delete versioned
19+
objects and you do not need a full history of versions, e.g. for documentation
20+
purposes.
21+
22+
The latest version (which is not a source of a newer version) can always be
23+
deleted (if the user has the appropriate rights).

docs/upgrade/2.0.0.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ Status indicators in page tree
3535
make sure that at least version 3.2.1 is installed. Older versions contain
3636
a bug that interferes with djangocms-versioning's icons.
3737

38+
Deletion protection
39+
-------------------
40+
41+
By default ``Version`` objects which are sources for later versions are
42+
protected from deletion. This implies that neither the corresponding content
43+
object nor the grouper object can be deleted. To allow deletion of ``Version``
44+
objects set ``DJANGOCMS_VERSIONING_ALLOW_DELETING_VERSIONS`` to ``True`` in
45+
the project's ``settings.py``.
46+
3847

3948
Backwards incompatible changes in 2.0.0
4049
=======================================

tests/test_0_migrations.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# original from
2+
# http://tech.octopus.energy/news/2016/01/21/testing-for-missing-migrations-in-django.html
3+
4+
# Needs to run as first test to avoid generating migrations for proxy version models.
5+
6+
from io import StringIO
7+
8+
from django.core.management import call_command
9+
from django.test import TestCase
10+
11+
12+
class MigrationTestCase(TestCase):
13+
def test_for_missing_migrations(self):
14+
output = StringIO()
15+
options = {
16+
"interactive": False,
17+
"dry_run": True,
18+
"stdout": output,
19+
"check_changes": True,
20+
}
21+
22+
try:
23+
call_command("makemigrations", "djangocms_versioning", **options)
24+
except SystemExit as e:
25+
status_code = str(e)
26+
else:
27+
# the "no changes" exit code is 0
28+
status_code = "0"
29+
30+
if status_code == "1":
31+
self.fail(f"There are missing migrations:\n {output.getvalue()}")

0 commit comments

Comments
 (0)