Merge pull request #2370 from normanjaeckel/Issue2315

Migration for new permission matrix
This commit is contained in:
Norman Jäckel 2016-09-08 13:20:49 +02:00 committed by GitHub
commit b661a6e215
5 changed files with 121 additions and 30 deletions

View File

@ -1,5 +0,0 @@
from ..utils.exceptions import OpenSlidesError
class UsersError(OpenSlidesError):
pass

View File

@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-08-01 14:54
from __future__ import unicode_literals
from django.db import migrations, models
def migrate_groups_and_user_permissions(apps, schema_editor):
"""
This function migrates the database to the new groups logic:
- Rename group 'Anonymous' (pk=1) to 'Default'
- Rename group 'Registered users' (pk=2) to 'Previous group Registered'
- Add all users who are not in any group to this group (pk=2)
- Add all permissions of 'Previous group Registered' to all other groups (except 'Default')
But only run this migration if:
- there are groups in the database,
- the name of the first group is 'Guests',
- the name of the second group is 'Registered users'.
"""
# Disconnect autoupdate. We do not want to trigger it here.
models.signals.post_save.disconnect(dispatch_uid='inform_changed_data_receiver')
User = apps.get_model('users', 'User')
Group = apps.get_model('auth', 'Group')
try:
group_default = Group.objects.get(pk=1)
group_registered = Group.objects.get(pk=2)
except Group.DoesNotExist:
# One of the groups does not exist. Just do nothing.
pass
else:
if group_default.name == 'Guests' and group_registered.name == 'Registered users':
# Rename groups pk 1 and 2.
group_default.name = 'Default'
group_default.save()
group_registered.name = 'Previous group Registered'
group_registered.save()
# Move users without groups to group pk 2.
users = User.objects.all()
for user in users:
if not user.groups.exists():
user.groups.add(group_registered)
# Copy permissions of group pk 2 to all other groups except pk 1.
groups = Group.objects.filter(pk__gt=2)
for group in groups:
for permission in group_registered.permissions.all():
group.permissions.add(permission)
class Migration(migrations.Migration):
dependencies = [
('users', '0003_user_number'),
]
operations = [
migrations.RunPython(migrate_groups_and_user_permissions),
]

View File

@ -5,16 +5,17 @@ from django.contrib.auth.models import (
AbstractBaseUser,
BaseUserManager,
Group,
Permission,
PermissionsMixin,
)
from django.db import models
from django.db.models import Q
from openslides.utils.search import user_name_helper
from ..core.config import config
from ..utils.models import RESTModelMixin
from .access_permissions import UserAccessPermissions
from .exceptions import UsersError
class UserManager(BaseUserManager):
@ -35,13 +36,17 @@ class UserManager(BaseUserManager):
"""
Creates an user with the username 'admin'. If such a user already
exists, resets it. The password is (re)set to 'admin'. The user
becomes member of the group 'Staff' (pk=3).
becomes member of the group 'Staff'. The two important permissions
'users.can_see_name' and 'users.can_manage' are added to this group,
so that the admin can manage all other permissions.
"""
try:
staff = Group.objects.get(pk=3)
except Group.DoesNotExist:
raise UsersError("Admin user can not be created or reset because "
"the group 'Staff' (pk=3) is not available.")
query_can_see_name = Q(content_type__app_label='users') & Q(codename='can_see_name')
query_can_manage = Q(content_type__app_label='users') & Q(codename='can_manage')
staff, _ = Group.objects.get_or_create(name='Staff')
staff.permissions.add(Permission.objects.get(query_can_see_name))
staff.permissions.add(Permission.objects.get(query_can_manage))
admin, created = self.get_or_create(
username='admin',
defaults={'last_name': 'Administrator'})

View File

