diff --git a/cms/admin/forms.py b/cms/admin/forms.py index 6c778ff68ed..d26e71618a2 100644 --- a/cms/admin/forms.py +++ b/cms/admin/forms.py @@ -1161,6 +1161,7 @@ class Meta: "can_add", "can_change", "can_delete", + "can_publish", "can_change_advanced_settings", "can_change_permissions", "can_move_page", @@ -1204,6 +1205,7 @@ class Meta: "can_add", "can_change", "can_delete", + "can_publish", "can_change_advanced_settings", "can_change_permissions", "can_move_page", diff --git a/cms/admin/permissionadmin.py b/cms/admin/permissionadmin.py index af981bd8e4e..83dce0c4c9b 100644 --- a/cms/admin/permissionadmin.py +++ b/cms/admin/permissionadmin.py @@ -97,6 +97,8 @@ def get_formset(self, request, obj=None, **kwargs): exclude.append('can_add') if not obj.has_delete_permission(user): exclude.append('can_delete') + if not obj.has_publish_permission(user): + exclude.append('can_publish') if not obj.has_advanced_settings_permission(user): exclude.append('can_change_advanced_settings') if not obj.has_move_page_permission(user): @@ -120,8 +122,8 @@ class ViewRestrictionInlineAdmin(PagePermissionInlineAdmin): class GlobalPagePermissionAdmin(admin.ModelAdmin): - list_display = ['user', 'group', 'can_change', 'can_delete', 'can_change_permissions'] - list_filter = ['user', 'group', 'can_change', 'can_delete', 'can_change_permissions'] + list_display = ['user', 'group', 'can_change', 'can_delete', 'can_publish', 'can_change_permissions'] + list_filter = ['user', 'group', 'can_change', 'can_delete', 'can_publish', 'can_change_permissions'] form = GlobalPagePermissionAdminForm search_fields = [] diff --git a/cms/api.py b/cms/api.py index 08447ad1e3e..179f5f18d09 100644 --- a/cms/api.py +++ b/cms/api.py @@ -437,7 +437,7 @@ def add_plugin(placeholder, plugin_type, language, position='last-child', def create_page_user(created_by, user, can_add_page=True, can_view_page=True, can_change_page=True, can_delete_page=True, - can_recover_page=True, can_add_pageuser=True, + can_publish_page=True, can_add_pageuser=True, can_change_pageuser=True, can_delete_pageuser=True, can_add_pagepermission=True, can_change_pagepermission=True, @@ -466,7 +466,7 @@ def create_page_user(created_by, user, 'can_view_page': can_view_page, 'can_change_page': can_change_page, 'can_delete_page': can_delete_page, - 'can_recover_page': can_recover_page, + 'can_publish_page': can_publish_page, 'can_add_pageuser': can_add_pageuser, 'can_change_pageuser': can_change_pageuser, 'can_delete_pageuser': can_delete_pageuser, @@ -506,15 +506,13 @@ def assign_user_to_page(page, user, grant_on=ACCESS_PAGE_AND_DESCENDANTS, :param can_*: Permissions to grant :param bool grant_all: Grant all permissions to the user """ - if can_publish is not None: - warnings.warn('This API function no longer accepts a "can_publish" argument.', - UserWarning, stacklevel=2) grant_all = grant_all and not global_permission data = { 'can_add': can_add or grant_all, 'can_change': can_change or grant_all, 'can_delete': can_delete or grant_all, + 'can_publish': can_publish or grant_all, 'can_change_advanced_settings': can_change_advanced_settings or grant_all, 'can_change_permissions': can_change_permissions or grant_all, 'can_move_page': can_move_page or grant_all, diff --git a/cms/cache/permissions.py b/cms/cache/permissions.py index 2ba2ac13974..2956441fb01 100644 --- a/cms/cache/permissions.py +++ b/cms/cache/permissions.py @@ -3,7 +3,7 @@ PERMISSION_KEYS = [ 'add_page', 'change_page', 'change_page_advanced_settings', 'change_page_permissions', 'delete_page', 'move_page', - 'view_page', + 'publish_page', 'view_page', ] diff --git a/cms/cache/placeholder.py b/cms/cache/placeholder.py index cc9064b557e..12623b85868 100644 --- a/cms/cache/placeholder.py +++ b/cms/cache/placeholder.py @@ -96,7 +96,8 @@ def _get_placeholder_cache_key(placeholder, lang, site_id, request, soft=False): """ prefix = get_cms_setting('CACHE_PREFIX') version, vary_on_list = _get_placeholder_cache_version(placeholder, lang, site_id) - main_key = f'{prefix}|render_placeholder|id:{placeholder.pk}|lang:{lang}|site:{site_id}|tz:{get_timezone_name()}|v:{version}' + tz = get_timezone_name() + main_key = f"{prefix}|render_placeholder|id:{placeholder.pk}|lang:{lang}|site:{site_id}|tz:{tz}|v:{version}" if not soft: # We are about to write to the cache, so we want to get the latest diff --git a/cms/migrations/0035_auto_20230822_2208_squashed_0036_auto_20240311_1028.py b/cms/migrations/0035_auto_20230822_2208_squashed_0036_auto_20240311_1028.py new file mode 100644 index 00000000000..6136f521fac --- /dev/null +++ b/cms/migrations/0035_auto_20230822_2208_squashed_0036_auto_20240311_1028.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.23 on 2024-03-11 09:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + replaces = [('cms', '0035_auto_20230822_2208'), ('cms', '0036_auto_20240311_1028')] + + dependencies = [ + ('cms', '0034_remove_pagecontent_placeholders'), + ] + + operations = [ + migrations.AlterModelOptions( + name='pagecontent', + options={'default_permissions': [], 'verbose_name': 'page content', 'verbose_name_plural': 'page contents'}, + ), + migrations.AlterModelOptions( + name='page', + options={'default_permissions': ('add', 'change', 'delete'), 'permissions': (('view_page', 'Can view page'), ('publish_page', 'Can publish page'), ('edit_static_placeholder', 'Can edit static placeholders')), 'verbose_name': 'page', 'verbose_name_plural': 'pages'}, + ), + ] diff --git a/cms/migrations/0036_auto_20240311_1028.py b/cms/migrations/0036_auto_20240311_1028.py new file mode 100644 index 00000000000..2b228d9e693 --- /dev/null +++ b/cms/migrations/0036_auto_20240311_1028.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.23 on 2024-03-11 10:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cms', '0035_auto_20230822_2208'), + ] + + operations = [ + migrations.AlterModelOptions( + name='page', + options={'default_permissions': ('add', 'change', 'delete'), 'permissions': (('view_page', 'Can view page'), ('publish_page', 'Can publish page'), ('edit_static_placeholder', 'Can edit static placeholders')), 'verbose_name': 'page', 'verbose_name_plural': 'pages'}, + ), + migrations.AddField( + model_name='globalpagepermission', + name='can_publish', + field=models.BooleanField(default=True, verbose_name='can publish'), + ), + migrations.AddField( + model_name='pagepermission', + name='can_publish', + field=models.BooleanField(default=True, verbose_name='can publish'), + ), + ] diff --git a/cms/models/contentmodels.py b/cms/models/contentmodels.py index 2b4946577b2..0a45249357c 100644 --- a/cms/models/contentmodels.py +++ b/cms/models/contentmodels.py @@ -172,6 +172,9 @@ def toggle_in_navigation(self, set_to=None): def has_placeholder_change_permission(self, user): return self.page.has_change_permission(user) + def has_publish_permission(self, user): + return self.page.has_publish_permission(user) + def rescan_placeholders(self): """ Rescan and if necessary create placeholders in the current template. diff --git a/cms/models/pagemodel.py b/cms/models/pagemodel.py index bcd53ae3e91..a290b6e3ec7 100644 --- a/cms/models/pagemodel.py +++ b/cms/models/pagemodel.py @@ -187,6 +187,7 @@ class Meta: default_permissions = ('add', 'change', 'delete') permissions = ( ('view_page', 'Can view page'), + ('publish_page', 'Can publish page'), ('edit_static_placeholder', 'Can edit static placeholders'), ) verbose_name = _('page') @@ -995,6 +996,10 @@ def has_delete_translation_permission(self, user, language): from cms.utils.page_permissions import user_can_delete_page_translation return user_can_delete_page_translation(user, page=self, language=language) + def has_publish_permission(self, user): + from cms.utils.page_permissions import user_can_publish_page + return user_can_publish_page(user, page=self) + def has_advanced_settings_permission(self, user): from cms.utils.page_permissions import ( user_can_change_page_advanced_settings, diff --git a/cms/models/permissionmodels.py b/cms/models/permissionmodels.py index c6b86ae233a..51884f13a51 100644 --- a/cms/models/permissionmodels.py +++ b/cms/models/permissionmodels.py @@ -83,6 +83,7 @@ class AbstractPagePermission(models.Model): can_change = models.BooleanField(_("can edit"), default=True) can_add = models.BooleanField(_("can add"), default=True) can_delete = models.BooleanField(_("can delete"), default=True) + can_publish = models.BooleanField(_("can publish"), default=True) can_change_advanced_settings = models.BooleanField(_("can change advanced settings"), default=False) can_change_permissions = models.BooleanField( _("can change permissions"), default=False, help_text=_("on page level") @@ -113,6 +114,11 @@ def clean(self): "to change the page. Edit permissions required.") raise ValidationError(message) + if self.can_publish: + message = _("Users can't publish a page without permissions " + "to change the page. Edit permissions required.") + raise ValidationError(message) + if self.can_change_advanced_settings: message = _("Users can't change page advanced settings without permissions " "to change the page. Edit permissions required.") @@ -156,6 +162,7 @@ def get_all_permissions(cls): 'can_add', 'can_change', 'can_delete', + 'can_publish', 'can_change_advanced_settings', 'can_change_permissions', 'can_move_page', @@ -174,6 +181,7 @@ def get_permissions_by_action(cls): 'change_page_permissions': ['can_change', 'can_change_permissions'], 'delete_page': ['can_change', 'can_delete'], 'delete_page_translation': ['can_change', 'can_delete'], + 'publish_page': ['can_change', 'can_publish'], 'move_page': ['can_change', 'can_move_page'], 'view_page': ['can_view'], } diff --git a/cms/templates/admin/cms/page/permissions.html b/cms/templates/admin/cms/page/permissions.html index fa90c1170c4..51db1e50739 100644 --- a/cms/templates/admin/cms/page/permissions.html +++ b/cms/templates/admin/cms/page/permissions.html @@ -38,6 +38,7 @@