Cleaned up users app.

This commit is contained in:
Norman Jäckel 2015-09-16 00:55:27 +02:00
parent d7fd61e979
commit 1e08e9411a
19 changed files with 175 additions and 308 deletions

View File

@ -91,13 +91,6 @@ INSTALLED_APPS = (
'openslides.mediafiles', 'openslides.mediafiles',
) )
TEMPLATE_CONTEXT_PROCESSORS = (
'openslides.users.auth.auth',
'django.contrib.messages.context_processors.messages',
'django.core.context_processors.request',
'django.core.context_processors.i18n',
'django.core.context_processors.static',
)
CACHES = { CACHES = {
'default': { 'default': {
@ -175,6 +168,6 @@ TEST_RUNNER = 'openslides.utils.test.OpenSlidesDiscoverRunner'
REST_FRAMEWORK = { REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ( 'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.SessionAuthentication',
'openslides.users.auth.AnonymousAuthentication', 'openslides.users.auth.RESTFrameworkAnonymousAuthentication',
) )
} }

View File

@ -1,10 +0,0 @@
from .models import Permission
def get_protected_perm():
"""
Returns the permission to manage users. This function is a helper
function used to protect manager users from locking out themselves.
"""
return Permission.objects.get_by_natural_key(
app_label='users', model='user', codename='can_manage')

View File

@ -10,12 +10,12 @@ class UsersAppConfig(AppConfig):
def ready(self): def ready(self):
# Load projector elements. # Load projector elements.
# Do this by just importing all from these files. # Just import this file.
from . import projector # noqa from . import projector # noqa
# Import all required stuff. # Import all required stuff.
from openslides.core.signals import config_signal, post_permission_creation from ..core.signals import config_signal, post_permission_creation
from openslides.utils.rest_api import router from ..utils.rest_api import router
from .signals import create_builtin_groups_and_admin, setup_users_config from .signals import create_builtin_groups_and_admin, setup_users_config
from .views import GroupViewSet, UserViewSet from .views import GroupViewSet, UserViewSet

View File

@ -1,63 +1,30 @@
from django.contrib.auth import get_user as _get_user from django.contrib.auth import get_user as _get_user
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.context_processors import auth as _auth
from django.contrib.auth.models import AnonymousUser as DjangoAnonymousUser from django.contrib.auth.models import AnonymousUser as DjangoAnonymousUser
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.db.models import Q from django.db.models import Q
from django.utils.functional import SimpleLazyObject from django.utils.functional import SimpleLazyObject
from rest_framework.authentication import BaseAuthentication from rest_framework.authentication import BaseAuthentication
from openslides.core.config import config from ..core.config import config
class AnonymousUser(DjangoAnonymousUser): # Registered users
"""
Class for anonymous user instances, which have the permissions from the
Group 'Anonymous' (pk=1).
"""
def get_all_permissions(self, obj=None):
"""
Return the permissions a user is granted by his group membership(s).
Try to return the permissions for the 'Anonymous' group (pk=1).
"""
perms = Permission.objects.filter(group__pk=1)
if perms is None:
return set()
# TODO: test without order_by()
perms = perms.values_list('content_type__app_label', 'codename').order_by()
return set(['%s.%s' % (content_type, codename) for content_type, codename in perms])
def has_perm(self, perm, obj=None):
"""
Check if the user has a specific permission
"""
return (perm in self.get_all_permissions())
def has_module_perms(self, app_label):
"""
Check if the user has permissions on the module app_label
"""
for perm in self.get_all_permissions():
if perm[:perm.index('.')] == app_label:
return True
return False
class CustomizedModelBackend(ModelBackend): class CustomizedModelBackend(ModelBackend):
""" """
Customized backend for authentication. Ensures that registered users have Customized backend for authentication. Ensures that registered users
all permission of the group 'Registered' (pk=2). have all permissions of the group 'Registered' (pk=2). See
AUTHENTICATION_BACKENDS settings.
""" """
def get_group_permissions(self, user_obj, obj=None): def get_group_permissions(self, user_obj, obj=None):
""" """
Returns a set of permission strings that this user has through his/her Returns a set of permission strings that this user has through his/her
groups. groups.
""" """
# TODO: Refactor this after Django 1.8 release. Add also anonymous # TODO: Refactor this after Django 1.8 is minimum requirement. Add
# permission check to this backend. # also anonymous permission check to this backend.
if user_obj.is_anonymous() or obj is not None: if user_obj.is_anonymous() or obj is not None:
return set() return set()
if not hasattr(user_obj, '_group_perm_cache'): if not hasattr(user_obj, '_group_perm_cache'):
@ -74,11 +41,61 @@ class CustomizedModelBackend(ModelBackend):
return user_obj._group_perm_cache return user_obj._group_perm_cache
class AuthenticationMiddleware(object): # Anonymous users
class AnonymousUser(DjangoAnonymousUser):
"""
Class for anonymous user instances which have the permissions from the
group 'Anonymous' (pk=1).
"""
def get_all_permissions(self, obj=None):
"""
Returns the permissions a user is granted by his group membership(s).
Try to return the permissions for the 'Anonymous' group (pk=1).
"""
perms = Permission.objects.filter(group__pk=1)
if perms is None:
return set()
# TODO: Test without order_by()
perms = perms.values_list('content_type__app_label', 'codename').order_by()
return set(['%s.%s' % (content_type, codename) for content_type, codename in perms])
def has_perm(self, perm, obj=None):
"""
Checks if the user has a specific permission.
"""
return (perm in self.get_all_permissions())
def has_module_perms(self, app_label):
"""
Checks if the user has permissions on the module app_label.
"""
for perm in self.get_all_permissions():
if perm[:perm.index('.')] == app_label:
return True
return False
class RESTFrameworkAnonymousAuthentication(BaseAuthentication):
"""
Authentication class for the Django REST framework.
Sets the user to the our AnonymousUser but only if
general_system_enable_anonymous is set to True in the config.
"""
def authenticate(self, request):
if config['general_system_enable_anonymous']:
return (AnonymousUser(), None)
return None
class AuthenticationMiddleware:
""" """
Middleware to get the logged in user in users. Middleware to get the logged in user in users.
Uses AnonymousUser instead of the django anonymous user. Uses AnonymousUser instead of Django's anonymous user.
""" """
def process_request(self, request): def process_request(self, request):
""" """
@ -94,20 +111,6 @@ class AuthenticationMiddleware(object):
request.user = SimpleLazyObject(lambda: get_user(request)) request.user = SimpleLazyObject(lambda: get_user(request))
class AnonymousAuthentication(BaseAuthentication):
"""
Authentication class for the Django REST framework.
Sets the user to the our AnonymousUser but only if
general_system_enable_anonymous is set to True in the config.
"""
def authenticate(self, request):
if config['general_system_enable_anonymous']:
return (AnonymousUser(), None)
return None
def get_user(request): def get_user(request):
""" """
Gets the user from the request. Gets the user from the request.
@ -124,22 +127,3 @@ def get_user(request):
return_user = AnonymousUser() return_user = AnonymousUser()
request._cached_user = return_user request._cached_user = return_user
return return_user return return_user
def auth(request):
"""
Contextmanager to handle auth.
Uses the django auth context manager to fill the context.
Alters the attribute user if the user is not authenticated.
"""
# Call the django standard auth function, like 'super()'
context = _auth(request)
# Change the django anonymous user with our anonymous user if anonymous auth
# is enabled
if config['general_system_enable_anonymous'] and isinstance(context['user'], DjangoAnonymousUser):
context['user'] = AnonymousUser()
return context

View File

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

View File

@ -1,6 +1,6 @@
from django.core.management.base import NoArgsCommand from django.core.management.base import NoArgsCommand
from openslides.users.models import User from ...models import User
class Command(NoArgsCommand): class Command(NoArgsCommand):

View File

@ -1,27 +1,29 @@
from random import choice from random import choice
from django.contrib.auth.hashers import make_password from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import ( # noqa from django.contrib.auth.models import (
AbstractBaseUser, AbstractBaseUser,
BaseUserManager, BaseUserManager,
Group, Group,
Permission,
PermissionsMixin, PermissionsMixin,
) )
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy, ugettext_noop from django.utils.translation import ugettext_lazy, ugettext_noop
from openslides.core.config import config from ..core.config import config
from openslides.utils.models import RESTModelMixin from ..utils.models import RESTModelMixin
from .exceptions import UsersError
from .exceptions import UserError
class UserManager(BaseUserManager): class UserManager(BaseUserManager):
""" """
UserManager that creates new users only with a password and a username. Customized manager that creates new users only with a password and a
username.
""" """
def create_user(self, username, password, **kwargs): def create_user(self, username, password, **kwargs):
"""
Creates a new user only with a password and a username.
"""
user = self.model(username=username, **kwargs) user = self.model(username=username, **kwargs)
user.set_password(password) user.set_password(password)
user.save(using=self._db) user.save(using=self._db)
@ -29,15 +31,15 @@ class UserManager(BaseUserManager):
def create_or_reset_admin_user(self): def create_or_reset_admin_user(self):
""" """
Creates an user with the username admin. If such a user exists, resets Creates an user with the username 'admin'. If such a user already
it. The password is (re)set to 'admin'. The user becomes member of the exists, resets it. The password is (re)set to 'admin'. The user
group 'Staff' (pk=4). becomes member of the group 'Staff' (pk=4).
""" """
try: try:
staff = Group.objects.get(pk=4) staff = Group.objects.get(pk=4)
except Group.DoesNotExist: except Group.DoesNotExist:
raise UserError("Admin user can not be created or reset because " raise UsersError("Admin user can not be created or reset because "
"the group 'Staff' is not available.") "the group 'Staff' (pk=4) is not available.")
admin, created = self.get_or_create( admin, created = self.get_or_create(
username='admin', username='admin',
defaults={'last_name': 'Administrator'}) defaults={'last_name': 'Administrator'})
@ -60,7 +62,7 @@ class UserManager(BaseUserManager):
base_name = first_name or last_name base_name = first_name or last_name
if not base_name: if not base_name:
raise ValueError("Either 'first_name' or 'last_name' must not be " raise ValueError("Either 'first_name' or 'last_name' must not be "
"empty") "empty.")
if not self.filter(username=base_name).exists(): if not self.filter(username=base_name).exists():
generated_username = base_name generated_username = base_name
@ -77,7 +79,7 @@ class UserManager(BaseUserManager):
def generate_password(self): def generate_password(self):
""" """
Generates a random passwort. Generates a random passwort. Do not use l, o, I, O, 1 or 0.
""" """
chars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789' chars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
size = 8 size = 8
@ -86,56 +88,75 @@ class UserManager(BaseUserManager):
class User(RESTModelMixin, PermissionsMixin, AbstractBaseUser): class User(RESTModelMixin, PermissionsMixin, AbstractBaseUser):
""" """
Model for users in OpenSlides. A client can login as a user with Model for users in OpenSlides. A client can login as an user with
credentials. A user can also just be used as representation for a person credentials. An user can also just be used as representation for a person
in other OpenSlides app like motion submitter or (assignment) election in other OpenSlides apps like motion submitter or (assignment) election
candidates. candidates.
""" """
USERNAME_FIELD = 'username' USERNAME_FIELD = 'username'
slide_callback_name = 'user'
username = models.CharField( username = models.CharField(
ugettext_lazy('Username'), max_length=255, unique=True, blank=True) ugettext_lazy('Username'),
max_length=255,
unique=True,
blank=True)
first_name = models.CharField( first_name = models.CharField(
ugettext_lazy('First name'), max_length=255, blank=True) ugettext_lazy('First name'),
max_length=255,
blank=True)
last_name = models.CharField( last_name = models.CharField(
ugettext_lazy('Last name'), max_length=255, blank=True) ugettext_lazy('Last name'),
max_length=255,
blank=True)
# TODO: Try to remove the default argument in the following fields.
# TODO: try to remove the default argument in the following fields
structure_level = models.CharField( structure_level = models.CharField(
max_length=255, blank=True, default='', ugettext_lazy('Structure level'),
verbose_name=ugettext_lazy('Structure level'), max_length=255,
blank=True,
default='',
help_text=ugettext_lazy('Will be shown after the name.')) help_text=ugettext_lazy('Will be shown after the name.'))
title = models.CharField( title = models.CharField(
max_length=50, blank=True, default='', ugettext_lazy('Title'),
verbose_name=ugettext_lazy('Title'), max_length=50,
blank=True,
default='',
help_text=ugettext_lazy('Will be shown before the name.')) help_text=ugettext_lazy('Will be shown before the name.'))
about_me = models.TextField( about_me = models.TextField(
blank=True, default='', verbose_name=ugettext_lazy('About me'), ugettext_lazy('About me'),
help_text=ugettext_lazy('Your profile text')) blank=True,
default='',
help_text=ugettext_lazy('Profile text.'))
comment = models.TextField( comment = models.TextField(
blank=True, default='', verbose_name=ugettext_lazy('Comment'), ugettext_lazy('Comment'),
blank=True,
default='',
help_text=ugettext_lazy('Only for notes.')) help_text=ugettext_lazy('Only for notes.'))
default_password = models.CharField( default_password = models.CharField(
max_length=100, blank=True, default='', ugettext_lazy('Default password'),
verbose_name=ugettext_lazy('Default password')) max_length=100,
blank=True,
default='')
is_active = models.BooleanField( is_active = models.BooleanField(
ugettext_lazy('active'), default=True, ugettext_lazy('Active'),
default=True,
help_text=ugettext_lazy( help_text=ugettext_lazy(
'Designates whether this user should be treated as ' 'Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.')) 'active. Unselect this instead of deleting the account.'))
is_present = models.BooleanField( is_present = models.BooleanField(
ugettext_lazy('present'), default=False, ugettext_lazy('Present'),
help_text=ugettext_lazy('Designates whether this user is in the room ' default=False,
'or not.')) help_text=ugettext_lazy(
'Designates whether this user is in the room or not.'))
objects = UserManager() objects = UserManager()
@ -145,19 +166,11 @@ class User(RESTModelMixin, PermissionsMixin, AbstractBaseUser):
('can_see_extra_data', ugettext_noop('Can see extra data of users')), ('can_see_extra_data', ugettext_noop('Can see extra data of users')),
('can_manage', ugettext_noop('Can manage users')), ('can_manage', ugettext_noop('Can manage users')),
) )
ordering = ('last_name',) ordering = ('last_name', 'first_name', 'username', )
def __str__(self): def __str__(self):
return self.get_full_name() return self.get_full_name()
def get_slide_context(self, **context):
"""
Returns the context for the user slide.
"""
# Does not call super. In this case the context would override the name
# 'user'.
return {'shown_user': self}
def get_full_name(self): def get_full_name(self):
""" """
Returns a long form of the name. Returns a long form of the name.
@ -166,7 +179,6 @@ class User(RESTModelMixin, PermissionsMixin, AbstractBaseUser):
* Professor Dr. Enders, Christoph (Leipzig) * Professor Dr. Enders, Christoph (Leipzig)
""" """
structure = '(%s)' % self.structure_level if self.structure_level else '' structure = '(%s)' % self.structure_level if self.structure_level else ''
return ' '.join((self.title, self.get_short_name(), structure)).strip() return ' '.join((self.title, self.get_short_name(), structure)).strip()
def get_short_name(self): def get_short_name(self):
@ -190,15 +202,9 @@ class User(RESTModelMixin, PermissionsMixin, AbstractBaseUser):
# The user has only a first_name or a last_name or no name # The user has only a first_name or a last_name or no name
else: else:
name = first_name or last_name or self.username name = first_name or last_name or self.username
return name
def reset_password(self, password=None): # Return result
""" return name
Reset the password for the user to his default-password.
"""
if password is None:
password = self.default_password
self.set_password(password)
def get_view_class(self): def get_view_class(self):
""" """

