from typing import TYPE_CHECKING from rest_framework import serializers from rest_framework.exceptions import PermissionDenied from outbo.apps.photobriefing.enums import ChoiceRole from outbo.apps.photobriefing.models import Brief, BriefItemChoice from outbo.apps.photobriefing.rules import can_complete_brief, can_publish_brief from outbo.apps.photobriefing.serializers import ( BriefItemSerializer, BriefItemChoiceSerializer, ) if TYPE_CHECKING: from outbo.apps.authentication.models import User class BaseBriefSerializer(serializers.ModelSerializer): class Meta: model = Brief def get_editable(self, instance: Brief): current_user = self.context["request"].user return instance.editable_for_user(user=current_user) def get_acceptable(self, instance: Brief): current_user = self.context["request"].user return instance.acceptable_for_user(user=current_user) def get_publishable(self, instance: Brief): current_user = self.context["request"].user return instance.publishable_for_user(user=current_user) def get_completable(self, instance: Brief): current_user = self.context["request"].user return instance.completable_for_user(user=current_user) class BriefSerializer: class Retrieve(BaseBriefSerializer): items = BriefItemSerializer.List(many=True) choices = BriefItemChoiceSerializer.List(many=True) editable = serializers.SerializerMethodField() acceptable = serializers.SerializerMethodField() publishable = serializers.SerializerMethodField() completable = serializers.SerializerMethodField() class Meta(BaseBriefSerializer.Meta): fields = [ "stage", "session_date", "concept_description", "items", "choices", "created_at", "updated_at", "editable", "acceptable", "publishable", "completable", ] class Update(BaseBriefSerializer): publish = serializers.BooleanField() complete = serializers.BooleanField() choice = BriefItemChoiceSerializer.Update(partial=False) items = BriefItemSerializer.Create(many=True) class Meta(BaseBriefSerializer.Meta): fields = [ "session_date", "concept_description", "items", "choice", "publish", "complete", ] def update(self, instance, validated_data): if validated_data.get("choice", None) is not None: serializer = BriefSerializer.ChoiceUpdate(context=self.context) return serializer.update(instance, {"choice": validated_data["choice"]}) if validated_data.get("publish", None) is not None: serializer = BriefSerializer.Publish(context=self.context) return serializer.update( instance, {"publish": validated_data["publish"]} ) if validated_data.get("complete", None) is not None: serializer = BriefSerializer.Complete(context=self.context) return serializer.update( instance, {"complete": validated_data["complete"]} ) items = validated_data.pop("items", None) if items: for item in items: item["brief"] = instance BriefItemSerializer.Create(context=self.context).create(item) return super().update(instance=instance, validated_data=validated_data) class Publish(BaseBriefSerializer): publish = serializers.BooleanField() class Meta(BaseBriefSerializer.Meta): fields = ["publish"] def update(self, instance, validated_data): publish = validated_data["publish"] current_user = self.context["request"].user if not can_publish_brief.test(current_user, instance): raise PermissionDenied() if publish: instance.publish_as_user(user=current_user) instance.save() return instance class Complete(BaseBriefSerializer): complete = serializers.BooleanField() class Meta(BaseBriefSerializer.Meta): fields = ["complete"] def update(self, instance: Brief, validated_data): complete = validated_data["complete"] current_user = self.context["request"].user if not can_complete_brief.test(current_user, instance): raise PermissionDenied() if complete: instance.complete_as_user(user=current_user) instance.save() return instance class ChoiceUpdate(BaseBriefSerializer): choice = BriefItemChoiceSerializer.Update() class Meta(BaseBriefSerializer.Meta): fields = ["choice"] def update(self, instance, validated_data): choice = validated_data["choice"] current_user: "User" = self.context["request"].user if current_user.is_supplier: role = ChoiceRole.SUPPLIER elif current_user.is_client: role = ChoiceRole.CLIENT else: raise NotImplemented current_choice, _ = BriefItemChoice.objects.get_or_create( defaults={"item": choice["item"]}, brief=instance, category=choice["category"], role=role, ) if current_choice.item != choice["item"]: current_choice.item = choice["item"] current_choice.save() return instance