mmap/src/graphql/queries/blog.rs
tsuki 58ea36e73c
Some checks are pending
Docker Build and Push / build (push) Waiting to run
sycn
2025-08-18 23:14:02 +08:00

225 lines
8.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::auth::get_auth_user;
use crate::graphql::types::{blog::*, PaginatedResult, PaginationInput};
use crate::services::{blog_service::BlogService, casbin_service::CasbinService};
use async_graphql::{Context, Error as GraphQLError, Object, Result};
use uuid::Uuid;
#[derive(Default)]
pub struct BlogQuery;
#[Object]
impl BlogQuery {
async fn blogs(
&self,
ctx: &Context<'_>,
filter: Option<BlogFilterInput>,
sort: Option<BlogSortInput>,
pagination: Option<PaginationInput>,
) -> Result<PaginatedResult<Blog>> {
let blog_service = ctx.data::<BlogService>()?;
// 检查用户权限
let mut updated_filter = filter.unwrap_or(BlogFilterInput {
title: None,
slug: None,
category_id: None,
status: None,
is_featured: None,
is_active: None,
tag_ids: None,
search: None,
date_from: None,
date_to: None,
});
// 尝试获取用户信息和权限检查
match get_auth_user(ctx).await {
Ok(user) => {
// 用户已认证,检查是否有读取 blogs 的权限
let casbin_service = ctx.data::<CasbinService>()?;
let has_permission = casbin_service
.can_read(&user.id.to_string(), "blogs")
.await
.unwrap_or(false);
// 如果没有权限,则只返回非 draft 状态的博客
if !has_permission {
// 如果过滤器中没有设置状态,或者状态包含 draft则排除 draft 状态
if updated_filter.status.is_none() || updated_filter.status.as_ref() == Some(&"draft".to_string()) {
updated_filter.status = Some("published".to_string());
}
}
}
Err(_) => {
// 用户未认证,只返回已发布的博客
if updated_filter.status.is_none() || updated_filter.status.as_ref() == Some(&"draft".to_string()) {
updated_filter.status = Some("published".to_string());
}
}
}
let result = blog_service
.get_blogs(Some(updated_filter), sort, pagination)
.await
.map_err(|e| GraphQLError::new(e.to_string()))?;
// 转换 model 类型到 GraphQL 类型
Ok(PaginatedResult::new(
result.items.into_iter().map(|item| item.into()).collect(),
result.total,
result.page,
result.per_page,
))
}
/// 根据ID获取博客文章
async fn blog(&self, ctx: &Context<'_>, id: Uuid) -> Result<Blog> {
let blog_service = ctx.data::<BlogService>()?;
let blog = blog_service
.get_blog_by_id(id)
.await
.map_err(|e| GraphQLError::new(e.to_string()))?;
// 权限检查:如果是 draft 状态,需要验证用户权限
if blog.status == "draft" {
match get_auth_user(ctx).await {
Ok(user) => {
let casbin_service = ctx.data::<CasbinService>()?;
let has_permission = casbin_service
.can_read(&user.id.to_string(), "blogs")
.await
.unwrap_or(false);
if !has_permission {
return Err(GraphQLError::new("Insufficient permissions to access draft content"));
}
}
Err(_) => {
return Err(GraphQLError::new("Authentication required to access draft content"));
}
}
}
Ok(blog.into())
}
/// 根据slug获取博客文章
async fn blog_by_slug(&self, ctx: &Context<'_>, slug: String) -> Result<Blog> {
let blog_service = ctx.data::<BlogService>()?;
let blog = blog_service
.get_blog_by_slug(&slug)
.await
.map_err(|e| GraphQLError::new(e.to_string()))?;
// 权限检查:如果是 draft 状态,需要验证用户权限
if blog.status == "draft" {
match get_auth_user(ctx).await {
Ok(user) => {
let casbin_service = ctx.data::<CasbinService>()?;
let has_permission = casbin_service
.can_read(&user.id.to_string(), "blogs")
.await
.unwrap_or(false);
if !has_permission {
return Err(GraphQLError::new("Insufficient permissions to access draft content"));
}
}
Err(_) => {
return Err(GraphQLError::new("Authentication required to access draft content"));
}
}
}
Ok(blog.into())
}
async fn blog_detail(&self, ctx: &Context<'_>, id: Uuid) -> Result<BlogDetail> {
let blog_service = ctx.data::<BlogService>()?;
let detail = blog_service
.get_blog_detail(id)
.await
.map_err(|e| GraphQLError::new(e.to_string()))?;
// 权限检查:如果是 draft 状态,需要验证用户权限
if detail.blog.status == "draft" {
match get_auth_user(ctx).await {
Ok(user) => {
let casbin_service = ctx.data::<CasbinService>()?;
let has_permission = casbin_service
.can_read(&user.id.to_string(), "blogs")
.await
.unwrap_or(false);
if !has_permission {
return Err(GraphQLError::new("Insufficient permissions to access draft content"));
}
}
Err(_) => {
return Err(GraphQLError::new("Authentication required to access draft content"));
}
}
}
// 手动转换 BlogDetail因为它包含嵌套结构
Ok(BlogDetail {
blog: detail.blog.into(),
category: detail.category.map(|c| c.into()),
tags: detail.tags.into_iter().map(|t| t.into()).collect(),
})
}
async fn blog_stats(&self, ctx: &Context<'_>) -> Result<BlogStats> {
let blog_service = ctx.data::<BlogService>()?;
let stats = blog_service
.get_blog_stats()
.await
.map_err(|e| GraphQLError::new(e.to_string()))?;
Ok(stats.into())
}
async fn blog_categories(
&self,
ctx: &Context<'_>,
filter: Option<BlogCategoryFilterInput>,
) -> Result<Vec<BlogCategory>> {
let blog_service = ctx.data::<BlogService>()?;
let categories = blog_service
.get_categories(filter)
.await
.map_err(|e| GraphQLError::new(e.to_string()))?;
Ok(categories.into_iter().map(|c| c.into()).collect())
}
async fn blog_category(&self, ctx: &Context<'_>, id: Uuid) -> Result<BlogCategory> {
let blog_service = ctx.data::<BlogService>()?;
let category = blog_service
.get_category_by_id(id)
.await
.map_err(|e| GraphQLError::new(e.to_string()))?;
Ok(category.into())
}
async fn blog_tags(
&self,
ctx: &Context<'_>,
filter: Option<BlogTagFilterInput>,
) -> Result<Vec<BlogTag>> {
let blog_service = ctx.data::<BlogService>()?;
let tags = blog_service
.get_tags(filter)
.await
.map_err(|e| GraphQLError::new(e.to_string()))?;
Ok(tags.into_iter().map(|t| t.into()).collect())
}
async fn blog_tag(&self, ctx: &Context<'_>, id: Uuid) -> Result<BlogTag> {
let blog_service = ctx.data::<BlogService>()?;
let tag = blog_service
.get_tag_by_id(id)
.await
.map_err(|e| GraphQLError::new(e.to_string()))?;
Ok(tag.into())
}
}