View File

@ -14,9 +14,8 @@ from reportlab.platypus import (
TableStyle, TableStyle,
) )
from openslides.core.config import config from ..core.config import config
from openslides.utils.pdf import stylesheet from ..utils.pdf import stylesheet
from .models import User from .models import User

View File

@ -1,8 +1,7 @@
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from openslides.core.exceptions import ProjectorException from ..core.exceptions import ProjectorException
from openslides.utils.projector import ProjectorElement, ProjectorRequirement from ..utils.projector import ProjectorElement, ProjectorRequirement
from .models import User from .models import User
from .views import GroupViewSet, UserViewSet from .views import GroupViewSet, UserViewSet

View File

@ -6,8 +6,8 @@ from .models import User
class Index(indexes.SearchIndex, indexes.Indexable): class Index(indexes.SearchIndex, indexes.Indexable):
text = indexes.EdgeNgramField(document=True, use_template=True) text = indexes.EdgeNgramField(document=True, use_template=True)
text = indexes.EdgeNgramField(document=True, use_template=True) text = indexes.EdgeNgramField(document=True, use_template=True)
modelfilter_name = "Users" # verbose_name of model modelfilter_name = 'Users' # verbose_name of model
modelfilter_value = "users.user" # 'app_name.model_name' modelfilter_value = 'users.user' # 'app_name.model_name'
def get_model(self): def get_model(self):
return User return User

