feat(blog): expand publishing and moderation APIs
This commit is contained in:
@@ -5,17 +5,37 @@ from typing import List, Optional
|
||||
|
||||
from ninja import ModelSchema, Schema
|
||||
|
||||
from apps.blog.models import Category, Comment, PostAsset, Tag
|
||||
from apps.blog.models import BlogBanner, Category, Comment, PostAsset, Tag
|
||||
from core.media import PREVIEW_VARIANT, THUMBNAIL_VARIANT, derivative_url
|
||||
|
||||
|
||||
class CategorySchema(ModelSchema):
|
||||
created_at: Optional[datetime] = None
|
||||
parent_id: Optional[int] = None
|
||||
|
||||
class Config:
|
||||
model = Category
|
||||
model_fields = ["id", "name", "slug", "description", "created_at"]
|
||||
|
||||
@staticmethod
|
||||
def resolve_parent_id(obj):
|
||||
return obj.parent_id
|
||||
|
||||
|
||||
class CategoryPathSchema(Schema):
|
||||
id: int
|
||||
name: str
|
||||
slug: str
|
||||
|
||||
|
||||
class CategoryFilterSchema(Schema):
|
||||
id: int
|
||||
name: str
|
||||
slug: str
|
||||
parent_id: Optional[int] = None
|
||||
post_count: int = 0
|
||||
children: List["CategoryFilterSchema"] = []
|
||||
|
||||
|
||||
class TagSchema(ModelSchema):
|
||||
created_at: Optional[datetime] = None
|
||||
@@ -25,11 +45,19 @@ class TagSchema(ModelSchema):
|
||||
model_fields = ["id", "name", "slug", "created_at"]
|
||||
|
||||
|
||||
class TagFilterSchema(Schema):
|
||||
id: int
|
||||
name: str
|
||||
slug: str
|
||||
post_count: int = 0
|
||||
|
||||
|
||||
class AuthorSchema(Schema):
|
||||
id: int
|
||||
username: str
|
||||
first_name: str
|
||||
last_name: str
|
||||
bio: Optional[str] = None
|
||||
profile_picture: Optional[str] = None
|
||||
profile_picture_thumbnail_url: Optional[str] = None
|
||||
profile_picture_preview_url: Optional[str] = None
|
||||
@@ -124,6 +152,8 @@ class PostListSchema(Schema):
|
||||
status: str
|
||||
published_at: Optional[datetime] = None
|
||||
category: Optional[CategorySchema] = None
|
||||
category_path: List[CategoryPathSchema] = []
|
||||
writers: List[AuthorSchema] = []
|
||||
tags: List[TagSchema]
|
||||
is_featured: bool
|
||||
created_at: datetime
|
||||
@@ -159,6 +189,17 @@ class PostListSchema(Schema):
|
||||
url = derivative_url(obj.featured_image, PREVIEW_VARIANT)
|
||||
return request.build_absolute_uri(url) if url else None
|
||||
|
||||
@staticmethod
|
||||
def resolve_category_path(obj):
|
||||
if not obj.category_id:
|
||||
return []
|
||||
return obj.category.path
|
||||
|
||||
@staticmethod
|
||||
def resolve_writers(obj):
|
||||
writers = list(obj.writers.all())
|
||||
return writers or [obj.author]
|
||||
|
||||
@staticmethod
|
||||
def resolve_likes_count(obj):
|
||||
return getattr(obj, "likes_count", None) or obj.likes.count()
|
||||
@@ -169,7 +210,11 @@ class PostListSchema(Schema):
|
||||
|
||||
@staticmethod
|
||||
def resolve_comments_count(obj):
|
||||
return getattr(obj, "comments_count", None) or obj.comments.filter(is_approved=True).count()
|
||||
return getattr(obj, "comments_count", None) or obj.comments.filter(
|
||||
is_approved=True,
|
||||
is_hidden=False,
|
||||
is_deleted=False,
|
||||
).count()
|
||||
|
||||
|
||||
class PostDetailSchema(PostListSchema):
|
||||
@@ -192,6 +237,7 @@ class PostCreateSchema(Schema):
|
||||
excerpt: Optional[str] = None
|
||||
category_id: Optional[int] = None
|
||||
tag_ids: Optional[List[int]] = []
|
||||
writer_ids: Optional[List[int]] = None
|
||||
status: str = "draft"
|
||||
is_featured: bool = False
|
||||
seo_title: Optional[str] = ""
|
||||
@@ -221,10 +267,14 @@ class CommentSchema(ModelSchema):
|
||||
post_title: str
|
||||
post_slug: str
|
||||
parent_id: Optional[int] = None
|
||||
is_hidden: bool = False
|
||||
is_deleted: bool = False
|
||||
deleted_at: Optional[datetime] = None
|
||||
hidden_replies_count: int = 0
|
||||
|
||||
class Config:
|
||||
model = Comment
|
||||
model_fields = ["id", "content", "created_at", "is_approved", "hidden_at"]
|
||||
model_fields = ["id", "content", "created_at", "updated_at", "is_approved", "hidden_at"]
|
||||
|
||||
@staticmethod
|
||||
def resolve_post_id(obj):
|
||||
@@ -242,12 +292,22 @@ class CommentSchema(ModelSchema):
|
||||
def resolve_parent_id(obj):
|
||||
return obj.parent_id
|
||||
|
||||
@staticmethod
|
||||
def resolve_hidden_replies_count(obj):
|
||||
if not getattr(obj, "replies", None):
|
||||
return 0
|
||||
return sum(len(reply.replies.all()) for reply in obj.replies.all())
|
||||
|
||||
|
||||
class CommentCreateSchema(Schema):
|
||||
content: str
|
||||
parent_id: Optional[int] = None
|
||||
|
||||
|
||||
class CommentUpdateSchema(Schema):
|
||||
content: str
|
||||
|
||||
|
||||
class CommentHideSchema(Schema):
|
||||
note: Optional[str] = ""
|
||||
|
||||
@@ -265,3 +325,30 @@ class BlogProfileActivitySchema(Schema):
|
||||
saved_posts: List[PostListSchema]
|
||||
comments: List[CommentSchema]
|
||||
replies: List[CommentSchema]
|
||||
|
||||
|
||||
class BlogBannerSchema(ModelSchema):
|
||||
image_url: str
|
||||
|
||||
class Config:
|
||||
model = BlogBanner
|
||||
model_fields = ["id", "title", "alt_text", "url", "sort_order"]
|
||||
|
||||
@staticmethod
|
||||
def resolve_image_url(obj, context):
|
||||
request = context["request"]
|
||||
return request.build_absolute_uri(obj.image.url) if obj.image else ""
|
||||
|
||||
|
||||
class BlogFilterAuthorSchema(Schema):
|
||||
id: int
|
||||
username: str
|
||||
first_name: str
|
||||
last_name: str
|
||||
post_count: int = 0
|
||||
|
||||
|
||||
class BlogFiltersSchema(Schema):
|
||||
categories: List[CategoryFilterSchema]
|
||||
tags: List[TagFilterSchema]
|
||||
authors: List[BlogFilterAuthorSchema]
|
||||
|
||||
Reference in New Issue
Block a user