From 7879b01d1f96665b033b39649d708852d7a190ec Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 6 Oct 2014 12:09:30 +0100 Subject: [PATCH] Added permission for page locking Also created migrations to give this permission to moderators --- wagtail/tests/fixtures/test.json | 10 +- ..._add_page_lock_permission_to_moderators.py | 28 +++++ wagtail/wagtailcore/models.py | 3 +- ..._add_page_lock_permission_to_moderators.py | 118 ++++++++++++++++++ .../tests/test_page_permissions.py | 32 +++++ 5 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 wagtail/wagtailcore/migrations/0005_add_page_lock_permission_to_moderators.py create mode 100644 wagtail/wagtailcore/south_migrations/0008_add_page_lock_permission_to_moderators.py diff --git a/wagtail/tests/fixtures/test.json b/wagtail/tests/fixtures/test.json index 940874435..414a2e96e 100644 --- a/wagtail/tests/fixtures/test.json +++ b/wagtail/tests/fixtures/test.json @@ -435,7 +435,15 @@ "permission_type": "edit" } }, - +{ + "pk": 6, + "model": "wagtailcore.grouppagepermission", + "fields": { + "group": ["Event moderators"], + "page": 3, + "permission_type": "lock" + } +}, { "pk": 1, "model": "tests.customuser", diff --git a/wagtail/wagtailcore/migrations/0005_add_page_lock_permission_to_moderators.py b/wagtail/wagtailcore/migrations/0005_add_page_lock_permission_to_moderators.py new file mode 100644 index 000000000..03a173019 --- /dev/null +++ b/wagtail/wagtailcore/migrations/0005_add_page_lock_permission_to_moderators.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +def add_page_lock_permission_to_moderators(apps, schema_editor): + Group = apps.get_model('auth.Group') + Page = apps.get_model('wagtailcore.Page') + GroupPagePermission = apps.get_model('wagtailcore.GroupPagePermission') + + root_pages = Page.objects.filter(depth=1) + moderators_group = Group.objects.get(name='Moderators') + + for page in root_pages: + GroupPagePermission.objects.create( + group=moderators_group, page=page, permission_type='lock') + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0004_page_locked'), + ] + + operations = [ + migrations.RunPython(add_page_lock_permission_to_moderators), + ] diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index f12bda217..c67ddc76f 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -996,6 +996,7 @@ PAGE_PERMISSION_TYPE_CHOICES = [ ('add', 'Add/edit pages you own'), ('edit', 'Add/edit any page'), ('publish', 'Publish any page'), + ('lock', 'Lock/unlock any page'), ] @@ -1165,7 +1166,7 @@ class PagePermissionTester(object): return self.can_publish() def can_lock(self): - return self.user.is_superuser + return self.user.is_superuser or ('lock' in self.permissions) def can_publish_subpage(self): """ diff --git a/wagtail/wagtailcore/south_migrations/0008_add_page_lock_permission_to_moderators.py b/wagtail/wagtailcore/south_migrations/0008_add_page_lock_permission_to_moderators.py new file mode 100644 index 000000000..e315535d6 --- /dev/null +++ b/wagtail/wagtailcore/south_migrations/0008_add_page_lock_permission_to_moderators.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models, connection + + +class Migration(DataMigration): + + def forwards(self, orm): + if connection.vendor == 'sqlite': + set_autocommit(True) + + root_pages = orm['wagtailcore.page'].objects.filter(depth=1) + moderators_group = orm['auth.group'].objects.get(name='Moderators') + + for page in root_pages: + orm['wagtailcore.grouppagepermission'].objects.create( + group=moderators_group, page=page, permission_type='lock') + + def backwards(self, orm): + pass + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'user_set'", 'blank': 'True', 'to': "orm['auth.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'user_set'", 'blank': 'True', 'to': "orm['auth.Permission']"}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'wagtailcore.grouppagepermission': { + 'Meta': {'unique_together': "(('group', 'page', 'permission_type'),)", 'object_name': 'GroupPagePermission'}, + 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'page_permissions'", 'to': "orm['auth.Group']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_permissions'", 'to': "orm['wagtailcore.Page']"}), + 'permission_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}) + }, + 'wagtailcore.page': { + 'Meta': {'object_name': 'Page'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pages'", 'to': "orm['contenttypes.ContentType']"}), + 'depth': ('django.db.models.fields.PositiveIntegerField', [], {}), + 'expire_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'go_live_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'has_unpublished_changes': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'live': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'numchild': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'owned_pages'", 'null': 'True', 'to': "orm['auth.User']"}), + 'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), + 'search_description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'seo_title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'show_in_menus': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'url_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}) + }, + 'wagtailcore.pagerevision': { + 'Meta': {'object_name': 'PageRevision'}, + 'approved_go_live_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'content_json': ('django.db.models.fields.TextField', [], {}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'revisions'", 'to': "orm['wagtailcore.Page']"}), + 'submitted_for_moderation': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) + }, + 'wagtailcore.pageviewrestriction': { + 'Meta': {'object_name': 'PageViewRestriction'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'view_restrictions'", 'to': "orm['wagtailcore.Page']"}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'wagtailcore.site': { + 'Meta': {'unique_together': "(('hostname', 'port'),)", 'object_name': 'Site'}, + 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_default_site': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'port': ('django.db.models.fields.IntegerField', [], {'default': '80'}), + 'root_page': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sites_rooted_here'", 'to': "orm['wagtailcore.Page']"}) + } + } + + complete_apps = ['wagtailcore'] + symmetrical = True diff --git a/wagtail/wagtailcore/tests/test_page_permissions.py b/wagtail/wagtailcore/tests/test_page_permissions.py index be759d975..bd2bd3f31 100644 --- a/wagtail/wagtailcore/tests/test_page_permissions.py +++ b/wagtail/wagtailcore/tests/test_page_permissions.py @@ -299,3 +299,35 @@ class TestPagePermission(TestCase): self.assertFalse(publishable_pages.filter(id=someone_elses_event_page.id).exists()) self.assertFalse(can_publish_pages) + + def test_lock_page_for_superuser(self): + user = get_user_model().objects.get(username='superuser') + christmas_page = EventPage.objects.get(url_path='/home/events/christmas/') + + perms = UserPagePermissionsProxy(user).for_page(christmas_page) + + self.assertTrue(perms.can_lock()) + + def test_lock_page_for_moderator(self): + user = get_user_model().objects.get(username='eventmoderator') + christmas_page = EventPage.objects.get(url_path='/home/events/christmas/') + + perms = UserPagePermissionsProxy(user).for_page(christmas_page) + + self.assertTrue(perms.can_lock()) + + def test_lock_page_for_editor(self): + user = get_user_model().objects.get(username='eventeditor') + christmas_page = EventPage.objects.get(url_path='/home/events/christmas/') + + perms = UserPagePermissionsProxy(user).for_page(christmas_page) + + self.assertFalse(perms.can_lock()) + + def test_lock_page_for_non_editing_user(self): + user = get_user_model().objects.get(username='admin_only_user') + christmas_page = EventPage.objects.get(url_path='/home/events/christmas/') + + perms = UserPagePermissionsProxy(user).for_page(christmas_page) + + self.assertFalse(perms.can_lock())