OpenSlides/openslides/users/serializers.py
2020-04-07 07:27:54 +02:00

191 lines
5.4 KiB
Python

from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import Permission
from ..utils.autoupdate import inform_changed_data
from ..utils.rest_api import (
IdPrimaryKeyRelatedField,
JSONField,
ModelSerializer,
RelatedField,
ValidationError,
)
from ..utils.validate import validate_html
from .models import Group, PersonalNote, User
USERCANSEESERIALIZER_FIELDS = (
"id",
"username",
"title",
"first_name",
"last_name",
"structure_level",
"number",
"about_me",
"groups",
"is_present",
"is_committee",
"vote_weight",
)
USERCANSEEEXTRASERIALIZER_FIELDS = USERCANSEESERIALIZER_FIELDS + (
"gender",
"email",
"last_email_send",
"comment",
"is_active",
"auth_type",
)
class UserSerializer(ModelSerializer):
"""
Serializer for users.models.User objects.
Serializes all relevant fields for manager.
"""
groups = IdPrimaryKeyRelatedField(
many=True,
required=False,
queryset=Group.objects.exclude(pk=1),
help_text=(
"The groups this user belongs to. A user will "
"get all permissions granted to each of "
"his/her groups."
),
)
class Meta:
model = User
fields = USERCANSEEEXTRASERIALIZER_FIELDS + (
"default_password",
"session_auth_hash",
)
read_only_fields = ("last_email_send", "auth_type")
def validate(self, data):
"""
Checks if the given data is empty. Generates the
username if it is empty.
"""
try:
action = self.context["view"].action
except (KeyError, AttributeError):
action = None
# Check if we are in Patch context, if not, check if we have the mandatory fields
if action != "partial_update":
if not (
data.get("username") or data.get("first_name") or data.get("last_name")
):
raise ValidationError(
{"detail": "Username, given name and surname can not all be empty."}
)
# Generate username. But only if it is not set and the serializer is not
# called in a PATCH context (partial_update).
if not data.get("username") and action != "partial_update":
data["username"] = User.objects.generate_username(
data.get("first_name", ""), data.get("last_name", "")
)
# check the about_me html
if "about_me" in data:
data["about_me"] = validate_html(data["about_me"])
return data
def prepare_password(self, validated_data):
"""
Sets the default password.
"""
# Prepare setup password.
if not validated_data.get("default_password"):
validated_data["default_password"] = User.objects.make_random_password()
validated_data["password"] = make_password(validated_data["default_password"])
return validated_data
def create(self, validated_data):
"""
Creates the user.
"""
# Perform creation in the database and return new user.
user = super().create(self.prepare_password(validated_data))
# TODO: This autoupdate call is redundant (required by issue #2727). See #2736.
inform_changed_data(user)
return user
class PermissionRelatedField(RelatedField):
"""
A custom field to use for the permission relationship.
"""
default_error_messages = {
"incorrect_value": 'Incorrect value "{value}". Expected app_label.codename string.',
"does_not_exist": 'Invalid permission "{value}". Object does not exist.',
}
def to_representation(self, value):
"""
Returns the permission code string (app_label.codename).
"""
return ".".join((value.content_type.app_label, value.codename))
def to_internal_value(self, data):
"""
Returns the permission object represented by data. The argument data is
what is sent by the client. This method expects permission code strings
(app_label.codename) like to_representation() returns.
"""
try:
app_label, codename = data.split(".")
except ValueError:
self.fail("incorrect_value", value=data)
try:
permission = Permission.objects.get(
content_type__app_label=app_label, codename=codename
)
except Permission.DoesNotExist:
self.fail("does_not_exist", value=data)
return permission
class GroupSerializer(ModelSerializer):
"""
Serializer for django.contrib.auth.models.Group objects.
"""
permissions = PermissionRelatedField(
many=True, queryset=Permission.objects.all(), required=False
)
class Meta:
model = Group
fields = ("id", "name", "permissions")
def update(self, *args, **kwargs):
"""
Customized update method. We just refresh the instance from the
database because of an unknown bug in Django REST framework.
"""
instance = super().update(*args, **kwargs)
return Group.objects.get(pk=instance.pk)
class PersonalNoteSerializer(ModelSerializer):
"""
Serializer for users.models.PersonalNote objects.
"""
notes = JSONField()
class Meta:
model = PersonalNote
fields = ("id", "user", "notes")
read_only_fields = ("user",)