serializers.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. from rest_framework import serializers
  2. from django.urls import reverse
  3. from misago.api.serializers import MutableFields
  4. from misago.core.utils import format_plaintext_for_html
  5. from .models import Category
  6. __all__ = [
  7. 'CategorySerializer',
  8. 'BasicCategorySerializer',
  9. 'CategoryWithPosterSerializer',
  10. ]
  11. def last_activity_detail(f):
  12. """util for serializing last activity details"""
  13. def decorator(self, obj):
  14. if not obj.last_thread_id:
  15. return None
  16. acl = self.get_acl(obj)
  17. tested_acls = (acl.get('can_see'), acl.get('can_browse'), acl.get('can_see_all_threads'), )
  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. 'description',
  36. 'is_closed',
  37. 'threads',
  38. 'posts',
  39. 'last_post_on',
  40. 'last_thread_title',
  41. 'last_poster',
  42. 'last_poster_name',
  43. 'css_class',
  44. 'is_read',
  45. 'subcategories',
  46. 'acl',
  47. 'level',
  48. 'lft',
  49. 'rght',
  50. 'url',
  51. ]
  52. def get_description(self, obj):
  53. if obj.description:
  54. return {
  55. 'plain': obj.description,
  56. 'html': format_plaintext_for_html(obj.description),
  57. }
  58. return None
  59. def get_is_read(self, obj):
  60. try:
  61. return obj.is_read
  62. except AttributeError:
  63. return None
  64. def get_subcategories(self, obj):
  65. try:
  66. return CategorySerializer(obj.subcategories, many=True).data
  67. except AttributeError:
  68. return []
  69. def get_acl(self, obj):
  70. try:
  71. return obj.acl
  72. except AttributeError:
  73. return {}
  74. @last_activity_detail
  75. def get_last_poster(self, obj):
  76. if obj.last_poster_id:
  77. return {
  78. 'id': obj.last_poster_id,
  79. 'avatars': obj.last_poster.avatars,
  80. 'url': reverse(
  81. 'misago:user', kwargs={
  82. 'slug': obj.last_poster_slug,
  83. 'pk': obj.last_poster_id,
  84. }
  85. )
  86. }
  87. return None
  88. def get_url(self, obj):
  89. return {
  90. 'index': obj.get_absolute_url(),
  91. 'last_thread': self.get_last_thread_url(obj),
  92. 'last_thread_new': self.get_last_thread_new_url(obj),
  93. 'last_post': self.get_last_post_url(obj),
  94. }
  95. @last_activity_detail
  96. def get_last_thread_url(self, obj):
  97. return obj.get_last_thread_url()
  98. @last_activity_detail
  99. def get_last_thread_new_url(self, obj):
  100. return obj.get_last_thread_new_url()
  101. @last_activity_detail
  102. def get_last_post_url(self, obj):
  103. return obj.get_last_post_url()
  104. class CategoryWithPosterSerializer(CategorySerializer):
  105. last_poster = serializers.SerializerMethodField()
  106. def get_subcategories(self, obj):
  107. try:
  108. return CategoryWithPosterSerializer(obj.subcategories, many=True).data
  109. except AttributeError:
  110. return []
  111. CategoryWithPosterSerializer = CategoryWithPosterSerializer.extend_fields('last_poster')
  112. BasicCategorySerializer = CategorySerializer.subset_fields(
  113. 'id', 'parent', 'name', 'description', 'is_closed', 'css_class',
  114. 'level', 'lft', 'rght', 'url'
  115. )