View File

@ -1,15 +1,15 @@
from django.contrib.auth.hashers import make_password from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import Permission
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy from django.utils.translation import ugettext_lazy
from openslides.utils.rest_api import ( from ..utils.rest_api import (
ModelSerializer, ModelSerializer,
PrimaryKeyRelatedField, PrimaryKeyRelatedField,
RelatedField, RelatedField,
ValidationError, ValidationError,
) )
from .models import Group, User
from .models import Group, Permission, User
class UserShortSerializer(ModelSerializer): class UserShortSerializer(ModelSerializer):
@ -28,7 +28,8 @@ class UserShortSerializer(ModelSerializer):
'last_name', 'last_name',
'structure_level', 'structure_level',
'about_me', 'about_me',
'groups',) 'groups',
)
class UserFullSerializer(ModelSerializer): class UserFullSerializer(ModelSerializer):
@ -58,7 +59,8 @@ class UserFullSerializer(ModelSerializer):
'comment', 'comment',
'groups', 'groups',
'default_password', 'default_password',
'is_active',) 'is_active',
)
def validate(self, data): def validate(self, data):
""" """
@ -70,7 +72,7 @@ class UserFullSerializer(ModelSerializer):
raise ValidationError(_('Username, first name and last name can not all be empty.')) raise ValidationError(_('Username, first name and last name can not all be empty.'))
# Generate username. But only if it is not set and the serializer is not # Generate username. But only if it is not set and the serializer is not
# called in a patch-context. # called in a PATCH context (partial_update).
try: try:
action = self.context['view'].action action = self.context['view'].action
except (KeyError, AttributeError): except (KeyError, AttributeError):
@ -84,7 +86,7 @@ class UserFullSerializer(ModelSerializer):
def create(self, validated_data): def create(self, validated_data):
""" """
Creates the user. Sets the default_password. Adds the new user to the Creates the user. Sets the default password. Adds the new user to the
registered group. registered group.
""" """
# Prepare setup password. # Prepare setup password.
@ -139,4 +141,5 @@ class GroupSerializer(ModelSerializer):
fields = ( fields = (
'id', 'id',
'name', 'name',
'permissions',) 'permissions',
)

