Cleaned up users app.
This commit is contained in:
parent
d7fd61e979
commit
1e08e9411a
@ -91,13 +91,6 @@ INSTALLED_APPS = (
|
||||
'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 = {
|
||||
'default': {
|
||||
@ -175,6 +168,6 @@ TEST_RUNNER = 'openslides.utils.test.OpenSlidesDiscoverRunner'
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
'openslides.users.auth.AnonymousAuthentication',
|
||||
'openslides.users.auth.RESTFrameworkAnonymousAuthentication',
|
||||
)
|
||||
}
|
||||
|
@ -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')
|
@ -10,12 +10,12 @@ class UsersAppConfig(AppConfig):
|
||||
|
||||
def ready(self):
|
||||
# Load projector elements.
|
||||
# Do this by just importing all from these files.
|
||||
# Just import this file.
|
||||
from . import projector # noqa
|
||||
|
||||
# Import all required stuff.
|
||||
from openslides.core.signals import config_signal, post_permission_creation
|
||||
from openslides.utils.rest_api import router
|
||||
from ..core.signals import config_signal, post_permission_creation
|
||||
from ..utils.rest_api import router
|
||||
from .signals import create_builtin_groups_and_admin, setup_users_config
|
||||
from .views import GroupViewSet, UserViewSet
|
||||
|
||||
|
@ -1,63 +1,30 @@
|
||||
from django.contrib.auth import get_user as _get_user
|
||||
from django.contrib.auth import get_user_model
|
||||
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 Permission
|
||||
from django.db.models import Q
|
||||
from django.utils.functional import SimpleLazyObject
|
||||
from rest_framework.authentication import BaseAuthentication
|
||||
|
||||
from openslides.core.config import config
|
||||
from ..core.config import config
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
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
|
||||
|
||||
# Registered users
|
||||
|
||||
class CustomizedModelBackend(ModelBackend):
|
||||
"""
|
||||
Customized backend for authentication. Ensures that registered users have
|
||||
all permission of the group 'Registered' (pk=2).
|
||||
Customized backend for authentication. Ensures that registered users
|
||||
have all permissions of the group 'Registered' (pk=2). See
|
||||
AUTHENTICATION_BACKENDS settings.
|
||||
"""
|
||||
def get_group_permissions(self, user_obj, obj=None):
|
||||
"""
|
||||
Returns a set of permission strings that this user has through his/her
|
||||
groups.
|
||||
"""
|
||||
# TODO: Refactor this after Django 1.8 release. Add also anonymous
|
||||
# permission check to this backend.
|
||||
# TODO: Refactor this after Django 1.8 is minimum requirement. Add
|
||||
# also anonymous permission check to this backend.
|
||||
if user_obj.is_anonymous() or obj is not None:
|
||||
return set()
|
||||
if not hasattr(user_obj, '_group_perm_cache'):
|
||||
@ -74,11 +41,61 @@ class CustomizedModelBackend(ModelBackend):
|
||||
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.
|
||||
|
||||
Uses AnonymousUser instead of the django anonymous user.
|
||||
Uses AnonymousUser instead of Django's anonymous user.
|
||||
"""
|
||||
def process_request(self, request):
|
||||
"""
|
||||
@ -94,20 +111,6 @@ class AuthenticationMiddleware(object):
|
||||
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):
|
||||
"""
|
||||
Gets the user from the request.
|
||||
@ -124,22 +127,3 @@ def get_user(request):
|
||||
return_user = AnonymousUser()
|
||||
request._cached_user = 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
|
||||
|
@ -1,5 +1,5 @@
|
||||
from openslides.utils.exceptions import OpenSlidesError
|
||||
from ..utils.exceptions import OpenSlidesError
|
||||
|
||||
|
||||
class UserError(OpenSlidesError):
|
||||
class UsersError(OpenSlidesError):
|
||||
pass
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django.core.management.base import NoArgsCommand
|
||||
|
||||
from openslides.users.models import User
|
||||
from ...models import User
|
||||
|
||||
|
||||
class Command(NoArgsCommand):
|
||||
|
@ -1,27 +1,29 @@
|
||||
from random import choice
|
||||
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.contrib.auth.models import ( # noqa
|
||||
from django.contrib.auth.models import (
|
||||
AbstractBaseUser,
|
||||
BaseUserManager,
|
||||
Group,
|
||||
Permission,
|
||||
PermissionsMixin,
|
||||
)
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||
|
||||
from openslides.core.config import config
|
||||
from openslides.utils.models import RESTModelMixin
|
||||
|
||||
from .exceptions import UserError
|
||||
from ..core.config import config
|
||||
from ..utils.models import RESTModelMixin
|
||||
from .exceptions import UsersError
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
Creates a new user only with a password and a username.
|
||||
"""
|
||||
user = self.model(username=username, **kwargs)
|
||||
user.set_password(password)
|
||||
user.save(using=self._db)
|
||||
@ -29,15 +31,15 @@ class UserManager(BaseUserManager):
|
||||
|
||||
def create_or_reset_admin_user(self):
|
||||
"""
|
||||
Creates an user with the username admin. If such a user exists, resets
|
||||
it. The password is (re)set to 'admin'. The user becomes member of the
|
||||
group 'Staff' (pk=4).
|
||||
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=4).
|
||||
"""
|
||||
try:
|
||||
staff = Group.objects.get(pk=4)
|
||||
except Group.DoesNotExist:
|
||||
raise UserError("Admin user can not be created or reset because "
|
||||
"the group 'Staff' is not available.")
|
||||
raise UsersError("Admin user can not be created or reset because "
|
||||
"the group 'Staff' (pk=4) is not available.")
|
||||
admin, created = self.get_or_create(
|
||||
username='admin',
|
||||
defaults={'last_name': 'Administrator'})
|
||||
@ -60,7 +62,7 @@ class UserManager(BaseUserManager):
|
||||
base_name = first_name or last_name
|
||||
if not base_name:
|
||||
raise ValueError("Either 'first_name' or 'last_name' must not be "
|
||||
"empty")
|
||||
"empty.")
|
||||
|
||||
if not self.filter(username=base_name).exists():
|
||||
generated_username = base_name
|
||||
@ -77,7 +79,7 @@ class UserManager(BaseUserManager):
|
||||
|
||||
def generate_password(self):
|
||||
"""
|
||||
Generates a random passwort.
|
||||
Generates a random passwort. Do not use l, o, I, O, 1 or 0.
|
||||
"""
|
||||
chars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
|
||||
size = 8
|
||||
@ -86,56 +88,75 @@ class UserManager(BaseUserManager):
|
||||
|
||||
class User(RESTModelMixin, PermissionsMixin, AbstractBaseUser):
|
||||
"""
|
||||
Model for users in OpenSlides. A client can login as a user with
|
||||
credentials. A user can also just be used as representation for a person
|
||||
in other OpenSlides app like motion submitter or (assignment) election
|
||||
Model for users in OpenSlides. A client can login as an user with
|
||||
credentials. An user can also just be used as representation for a person
|
||||
in other OpenSlides apps like motion submitter or (assignment) election
|
||||
candidates.
|
||||
"""
|
||||
USERNAME_FIELD = 'username'
|
||||
slide_callback_name = 'user'
|
||||
|
||||
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(
|
||||
ugettext_lazy('First name'), max_length=255, blank=True)
|
||||
ugettext_lazy('First name'),
|
||||
max_length=255,
|
||||
blank=True)
|
||||
|
||||
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(
|
||||
max_length=255, blank=True, default='',
|
||||
verbose_name=ugettext_lazy('Structure level'),
|
||||
ugettext_lazy('Structure level'),
|
||||
max_length=255,
|
||||
blank=True,
|
||||
default='',
|
||||
help_text=ugettext_lazy('Will be shown after the name.'))
|
||||
|
||||
title = models.CharField(
|
||||
max_length=50, blank=True, default='',
|
||||
verbose_name=ugettext_lazy('Title'),
|
||||
ugettext_lazy('Title'),
|
||||
max_length=50,
|
||||
blank=True,
|
||||
default='',
|
||||
help_text=ugettext_lazy('Will be shown before the name.'))
|
||||
|
||||
about_me = models.TextField(
|
||||
blank=True, default='', verbose_name=ugettext_lazy('About me'),
|
||||
help_text=ugettext_lazy('Your profile text'))
|
||||
ugettext_lazy('About me'),
|
||||
blank=True,
|
||||
default='',
|
||||
help_text=ugettext_lazy('Profile text.'))
|
||||
|
||||
comment = models.TextField(
|
||||
blank=True, default='', verbose_name=ugettext_lazy('Comment'),
|
||||
ugettext_lazy('Comment'),
|
||||
blank=True,
|
||||
default='',
|
||||
help_text=ugettext_lazy('Only for notes.'))
|
||||
|
||||
default_password = models.CharField(
|
||||
max_length=100, blank=True, default='',
|
||||
verbose_name=ugettext_lazy('Default password'))
|
||||
ugettext_lazy('Default password'),
|
||||
max_length=100,
|
||||
blank=True,
|
||||
default='')
|
||||
|
||||
is_active = models.BooleanField(
|
||||
ugettext_lazy('active'), default=True,
|
||||
ugettext_lazy('Active'),
|
||||
default=True,
|
||||
help_text=ugettext_lazy(
|
||||
'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(
|
||||
ugettext_lazy('present'), default=False,
|
||||
help_text=ugettext_lazy('Designates whether this user is in the room '
|
||||
'or not.'))
|
||||
ugettext_lazy('Present'),
|
||||
default=False,
|
||||
help_text=ugettext_lazy(
|
||||
'Designates whether this user is in the room or not.'))
|
||||
|
||||
objects = UserManager()
|
||||
|
||||
@ -145,19 +166,11 @@ class User(RESTModelMixin, PermissionsMixin, AbstractBaseUser):
|
||||
('can_see_extra_data', ugettext_noop('Can see extra data of users')),
|
||||
('can_manage', ugettext_noop('Can manage users')),
|
||||
)
|
||||
ordering = ('last_name',)
|
||||
ordering = ('last_name', 'first_name', 'username', )
|
||||
|
||||
def __str__(self):
|
||||
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):
|
||||
"""
|
||||
Returns a long form of the name.
|
||||
@ -166,7 +179,6 @@ class User(RESTModelMixin, PermissionsMixin, AbstractBaseUser):
|
||||
* Professor Dr. Enders, Christoph (Leipzig)
|
||||
"""
|
||||
structure = '(%s)' % self.structure_level if self.structure_level else ''
|
||||
|
||||
return ' '.join((self.title, self.get_short_name(), structure)).strip()
|
||||
|
||||
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
|
||||
else:
|
||||
name = first_name or last_name or self.username
|
||||
return name
|
||||
|
||||
def reset_password(self, password=None):
|
||||
"""
|
||||
Reset the password for the user to his default-password.
|
||||
"""
|
||||
if password is None:
|
||||
password = self.default_password
|
||||
self.set_password(password)
|
||||
# Return result
|
||||
return name
|
||||
|
||||
def get_view_class(self):
|
||||
"""
|
||||
|
@ -14,9 +14,8 @@ from reportlab.platypus import (
|
||||
TableStyle,
|
||||
)
|
||||
|
||||
from openslides.core.config import config
|
||||
from openslides.utils.pdf import stylesheet
|
||||
|
||||
from ..core.config import config
|
||||
from ..utils.pdf import stylesheet
|
||||
from .models import User
|
||||
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from openslides.core.exceptions import ProjectorException
|
||||
from openslides.utils.projector import ProjectorElement, ProjectorRequirement
|
||||
|
||||
from ..core.exceptions import ProjectorException
|
||||
from ..utils.projector import ProjectorElement, ProjectorRequirement
|
||||
from .models import User
|
||||
from .views import GroupViewSet, UserViewSet
|
||||
|
||||
|
@ -6,8 +6,8 @@ from .models import User
|
||||
class Index(indexes.SearchIndex, indexes.Indexable):
|
||||
text = indexes.EdgeNgramField(document=True, use_template=True)
|
||||
text = indexes.EdgeNgramField(document=True, use_template=True)
|
||||
modelfilter_name = "Users" # verbose_name of model
|
||||
modelfilter_value = "users.user" # 'app_name.model_name'
|
||||
modelfilter_name = 'Users' # verbose_name of model
|
||||
modelfilter_value = 'users.user' # 'app_name.model_name'
|
||||
|
||||
def get_model(self):
|
||||
return User
|
||||
|
@ -1,15 +1,15 @@
|
||||
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_lazy
|
||||
|
||||
from openslides.utils.rest_api import (
|
||||
from ..utils.rest_api import (
|
||||
ModelSerializer,
|
||||
PrimaryKeyRelatedField,
|
||||
RelatedField,
|
||||
ValidationError,
|
||||
)
|
||||
|
||||
from .models import Group, Permission, User
|
||||
from .models import Group, User
|
||||
|
||||
|
||||
class UserShortSerializer(ModelSerializer):
|
||||
@ -28,7 +28,8 @@ class UserShortSerializer(ModelSerializer):
|
||||
'last_name',
|
||||
'structure_level',
|
||||
'about_me',
|
||||
'groups',)
|
||||
'groups',
|
||||
)
|
||||
|
||||
|
||||
class UserFullSerializer(ModelSerializer):
|
||||
@ -58,7 +59,8 @@ class UserFullSerializer(ModelSerializer):
|
||||
'comment',
|
||||
'groups',
|
||||
'default_password',
|
||||
'is_active',)
|
||||
'is_active',
|
||||
)
|
||||
|
||||
def validate(self, data):
|
||||
"""
|
||||
@ -70,7 +72,7 @@ class UserFullSerializer(ModelSerializer):
|
||||
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
|
||||
# called in a patch-context.
|
||||
# called in a PATCH context (partial_update).
|
||||
try:
|
||||
action = self.context['view'].action
|
||||
except (KeyError, AttributeError):
|
||||
@ -84,7 +86,7 @@ class UserFullSerializer(ModelSerializer):
|
||||
|
||||
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.
|
||||
"""
|
||||
# Prepare setup password.
|
||||
@ -139,4 +141,5 @@ class GroupSerializer(ModelSerializer):
|
||||
fields = (
|
||||
'id',
|
||||
'name',
|
||||
'permissions',)
|
||||
'permissions',
|
||||
)
|
||||
|
@ -1,10 +1,10 @@
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import ugettext_lazy, ugettext_noop
|
||||
|
||||
from openslides.core.config import ConfigVariable
|
||||
|
||||
from .models import Group, Permission, User
|
||||
from ..core.config import ConfigVariable
|
||||
from .models import Group, User
|
||||
|
||||
|
||||
def setup_users_config(sender, **kwargs):
|
||||
@ -126,9 +126,10 @@ def create_builtin_groups_and_admin(**kwargs):
|
||||
'users.can_manage',
|
||||
'users.can_see_extra_data',
|
||||
'users.can_see_name', )
|
||||
permission_dict = {}
|
||||
permission_query = Q()
|
||||
permission_dict = {}
|
||||
|
||||
# Load all permissions
|
||||
for permission_string in permission_strings:
|
||||
app_label, codename = permission_string.split('.')
|
||||
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.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.
|
||||
group_staff.permissions.add(
|
||||
permission_dict['users.can_see_extra_data'],
|
||||
permission_dict['users.can_see_name'])
|
||||
|
||||
# Admin user
|
||||
# Create or reset admin user
|
||||
User.objects.create_or_reset_admin_user()
|
||||
|
@ -5,16 +5,7 @@ from . import views
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
|
||||
# PDF
|
||||
url(r'^print/$',
|
||||
views.UsersListPDF.as_view(),
|
||||
name='user_listpdf'),
|
||||
|
||||
url(r'^passwords/print/$',
|
||||
views.UsersPasswordsPDF.as_view(),
|
||||
name='user_passwordspdf'),
|
||||
|
||||
# auth
|
||||
# Auth
|
||||
url(r'^login/$',
|
||||
views.UserLoginView.as_view(),
|
||||
name='user_login'),
|
||||
@ -26,4 +17,13 @@ urlpatterns = patterns(
|
||||
url(r'^whoami/$',
|
||||
views.WhoAmIView.as_view(),
|
||||
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'),
|
||||
)
|
||||
|
@ -3,12 +3,10 @@ from django.contrib.auth import logout as auth_logout
|
||||
from django.contrib.auth.forms import AuthenticationForm
|
||||
from django.utils.translation import ugettext as _
|
||||
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 .pdf import users_passwords_to_pdf, users_to_pdf
|
||||
from .serializers import (
|
||||
@ -185,7 +183,7 @@ class GroupViewSet(ModelViewSet):
|
||||
|
||||
class UserLoginView(APIView):
|
||||
"""
|
||||
Login the user via Ajax.
|
||||
Login the user.
|
||||
"""
|
||||
http_method_names = ['post']
|
||||
|
||||
@ -208,7 +206,7 @@ class UserLoginView(APIView):
|
||||
|
||||
class UserLogoutView(APIView):
|
||||
"""
|
||||
Logout the user via Ajax.
|
||||
Logout the user.
|
||||
"""
|
||||
http_method_names = ['post']
|
||||
|
||||
@ -225,7 +223,7 @@ class WhoAmIView(APIView):
|
||||
|
||||
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.
|
||||
"""
|
||||
@ -238,11 +236,11 @@ class WhoAmIView(APIView):
|
||||
|
||||
class UsersListPDF(PDFView):
|
||||
"""
|
||||
Generate the userliste as PDF.
|
||||
Generate a list of all users as PDF.
|
||||
"""
|
||||
required_permission = 'users.can_see_extra_data'
|
||||
filename = ugettext_lazy("user-list")
|
||||
document_title = ugettext_lazy('List of Users')
|
||||
filename = ugettext_lazy('user-list')
|
||||
document_title = ugettext_lazy('List of users')
|
||||
|
||||
def append_to_pdf(self, pdf):
|
||||
"""
|
||||
@ -256,7 +254,7 @@ class UsersPasswordsPDF(PDFView):
|
||||
Generate the access data welcome paper for all users as PDF.
|
||||
"""
|
||||
required_permission = 'users.can_manage'
|
||||
filename = ugettext_lazy("User-access-data")
|
||||
filename = ugettext_lazy('user-access-data')
|
||||
top_space = 0
|
||||
|
||||
def build_document(self, pdf_document, story):
|
||||
|
@ -2,6 +2,7 @@ import re
|
||||
from collections import OrderedDict
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from rest_framework import status # noqa
|
||||
from rest_framework.decorators import detail_route, list_route # noqa
|
||||
from rest_framework.metadata import SimpleMetadata # noqa
|
||||
from rest_framework.mixins import DestroyModelMixin, UpdateModelMixin # noqa
|
||||
|
@ -1,25 +1,10 @@
|
||||
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):
|
||||
"""
|
||||
Converts an arabic number within range from 1 to 4999 to the corresponding roman number.
|
||||
Returns None on error conditions.
|
||||
Converts an arabic number within range from 1 to 4999 to the
|
||||
corresponding roman number. Returns None on error conditions.
|
||||
"""
|
||||
try:
|
||||
return roman.toRoman(number)
|
||||
|
@ -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")
|
@ -1,7 +1,7 @@
|
||||
from unittest import TestCase
|
||||
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):
|
||||
@ -98,40 +98,3 @@ class TestGetUser(TestCase):
|
||||
request._cached_user,
|
||||
'django_anonymous_user',
|
||||
"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'})
|
||||
|
@ -18,19 +18,6 @@ class UserTest(TestCase):
|
||||
'Test Value IJee1yoet1ooGhesh5li',
|
||||
"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):
|
||||
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.")
|
||||
|
||||
|
||||
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):
|
||||
def test_create_user(self):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user