from django.urls import reverse from rest_framework import serializers from ..core.serializers import MutableFields from ..core.utils import format_plaintext_for_html from .models import Category __all__ = ["CategorySerializer"] def last_activity_detail(f): """util for serializing last activity details""" def decorator(self, obj): if not obj.last_thread_id: return None acl = self.get_acl(obj) tested_acls = ( acl.get("can_see"), acl.get("can_browse"), acl.get("can_see_all_threads"), ) if not all(tested_acls): return None return f(self, obj) return decorator class CategorySerializer(serializers.ModelSerializer, MutableFields): parent = serializers.PrimaryKeyRelatedField(read_only=True) description = serializers.SerializerMethodField() is_read = serializers.SerializerMethodField() subcategories = serializers.SerializerMethodField() acl = serializers.SerializerMethodField() url = serializers.SerializerMethodField() class Meta: model = Category fields = [ "id", "parent", "name", "short_name", "color", "description", "is_closed", "threads", "posts", "last_post_on", "last_thread_title", "last_poster", "last_poster_name", "css_class", "is_read", "subcategories", "acl", "level", "lft", "rght", "url", ] def to_representation(self, instance): data = super().to_representation(instance) if instance.special_role: data["special_role"] = instance.special_role return data def get_description(self, obj): if obj.description: return { "plain": obj.description, "html": format_plaintext_for_html(obj.description), } # Serve root category's description if obj.special_role == "root_category" and self.context: settings = self.context.settings if settings.index_message: return { "plain": settings.index_message, "html": format_plaintext_for_html(settings.index_message), } def get_css_class(self, obj): return obj.css_class or None def get_is_read(self, obj): try: return obj.is_read except AttributeError: return None def get_subcategories(self, obj): try: return CategorySerializer( obj.subcategories, context=self.context, many=True ).data except AttributeError: return [] def get_acl(self, obj): try: return obj.acl except AttributeError: return {} @last_activity_detail def get_last_poster(self, obj): if obj.last_poster_id: return { "id": obj.last_poster_id, "avatars": obj.last_poster.avatars, "url": reverse( "misago:user", kwargs={"slug": obj.last_poster_slug, "pk": obj.last_poster_id}, ), } def get_url(self, obj): return { "index": obj.get_absolute_url(), "last_thread": self.get_last_thread_url(obj), "last_thread_new": self.get_last_thread_new_url(obj), "last_post": self.get_last_post_url(obj), } @last_activity_detail def get_last_thread_url(self, obj): return obj.get_last_thread_url() @last_activity_detail def get_last_thread_new_url(self, obj): return obj.get_last_thread_new_url() @last_activity_detail def get_last_post_url(self, obj): return obj.get_last_post_url() class CategoryWithPosterSerializer(CategorySerializer): last_poster = serializers.SerializerMethodField() def get_subcategories(self, obj): try: return CategoryWithPosterSerializer(obj.subcategories, many=True).data except AttributeError: return [] CategoryWithPosterSerializer = CategoryWithPosterSerializer.extend_fields("last_poster")