dd4754d045
Before this commit, there where two different locks when updating the restricted data cache. A future lock, what is faster but only works in the same thread. The other lock is in redis, it is not so fast, but also works in many threads. The future lock was buggy, because on a second call of update_restricted_data the same future was reused. So on the second run, the future was already done. I don't see any way to delete. The last client would have to delete it, but there is no way to find out which client the last one is.
181 lines
5.2 KiB
Python
181 lines
5.2 KiB
Python
from django.contrib.auth.hashers import make_password
|
|
from django.contrib.auth.models import Permission
|
|
|
|
from .models import Group, PersonalNote, User
|
|
from ..utils.autoupdate import inform_changed_data
|
|
from ..utils.rest_api import (
|
|
IdPrimaryKeyRelatedField,
|
|
JSONField,
|
|
ModelSerializer,
|
|
RelatedField,
|
|
ValidationError,
|
|
)
|
|
|
|
|
|
USERCANSEESERIALIZER_FIELDS = (
|
|
"id",
|
|
"username",
|
|
"title",
|
|
"first_name",
|
|
"last_name",
|
|
"structure_level",
|
|
"number",
|
|
"about_me",
|
|
"groups",
|
|
"is_present",
|
|
"is_committee",
|
|
)
|
|
|
|
|
|
USERCANSEEEXTRASERIALIZER_FIELDS = USERCANSEESERIALIZER_FIELDS + (
|
|
"gender",
|
|
"email",
|
|
"last_email_send",
|
|
"comment",
|
|
"is_active",
|
|
)
|
|
|
|
|
|
class UserFullSerializer(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",)
|
|
|
|
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", "")
|
|
)
|
|
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.generate_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())
|
|
|
|
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",)
|