serializers.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. from django.urls import reverse
  2. from rest_framework import serializers
  3. from ..core.serializers import MutableFields
  4. from ..core.utils import format_plaintext_for_html
  5. from .models import Category
  6. __all__ = ["CategorySerializer"]
  7. def last_activity_detail(f):
  8. """util for serializing last activity details"""
  9. def decorator(self, obj):
  10. if not obj.last_thread_id:
  11. return None
  12. acl = self.get_acl(obj)
  13. tested_acls = (
  14. acl.get("can_see"),
  15. acl.get("can_browse"),
  16. acl.get("can_see_all_threads"),
  17. )
  18. if not all(tested_acls):
  19. return None
  20. return f(self, obj)
  21. return decorator
  22. class CategorySerializer(serializers.ModelSerializer, MutableFields):
  23. parent = serializers.PrimaryKeyRelatedField(read_only=True)
  24. description = serializers.SerializerMethodField()
  25. is_read = serializers.SerializerMethodField()
  26. subcategories = serializers.SerializerMethodField()
  27. acl = serializers.SerializerMethodField()
  28. url = serializers.SerializerMethodField()
  29. class Meta:
  30. model = Category
  31. fields = [
  32. "id",
  33. "parent",
  34. "name",
  35. "short_name",
  36. "color",
  37. "description",
  38. "is_closed",
  39. "threads",
  40. "posts",
  41. "last_post_on",
  42. "last_thread_title",
  43. "last_poster",
  44. "last_poster_name",
  45. "css_class",
  46. "is_read",
  47. "subcategories",
  48. "acl",
  49. "level",
  50. "lft",
  51. "rght",
  52. "url",
  53. ]
  54. def to_representation(self, instance):
  55. data = super().to_representation(instance)
  56. if instance.special_role:
  57. data["special_role"] = instance.special_role
  58. return data
  59. def get_description(self, obj):
  60. if obj.description:
  61. return {
  62. "plain": obj.description,
  63. "html": format_plaintext_for_html(obj.description),
  64. }
  65. # Serve root category's description
  66. if obj.special_role == "root_category" and self.context:
  67. settings = self.context.settings
  68. if settings.index_message:
  69. return {
  70. "plain": settings.index_message,
  71. "html": format_plaintext_for_html(settings.index_message),
  72. }
  73. def get_css_class(self, obj):
  74. return obj.css_class or None
  75. def get_is_read(self, obj):
  76. try:
  77. return obj.is_read
  78. except AttributeError:
  79. return None
  80. def get_subcategories(self, obj):
  81. try:
  82. return CategorySerializer(
  83. obj.subcategories, context=self.context, many=True
  84. ).data
  85. except AttributeError:
  86. return []
  87. def get_acl(self, obj):
  88. try:
  89. return obj.acl
  90. except AttributeError:
  91. return {}
  92. @last_activity_detail
  93. def get_last_poster(self, obj):
  94. if obj.last_poster_id:
  95. return {
  96. "id": obj.last_poster_id,
  97. "avatars": obj.last_poster.avatars,
  98. "url": reverse(
  99. "misago:user",
  100. kwargs={"slug": obj.last_poster_slug, "pk": obj.last_poster_id},
  101. ),
  102. }
  103. def get_url(self, obj):
  104. return {
  105. "index": obj.get_absolute_url(),
  106. "last_thread": self.get_last_thread_url(obj),
  107. "last_thread_new": self.get_last_thread_new_url(obj),
  108. "last_post": self.get_last_post_url(obj),
  109. }
  110. @last_activity_detail
  111. def get_last_thread_url(self, obj):
  112. return obj.get_last_thread_url()
  113. @last_activity_detail
  114. def get_last_thread_new_url(self, obj):
  115. return obj.get_last_thread_new_url()
  116. @last_activity_detail
  117. def get_last_post_url(self, obj):
  118. return obj.get_last_post_url()
  119. class CategoryWithPosterSerializer(CategorySerializer):
  120. last_poster = serializers.SerializerMethodField()
  121. def get_subcategories(self, obj):
  122. try:
  123. return CategoryWithPosterSerializer(obj.subcategories, many=True).data
  124. except AttributeError:
  125. return []
  126. CategoryWithPosterSerializer = CategoryWithPosterSerializer.extend_fields("last_poster")