Files
dashboard-cpsp-executive/backend/apps/accounts/serializers.py
T

187 lines
5.9 KiB
Python

from django.contrib.auth import get_user_model
from rest_framework import serializers
from apps.accounts.models import ApiKey
User = get_user_model()
class PkAsIdMixin(serializers.Serializer):
"""Keep JSON `id` stable after ERD-named primary keys."""
id = serializers.IntegerField(source="pk", read_only=True)
class UserSerializer(PkAsIdMixin, serializers.ModelSerializer):
managed_by = serializers.PrimaryKeyRelatedField(
queryset=User.objects.filter(status__in=["buh", "bu_admin"]),
allow_null=True,
required=False,
)
managed_by_name = serializers.CharField(
source="managed_by.display_name", read_only=True, allow_null=True
)
managed_by_pending = serializers.PrimaryKeyRelatedField(read_only=True)
managed_by_pending_name = serializers.CharField(
source="managed_by_pending.display_name", read_only=True, allow_null=True
)
class Meta:
model = User
fields = [
"id",
"user_name",
"display_name",
"status",
"is_superuser",
"managed_by",
"managed_by_name",
"managed_by_pending",
"managed_by_pending_name",
"managed_by_requested_at",
"created_at",
"updated_at",
]
read_only_fields = [
"id",
"is_superuser",
"managed_by_name",
"managed_by_pending",
"managed_by_pending_name",
"managed_by_requested_at",
"created_at",
"updated_at",
]
class UserWriteSerializer(PkAsIdMixin, serializers.ModelSerializer):
"""Create/update users for Account Admin. Password required on create."""
password = serializers.CharField(write_only=True, required=False, allow_blank=False)
managed_by = serializers.PrimaryKeyRelatedField(
queryset=User.objects.filter(status__in=["buh", "bu_admin"]),
allow_null=True,
required=False,
)
managed_by_name = serializers.CharField(
source="managed_by.display_name", read_only=True, allow_null=True
)
managed_by_pending = serializers.PrimaryKeyRelatedField(read_only=True)
managed_by_pending_name = serializers.CharField(
source="managed_by_pending.display_name", read_only=True, allow_null=True
)
class Meta:
model = User
fields = [
"id",
"user_name",
"display_name",
"status",
"is_superuser",
"password",
"managed_by",
"managed_by_name",
"managed_by_pending",
"managed_by_pending_name",
"managed_by_requested_at",
"created_at",
"updated_at",
]
read_only_fields = [
"id",
"is_superuser",
"managed_by_name",
"managed_by_pending",
"managed_by_pending_name",
"managed_by_requested_at",
"created_at",
"updated_at",
]
def validate_password(self, value: str) -> str:
if value is not None and not str(value).strip():
raise serializers.ValidationError("Password cannot be blank.")
return value
def validate(self, attrs):
if self.instance is None and not attrs.get("password"):
raise serializers.ValidationError({"password": "This field is required."})
new_status = attrs.get("status")
if new_status == User.STATUS_SUPERUSER:
raise serializers.ValidationError(
{"status": "Superuser accounts cannot be created or assigned here."}
)
request = self.context.get("request")
actor = getattr(request, "user", None) if request else None
instance = self.instance
if (
instance is not None
and actor is not None
and getattr(actor, "is_authenticated", False)
and instance.pk == actor.pk
and "status" in attrs
and attrs["status"] != instance.status
):
if attrs["status"] == User.STATUS_INACTIVE:
raise serializers.ValidationError(
{"status": "You cannot deactivate your own account."}
)
raise serializers.ValidationError(
{"status": "You cannot change your own account status."}
)
return attrs
def create(self, validated_data):
password = validated_data.pop("password")
user_name = validated_data.pop("user_name")
return User.objects.create_user(
user_name=user_name, password=password, **validated_data
)
def update(self, instance, validated_data):
password = validated_data.pop("password", None)
for attr, value in validated_data.items():
setattr(instance, attr, value)
if password:
instance.set_password(password)
instance.save()
return instance
class SetPasswordSerializer(serializers.Serializer):
password = serializers.CharField(write_only=True, allow_blank=False)
def validate_password(self, value: str) -> str:
if not str(value).strip():
raise serializers.ValidationError("Password cannot be blank.")
return value
class LoginSerializer(serializers.Serializer):
user_name = serializers.CharField(max_length=30)
password = serializers.CharField(write_only=True)
class ApiKeySerializer(serializers.ModelSerializer):
class Meta:
model = ApiKey
fields = [
"id",
"name",
"prefix",
"is_active",
"last_used_at",
"created_at",
"updated_at",
"user",
]
read_only_fields = fields
class ApiKeyCreateSerializer(serializers.Serializer):
name = serializers.CharField(max_length=100)
user_id = serializers.IntegerField(required=False)