@ -10,9 +10,9 @@ def create_builtin_groups_and_admin(**kwargs):
Creates the builtin user: admin.
"""
# Check whether the group pk's 1 to 4 are free.
if Group.objects.filter(pk__in=range(1, 5)).exists():
# Do completely nothing if there are already some of our groups in the database.
# Check whether there are groups in the database.
if Group.objects.exists():
# Do completely nothing if there are already some groups in the database.
return
permission_strings = (

View File

@ -286,30 +286,26 @@ class UserManagerGeneratePassword(TestCase):
for _ in range(8)])
@patch('openslides.users.models.Permission')
@patch('openslides.users.models.Group')
class UserManagerCreateOrResetAdminUser(TestCase):
def test_get_admin_group(self, mock_group):
def test_add_admin_group(self, mock_group, mock_permission):
"""
Tests that the Group with pk=3 is added to the admin.
Tests that the Group with name='Staff' is added to the admin.
"""
def mock_side_effect(pk):
if pk == 3:
result = 'mock_staff'
else:
result = ''
return result
admin_user = MagicMock()
manager = UserManager()
manager.get_or_create = MagicMock(return_value=(admin_user, False))
mock_group.objects.get.side_effect = mock_side_effect
staff_group = MagicMock(name="Staff")
mock_group.objects.get_or_create = MagicMock(return_value=(staff_group, True))
mock_permission.get = MagicMock()
manager.create_or_reset_admin_user()
mock_group.objects.get.assert_called_once_with(pk=3)
admin_user.groups.add.assert_called_once_with('mock_staff')
admin_user.groups.add.assert_called_once_with(staff_group)
def test_password_set_to_admin(self, mock_group):
def test_password_set_to_admin(self, mock_group, mock_permission):
"""
Tests that the password of the admin is set to 'admin'.
"""
@ -317,6 +313,10 @@ class UserManagerCreateOrResetAdminUser(TestCase):
manager = UserManager()
manager.get_or_create = MagicMock(return_value=(admin_user, False))
staff_group = MagicMock(name="Staff")
mock_group.objects.get_or_create = MagicMock(return_value=(staff_group, True))
mock_permission.get = MagicMock()
manager.create_or_reset_admin_user()
self.assertEqual(
@ -325,7 +325,7 @@ class UserManagerCreateOrResetAdminUser(TestCase):
admin_user.save.assert_called_once_with()
@patch('openslides.users.models.User')
def test_return_value(self, mock_user, mock_group):
def test_return_value(self, mock_user, mock_group, mock_permission):
"""
Tests that the method returns True when a user is created.
"""
@ -334,6 +334,10 @@ class UserManagerCreateOrResetAdminUser(TestCase):
manager.get_or_create = MagicMock(return_value=(admin_user, True))
manager.model = mock_user
staff_group = MagicMock(name="Staff")
mock_group.objects.get_or_create = MagicMock(return_value=(staff_group, True))
mock_permission.get = MagicMock()
self.assertEqual(
manager.create_or_reset_admin_user(),
True,
@ -341,7 +345,7 @@ class UserManagerCreateOrResetAdminUser(TestCase):
"new user is created.")
@patch('openslides.users.models.User')
def test_attributes_of_created_user(self, mock_user, mock_group):
def test_attributes_of_created_user(self, mock_user, mock_group, mock_permission):
"""
Tests username and last_name of the created admin user.
"""
@ -350,6 +354,10 @@ class UserManagerCreateOrResetAdminUser(TestCase):
manager.get_or_create = MagicMock(return_value=(admin_user, True))
manager.model = mock_user
staff_group = MagicMock(name="Staff")
mock_group.objects.get_or_create = MagicMock(return_value=(staff_group, True))
mock_permission.get = MagicMock()
manager.create_or_reset_admin_user()
self.assertEqual(
@ -360,3 +368,24 @@ class UserManagerCreateOrResetAdminUser(TestCase):
admin_user.last_name,
'Administrator',
"The last_name of a new created admin should be 'Administrator'.")
def test_get_permissions(self, mock_group, mock_permission):
"""
Tests if two permissions are get
"""
admin_user = MagicMock()
manager = UserManager()
manager.get_or_create = MagicMock(return_value=(admin_user, True))
staff_group = MagicMock(name="Staff")
mock_group.objects.get_or_create = MagicMock(return_value=(staff_group, True))
permission_mock = MagicMock(name="test permission")
mock_permission.objects.get = MagicMock(return_value=permission_mock)
manager.create_or_reset_admin_user()
self.assertEqual(
mock_permission.objects.get.call_count,
2,
"Permission.get should be called two times")