You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
5.6 KiB
154 lines
5.6 KiB
from django.contrib import admin
|
|
from django.utils.translation import gettext_lazy as _
|
|
from unfold.admin import ModelAdmin, StackedInline, TabularInline
|
|
from unfold.decorators import display, action
|
|
|
|
from apps.cms.models.post import (
|
|
PostCategory,
|
|
PostTag,
|
|
Post,
|
|
PostComment,
|
|
PostLike,
|
|
MediaAsset,
|
|
)
|
|
from utils.admin import project_admin_site
|
|
|
|
|
|
class PostCommentInline(TabularInline):
|
|
model = PostComment
|
|
extra = 0
|
|
fields = ('author_name', 'author_email', 'user', 'content', 'status', 'created_at')
|
|
readonly_fields = ('created_at',)
|
|
|
|
|
|
@admin.register(Post, site=project_admin_site)
|
|
class PostAdmin(ModelAdmin):
|
|
list_display = (
|
|
'title',
|
|
'post_type_badge',
|
|
'language',
|
|
'category',
|
|
'status_badge',
|
|
'author',
|
|
'views_count',
|
|
'likes_count',
|
|
'is_featured',
|
|
'publish_date',
|
|
)
|
|
list_display_links = ('title', 'post_type_badge', 'category', 'author')
|
|
list_filter = ('post_type', 'language', 'status', 'is_featured', 'category')
|
|
search_fields = ('title', 'excerpt', 'content', 'author__email', 'author__fullname')
|
|
prepopulated_fields = {'slug': ('title',)}
|
|
readonly_fields = ('reading_time_minutes', 'views_count', 'likes_count', 'created_at', 'updated_at')
|
|
inlines = [PostCommentInline]
|
|
actions = ['publish_posts', 'archive_posts', 'toggle_featured']
|
|
|
|
fieldsets = (
|
|
(_('Article Content'), {
|
|
'fields': ('title', 'slug', 'post_type', 'category', 'language', 'status', 'is_featured')
|
|
}),
|
|
(_('Author & Affiliation'), {
|
|
'fields': ('author', 'institution', 'author_role_label', 'author_custom_avatar')
|
|
}),
|
|
(_('Media & Excerpt'), {
|
|
'fields': ('featured_image', 'excerpt', 'content', 'tags')
|
|
}),
|
|
(_('Metrics & Scheduling'), {
|
|
'fields': ('reading_time_minutes', 'views_count', 'likes_count', 'publish_date', 'created_at', 'updated_at')
|
|
}),
|
|
)
|
|
|
|
@display(description=_('Type'))
|
|
def post_type_badge(self, obj):
|
|
return obj.get_post_type_display()
|
|
|
|
@display(description=_('Status'), label={
|
|
Post.Status.PUBLISHED: "success",
|
|
Post.Status.REVIEW: "warning",
|
|
Post.Status.DRAFT: "info",
|
|
Post.Status.ARCHIVED: "danger",
|
|
})
|
|
def status_badge(self, obj):
|
|
return obj.get_status_display()
|
|
|
|
@action(description=_('Publish selected posts'))
|
|
def publish_posts(self, request, queryset):
|
|
count = queryset.update(status=Post.Status.PUBLISHED)
|
|
self.message_user(request, _(f"{count} post(s) published successfully."))
|
|
|
|
@action(description=_('Archive selected posts'))
|
|
def archive_posts(self, request, queryset):
|
|
count = queryset.update(status=Post.Status.ARCHIVED)
|
|
self.message_user(request, _(f"{count} post(s) archived."))
|
|
|
|
@action(description=_('Toggle featured status for selected posts'))
|
|
def toggle_featured(self, request, queryset):
|
|
for item in queryset:
|
|
item.is_featured = not item.is_featured
|
|
item.save(update_fields=['is_featured'])
|
|
self.message_user(request, _("Featured status updated."))
|
|
|
|
|
|
@admin.register(PostCategory, site=project_admin_site)
|
|
class PostCategoryAdmin(ModelAdmin):
|
|
list_display = ('name', 'slug', 'language', 'created_at')
|
|
list_display_links = ('name', 'slug')
|
|
list_filter = ('language',)
|
|
search_fields = ('name', 'description')
|
|
prepopulated_fields = {'slug': ('name',)}
|
|
|
|
|
|
@admin.register(PostTag, site=project_admin_site)
|
|
class PostTagAdmin(ModelAdmin):
|
|
list_display = ('name', 'slug')
|
|
list_display_links = ('name', 'slug')
|
|
search_fields = ('name',)
|
|
prepopulated_fields = {'slug': ('name',)}
|
|
|
|
|
|
@admin.register(PostComment, site=project_admin_site)
|
|
class PostCommentAdmin(ModelAdmin):
|
|
list_display = ('author_display', 'post', 'status_badge', 'created_at')
|
|
list_display_links = ('author_display', 'post')
|
|
list_filter = ('status', 'created_at')
|
|
search_fields = ('author_name', 'author_email', 'content', 'post__title')
|
|
actions = ['approve_comments', 'mark_as_spam']
|
|
|
|
@display(description=_('Author'))
|
|
def author_display(self, obj):
|
|
return obj.author_name or (obj.user.fullname if obj.user else "Anonymous")
|
|
|
|
@display(description=_('Status'), label={
|
|
PostComment.Status.APPROVED: "success",
|
|
PostComment.Status.PENDING: "warning",
|
|
PostComment.Status.SPAM: "danger",
|
|
})
|
|
def status_badge(self, obj):
|
|
return obj.get_status_display()
|
|
|
|
@action(description=_('Approve selected comments'))
|
|
def approve_comments(self, request, queryset):
|
|
count = queryset.update(status=PostComment.Status.APPROVED)
|
|
self.message_user(request, _(f"{count} comment(s) approved."))
|
|
|
|
@action(description=_('Mark selected comments as spam'))
|
|
def mark_as_spam(self, request, queryset):
|
|
count = queryset.update(status=PostComment.Status.SPAM)
|
|
self.message_user(request, _(f"{count} comment(s) marked as spam."))
|
|
|
|
|
|
@admin.register(PostLike, site=project_admin_site)
|
|
class PostLikeAdmin(ModelAdmin):
|
|
list_display = ('user', 'post', 'created_at')
|
|
list_display_links = ('user', 'post')
|
|
search_fields = ('user__email', 'user__fullname', 'post__title')
|
|
readonly_fields = ('created_at',)
|
|
|
|
|
|
@admin.register(MediaAsset, site=project_admin_site)
|
|
class MediaAssetAdmin(ModelAdmin):
|
|
list_display = ('title', 'media_type', 'file_size', 'uploaded_by', 'created_at')
|
|
list_display_links = ('title', 'uploaded_by')
|
|
list_filter = ('media_type', 'created_at')
|
|
search_fields = ('title', 'uploaded_by__email')
|
|
readonly_fields = ('created_at',)
|