View File

@ -1,10 +1,10 @@
from django.contrib.auth.models import Permission
from django.db.models import Q from django.db.models import Q
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy, ugettext_noop from django.utils.translation import ugettext_lazy, ugettext_noop
from openslides.core.config import ConfigVariable from ..core.config import ConfigVariable
from .models import Group, User
from .models import Group, Permission, User
def setup_users_config(sender, **kwargs): def setup_users_config(sender, **kwargs):
@ -126,9 +126,10 @@ def create_builtin_groups_and_admin(**kwargs):
'users.can_manage', 'users.can_manage',
'users.can_see_extra_data', 'users.can_see_extra_data',
'users.can_see_name', ) 'users.can_see_name', )
permission_dict = {}
permission_query = Q() permission_query = Q()
permission_dict = {}
# Load all permissions
for permission_string in permission_strings: for permission_string in permission_strings:
app_label, codename = permission_string.split('.') app_label, codename = permission_string.split('.')
query_part = Q(content_type__app_label=app_label) & Q(codename=codename) query_part = Q(content_type__app_label=app_label) & Q(codename=codename)
@ -183,11 +184,12 @@ def create_builtin_groups_and_admin(**kwargs):
group_staff = Group.objects.create(name=ugettext_noop('Staff'), pk=4) group_staff = Group.objects.create(name=ugettext_noop('Staff'), pk=4)
group_staff.permissions.add(*staff_permissions) group_staff.permissions.add(*staff_permissions)
# Add users.can_see_name and users.can_see_extra_data permissions # Add users.can_see_name and users.can_see_extra_data permissions to staff
# group to ensure proper management possibilities
# TODO: Remove this redundancy after cleanup of the permission system. # TODO: Remove this redundancy after cleanup of the permission system.
group_staff.permissions.add( group_staff.permissions.add(
permission_dict['users.can_see_extra_data'], permission_dict['users.can_see_extra_data'],
permission_dict['users.can_see_name']) permission_dict['users.can_see_name'])
# Admin user # Create or reset admin user
User.objects.create_or_reset_admin_user() User.objects.create_or_reset_admin_user()

