2024-04-17 11:19:22 +02:00
|
|
|
"""Client serializers for People's mailbox manager app."""
|
2024-04-16 17:06:43 +02:00
|
|
|
|
2024-09-20 18:08:02 +02:00
|
|
|
import json
|
|
|
|
|
|
2024-09-27 15:54:44 +02:00
|
|
|
from rest_framework import exceptions, serializers
|
2024-04-16 17:06:43 +02:00
|
|
|
|
2024-11-25 14:44:34 +01:00
|
|
|
from core.api.client.serializers import UserSerializer
|
2024-09-25 00:43:02 +02:00
|
|
|
from core.models import User
|
2024-09-14 00:59:38 +02:00
|
|
|
|
2024-09-25 00:43:02 +02:00
|
|
|
from mailbox_manager import enums, models
|
2024-09-19 18:47:08 +02:00
|
|
|
from mailbox_manager.utils.dimail import DimailAPIClient
|
2024-04-16 17:06:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class MailboxSerializer(serializers.ModelSerializer):
|
|
|
|
|
"""Serialize mailbox."""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
model = models.Mailbox
|
2024-11-15 18:14:10 +01:00
|
|
|
fields = [
|
|
|
|
|
"id",
|
|
|
|
|
"first_name",
|
|
|
|
|
"last_name",
|
|
|
|
|
"local_part",
|
|
|
|
|
"secondary_email",
|
|
|
|
|
"status",
|
|
|
|
|
]
|
2024-08-05 12:20:44 +02:00
|
|
|
# everything is actually read-only as we do not allow update for now
|
2024-11-15 18:14:10 +01:00
|
|
|
read_only_fields = ["id", "status"]
|
2024-04-16 17:06:43 +02:00
|
|
|
|
2024-09-19 18:47:08 +02:00
|
|
|
def create(self, validated_data):
|
|
|
|
|
"""
|
|
|
|
|
Override create function to fire a request on mailbox creation.
|
|
|
|
|
"""
|
2024-11-15 18:14:10 +01:00
|
|
|
mailbox_status = enums.MailDomainStatusChoices.PENDING
|
2024-09-20 18:08:02 +02:00
|
|
|
|
2024-11-15 18:14:10 +01:00
|
|
|
if validated_data["domain"].status == enums.MailDomainStatusChoices.ENABLED:
|
|
|
|
|
client = DimailAPIClient()
|
|
|
|
|
# send new mailbox request to dimail
|
|
|
|
|
response = client.send_mailbox_request(
|
|
|
|
|
validated_data, self.context["request"].user.sub
|
|
|
|
|
)
|
2024-09-20 18:08:02 +02:00
|
|
|
|
2024-11-15 18:14:10 +01:00
|
|
|
# fix format to have actual json, and remove uuid
|
|
|
|
|
mailbox_data = json.loads(
|
|
|
|
|
response.content.decode("utf-8").replace("'", '"')
|
|
|
|
|
)
|
|
|
|
|
del mailbox_data["uuid"]
|
|
|
|
|
|
|
|
|
|
mailbox_status = enums.MailDomainStatusChoices.ENABLED
|
2024-09-20 18:08:02 +02:00
|
|
|
|
2024-11-15 18:14:10 +01:00
|
|
|
# send confirmation email
|
|
|
|
|
client.send_new_mailbox_notification(
|
|
|
|
|
recipient=validated_data["secondary_email"], mailbox_data=mailbox_data
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# actually save mailbox on our database
|
|
|
|
|
return models.Mailbox.objects.create(**validated_data, status=mailbox_status)
|
2024-09-19 18:47:08 +02:00
|
|
|
|
2024-04-16 17:06:43 +02:00
|
|
|
|
|
|
|
|
class MailDomainSerializer(serializers.ModelSerializer):
|
|
|
|
|
"""Serialize mail domain."""
|
|
|
|
|
|
2024-08-06 00:04:51 +02:00
|
|
|
abilities = serializers.SerializerMethodField(read_only=True)
|
|
|
|
|
|
2024-04-16 17:06:43 +02:00
|
|
|
class Meta:
|
|
|
|
|
model = models.MailDomain
|
2024-06-03 16:59:55 +02:00
|
|
|
lookup_field = "slug"
|
2024-04-17 11:19:22 +02:00
|
|
|
fields = [
|
|
|
|
|
"id",
|
|
|
|
|
"name",
|
2024-06-18 15:10:15 +02:00
|
|
|
"slug",
|
2024-08-08 15:55:16 +02:00
|
|
|
"status",
|
2024-08-06 00:04:51 +02:00
|
|
|
"abilities",
|
2024-04-17 11:19:22 +02:00
|
|
|
"created_at",
|
|
|
|
|
"updated_at",
|
|
|
|
|
]
|
2024-06-19 16:48:07 +02:00
|
|
|
read_only_fields = [
|
|
|
|
|
"id",
|
|
|
|
|
"slug",
|
2024-08-08 15:55:16 +02:00
|
|
|
"status",
|
2024-08-06 00:04:51 +02:00
|
|
|
"abilities",
|
2024-06-19 16:48:07 +02:00
|
|
|
"created_at",
|
|
|
|
|
"updated_at",
|
|
|
|
|
]
|
2024-04-17 11:19:22 +02:00
|
|
|
|
2024-08-06 00:04:51 +02:00
|
|
|
def get_abilities(self, domain) -> dict:
|
|
|
|
|
"""Return abilities of the logged-in user on the instance."""
|
|
|
|
|
request = self.context.get("request")
|
|
|
|
|
if request:
|
|
|
|
|
return domain.get_abilities(request.user)
|
|
|
|
|
return {}
|
|
|
|
|
|
2024-10-23 18:44:14 +02:00
|
|
|
def create(self, validated_data):
|
|
|
|
|
"""
|
|
|
|
|
Override create function to fire a request to dimail upon domain creation.
|
|
|
|
|
"""
|
|
|
|
|
# send new domain request to dimail
|
|
|
|
|
client = DimailAPIClient()
|
|
|
|
|
client.send_domain_creation_request(
|
|
|
|
|
validated_data["name"], self.context["request"].user.sub
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# no exception raised ? Then actually save domain on our database
|
|
|
|
|
return models.MailDomain.objects.create(**validated_data)
|
|
|
|
|
|
2024-04-17 11:19:22 +02:00
|
|
|
|
|
|
|
|
class MailDomainAccessSerializer(serializers.ModelSerializer):
|
2024-09-14 00:59:38 +02:00
|
|
|
"""Serialize mail domain access."""
|
|
|
|
|
|
|
|
|
|
user = UserSerializer(read_only=True, fields=["id", "name", "email"])
|
|
|
|
|
can_set_role_to = serializers.SerializerMethodField(read_only=True)
|
2024-04-17 11:19:22 +02:00
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
model = models.MailDomainAccess
|
2024-09-25 00:43:02 +02:00
|
|
|
fields = ["id", "user", "role", "can_set_role_to"]
|
|
|
|
|
read_only_fields = ["id", "can_set_role_to"]
|
|
|
|
|
|
|
|
|
|
def update(self, instance, validated_data):
|
|
|
|
|
"""Make "user" field is readonly but only on update."""
|
|
|
|
|
validated_data.pop("user", None)
|
|
|
|
|
return super().update(instance, validated_data)
|
2024-09-14 00:59:38 +02:00
|
|
|
|
|
|
|
|
def get_can_set_role_to(self, access):
|
2024-09-27 15:54:44 +02:00
|
|
|
"""Return roles available to set for the authenticated user"""
|
|
|
|
|
return access.get_can_set_role_to(self.context.get("request").user)
|
|
|
|
|
|
|
|
|
|
def validate(self, attrs):
|
|
|
|
|
"""
|
2024-09-25 00:43:02 +02:00
|
|
|
Check access rights specific to writing (update/create)
|
2024-09-27 15:54:44 +02:00
|
|
|
"""
|
2024-09-25 00:43:02 +02:00
|
|
|
|
2024-09-27 15:54:44 +02:00
|
|
|
request = self.context.get("request")
|
|
|
|
|
authenticated_user = getattr(request, "user", None)
|
|
|
|
|
role = attrs.get("role")
|
|
|
|
|
|
|
|
|
|
# Update
|
|
|
|
|
if self.instance:
|
|
|
|
|
can_set_role_to = self.instance.get_can_set_role_to(authenticated_user)
|
|
|
|
|
|
|
|
|
|
if role and role not in can_set_role_to:
|
|
|
|
|
message = (
|
|
|
|
|
f"You are only allowed to set role to {', '.join(can_set_role_to)}"
|
|
|
|
|
if can_set_role_to
|
|
|
|
|
else "You are not allowed to modify role for this user."
|
|
|
|
|
)
|
|
|
|
|
raise exceptions.PermissionDenied(message)
|
2024-09-25 00:43:02 +02:00
|
|
|
# Create
|
|
|
|
|
else:
|
|
|
|
|
# A domain slug has to be set to create a new access
|
|
|
|
|
try:
|
|
|
|
|
domain_slug = self.context["domain_slug"]
|
|
|
|
|
except KeyError as exc:
|
|
|
|
|
raise exceptions.ValidationError(
|
|
|
|
|
"You must set a domain slug in kwargs to create a new domain access."
|
|
|
|
|
) from exc
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
access = authenticated_user.mail_domain_accesses.get(
|
|
|
|
|
domain__slug=domain_slug
|
|
|
|
|
)
|
|
|
|
|
except models.MailDomainAccess.DoesNotExist as exc:
|
|
|
|
|
raise exceptions.PermissionDenied(
|
|
|
|
|
"You are not allowed to manage accesses for this domain."
|
|
|
|
|
) from exc
|
|
|
|
|
|
|
|
|
|
# Authenticated user must be owner or admin of current domain to set new roles
|
|
|
|
|
if access.role not in [
|
|
|
|
|
enums.MailDomainRoleChoices.OWNER,
|
|
|
|
|
enums.MailDomainRoleChoices.ADMIN,
|
|
|
|
|
]:
|
|
|
|
|
raise exceptions.PermissionDenied(
|
|
|
|
|
"You are not allowed to manage accesses for this domain."
|
|
|
|
|
)
|
|
|
|
|
# only an owner can set an owner role to another user
|
|
|
|
|
if (
|
|
|
|
|
role == enums.MailDomainRoleChoices.OWNER
|
|
|
|
|
and access.role != enums.MailDomainRoleChoices.OWNER
|
|
|
|
|
):
|
|
|
|
|
raise exceptions.PermissionDenied(
|
|
|
|
|
"Only owners of a domain can assign other users as owners."
|
|
|
|
|
)
|
|
|
|
|
attrs["user"] = User.objects.get(pk=self.initial_data["user"])
|
|
|
|
|
attrs["domain"] = models.MailDomain.objects.get(
|
|
|
|
|
slug=self.context["domain_slug"]
|
|
|
|
|
)
|
2024-09-27 15:54:44 +02:00
|
|
|
return attrs
|
2024-09-14 00:59:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class MailDomainAccessReadOnlySerializer(MailDomainAccessSerializer):
|
|
|
|
|
"""Serialize mail domain access for list and retrieve actions."""
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
model = models.MailDomainAccess
|
|
|
|
|
fields = [
|
|
|
|
|
"id",
|
|
|
|
|
"user",
|
|
|
|
|
"role",
|
|
|
|
|
"can_set_role_to",
|
|
|
|
|
]
|
|
|
|
|
read_only_fields = [
|
|
|
|
|
"id",
|
|
|
|
|
"user",
|
|
|
|
|
"role",
|
|
|
|
|
"can_set_role_to",
|
2024-04-17 11:19:22 +02:00
|
|
|
]
|