View File

@ -5,16 +5,7 @@ from . import views
urlpatterns = patterns( urlpatterns = patterns(
'', '',
# PDF # Auth
url(r'^print/$',
views.UsersListPDF.as_view(),
name='user_listpdf'),
url(r'^passwords/print/$',
views.UsersPasswordsPDF.as_view(),
name='user_passwordspdf'),
# auth
url(r'^login/$', url(r'^login/$',
views.UserLoginView.as_view(), views.UserLoginView.as_view(),
name='user_login'), name='user_login'),
@ -26,4 +17,13 @@ urlpatterns = patterns(
url(r'^whoami/$', url(r'^whoami/$',
views.WhoAmIView.as_view(), views.WhoAmIView.as_view(),
name='user_whoami'), name='user_whoami'),
# PDF
url(r'^print/$',
views.UsersListPDF.as_view(),
name='user_listpdf'),
url(r'^passwords/print/$',
views.UsersPasswordsPDF.as_view(),
name='user_passwordspdf'),
) )

View File

@ -3,12 +3,10 @@ from django.contrib.auth import logout as auth_logout
from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.forms import AuthenticationForm
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy from django.utils.translation import ugettext_lazy
from rest_framework import status
from openslides.core.config import config
from openslides.utils.rest_api import ModelViewSet, Response, detail_route
from openslides.utils.views import APIView, PDFView
from ..core.config import config
from ..utils.rest_api import ModelViewSet, Response, detail_route, status
from ..utils.views import APIView, PDFView
from .models import Group, User from .models import Group, User
from .pdf import users_passwords_to_pdf, users_to_pdf from .pdf import users_passwords_to_pdf, users_to_pdf
from .serializers import ( from .serializers import (
@ -185,7 +183,7 @@ class GroupViewSet(ModelViewSet):
class UserLoginView(APIView): class UserLoginView(APIView):
""" """
Login the user via Ajax. Login the user.
""" """
http_method_names = ['post'] http_method_names = ['post']
@ -208,7 +206,7 @@ class UserLoginView(APIView):
class UserLogoutView(APIView): class UserLogoutView(APIView):
""" """
Logout the user via Ajax. Logout the user.
""" """
http_method_names = ['post'] http_method_names = ['post']
@ -225,7 +223,7 @@ class WhoAmIView(APIView):
def get_context_data(self, **context): def get_context_data(self, **context):
""" """
Appends the user id into the context. Appends the user id to the context.
Uses None for the anonymous user. Uses None for the anonymous user.
""" """
@ -238,11 +236,11 @@ class WhoAmIView(APIView):
class UsersListPDF(PDFView): class UsersListPDF(PDFView):
""" """
Generate the userliste as PDF. Generate a list of all users as PDF.
""" """
required_permission = 'users.can_see_extra_data' required_permission = 'users.can_see_extra_data'
filename = ugettext_lazy("user-list") filename = ugettext_lazy('user-list')
document_title = ugettext_lazy('List of Users') document_title = ugettext_lazy('List of users')
def append_to_pdf(self, pdf): def append_to_pdf(self, pdf):
""" """
@ -256,7 +254,7 @@ class UsersPasswordsPDF(PDFView):
Generate the access data welcome paper for all users as PDF. Generate the access data welcome paper for all users as PDF.
""" """
required_permission = 'users.can_manage' required_permission = 'users.can_manage'
filename = ugettext_lazy("User-access-data") filename = ugettext_lazy('user-access-data')
top_space = 0 top_space = 0
def build_document(self, pdf_document, story): def build_document(self, pdf_document, story):

View File

@ -2,6 +2,7 @@ import re
from collections import OrderedDict from collections import OrderedDict
from urllib.parse import urlparse from urllib.parse import urlparse
from rest_framework import status # noqa
from rest_framework.decorators import detail_route, list_route # noqa from rest_framework.decorators import detail_route, list_route # noqa
from rest_framework.metadata import SimpleMetadata # noqa from rest_framework.metadata import SimpleMetadata # noqa
from rest_framework.mixins import DestroyModelMixin, UpdateModelMixin # noqa from rest_framework.mixins import DestroyModelMixin, UpdateModelMixin # noqa

View File

@ -1,25 +1,10 @@
import roman import roman
from django.contrib.auth.models import Permission
def delete_default_permissions(**kwargs):
"""
Deletes the permissions, django creates by default for the admin.
"""
# TODO: Find a way not to create the permissions in the first place.
# Meta.default_permissions does not work, because django will
# nevertheless create permissions for its own models like "group"
for p in Permission.objects.all():
if (p.codename.startswith('add') or
p.codename.startswith('delete') or
p.codename.startswith('change')):
p.delete()
def to_roman(number): def to_roman(number):
""" """
Converts an arabic number within range from 1 to 4999 to the corresponding roman number. Converts an arabic number within range from 1 to 4999 to the
Returns None on error conditions. corresponding roman number. Returns None on error conditions.
""" """
try: try:
return roman.toRoman(number) return roman.toRoman(number)

View File

@ -1,19 +0,0 @@
from unittest import TestCase
from unittest.mock import patch
from openslides.users.api import get_protected_perm
@patch('openslides.users.api.Permission')
class GetProtectedPerm(TestCase):
def test_normal(self, mock_permission):
mock_permission.objects.get_by_natural_key.return_value = 'test_permission'
value = get_protected_perm()
mock_permission.objects.get_by_natural_key.assert_called_once_with(
app_label='users', model='user', codename='can_manage')
self.assertEqual(
value,
'test_permission',
"The function should return the user.can_manage permission")

View File

@ -1,7 +1,7 @@
from unittest import TestCase from unittest import TestCase
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from openslides.users.auth import AnonymousUser, auth, get_user from openslides.users.auth import AnonymousUser, get_user
class TestAnonymousUser(TestCase): class TestAnonymousUser(TestCase):
@ -98,40 +98,3 @@ class TestGetUser(TestCase):
request._cached_user, request._cached_user,
'django_anonymous_user', 'django_anonymous_user',
"The django user should be cached") "The django user should be cached")
@patch('openslides.users.auth.config')
@patch('openslides.users.auth._auth')
class TestAuth(TestCase):
def test_anonymous_enabled(self, mock_auth, mock_config):
mock_config.__getitem__.return_value = True
request = MagicMock()
mock_auth.return_value = {'user': AnonymousUser()}
context = auth(request)
self.assertEqual(
context,
{'user': AnonymousUser()})
def test_anonymous_disabled(self, mock_auth, mock_config):
mock_config.__getitem__.return_value = False
request = MagicMock()
mock_auth.return_value = {'user': AnonymousUser()}
context = auth(request)
self.assertEqual(
context,
{'user': AnonymousUser()})
def test_logged_in_user_in_request(self, mock_auth, mock_config):
mock_config.__getitem__.return_value = True
request = MagicMock()
mock_auth.return_value = {'user': 'logged_in_user'}
context = auth(request)
self.assertEqual(
context,
{'user': 'logged_in_user'})

View File

@ -18,19 +18,6 @@ class UserTest(TestCase):
'Test Value IJee1yoet1ooGhesh5li', 'Test Value IJee1yoet1ooGhesh5li',
"The str representation of User is not user.get_full_name().") "The str representation of User is not user.get_full_name().")
def test_get_slide_context(self):
"""
Tests, that get_slide_context returns:
{'shown_user': self}
"""
user = User()
self.assertEqual(
user.get_slide_context(),
{'shown_user': user},
"User.get_slide_context returns a wrong context.")
class UserGetFullName(TestCase): class UserGetFullName(TestCase):
def test_get_full_name_with_structure_level_and_title(self): def test_get_full_name_with_structure_level_and_title(self):
@ -185,30 +172,6 @@ class UserGetShortName(TestCase):
"User.get_short_name() has to strip whitespaces from the name parts.") "User.get_short_name() has to strip whitespaces from the name parts.")
class UserResetPassword(TestCase):
def test_reset_password_no_attribute(self):
"""
Tests reset_password with no attribute.
"""
user = User(default_password='test_default_password')
user.set_password = MagicMock()
user.reset_password()
user.set_password.assert_called_once_with('test_default_password')
def test_reset_password_with_attribute(self):
"""
Tests reset_password with no attribute.
"""
user = User(default_password='test_default_password')
user.set_password = MagicMock()
user.reset_password('test_password')
user.set_password.assert_called_once_with('test_password')
class UserManagerTest(TestCase): class UserManagerTest(TestCase):
def test_create_user(self): def test_create_user(self):
""" """