feat(diary): Phase 1.3 完善修复 — 贴纸/主题 CRUD + 管理端对接 + HMS 清理
H7 贴纸 CRUD: - POST /diary/sticker-packs — 创建贴纸包 - DELETE /diary/sticker-packs/:id — 软删除贴纸包 - POST /diary/sticker-packs/:id/stickers — 添加贴纸 H8 主题编辑/停用: - PUT /diary/topics/:id — 编辑主题 (标题/描述/截止日期) - PATCH /diary/topics/:id/deactivate — 停用主题 管理端前端: - ClassList.tsx 对接 update/deactivate/reset-code (含 Popconfirm 确认) - JournalList.tsx 班级筛选改用 classApi.listAll() - classes.ts 新增 listAll/update/deactivate/resetCode API M2 HMS 遗留清理: - 删除 copilot.ts, healthFixtures.ts, healthHandlers.ts - AuditLogViewer 资源类型 → 日记模块 - auth.test.ts / renderWithProviders health.* → diary.* M4 编辑器加载: - EditorPage journalId 非空时从 Isar 恢复笔画/元素/标签/心情/标题 77 tests passed, cargo check ✅, tsc ✅, flutter analyze ✅
This commit is contained in:
@@ -189,6 +189,51 @@ pub struct CreateCommentReq {
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
/// 更新主题请求
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct UpdateTopicReq {
|
||||
/// 主题标题
|
||||
pub title: Option<String>,
|
||||
/// 主题描述
|
||||
pub description: Option<String>,
|
||||
/// 截止日期
|
||||
pub due_date: Option<chrono::NaiveDate>,
|
||||
/// 乐观锁版本号
|
||||
pub version: i32,
|
||||
}
|
||||
|
||||
/// 创建贴纸包请求
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct CreateStickerPackReq {
|
||||
/// 贴纸包名称
|
||||
pub name: String,
|
||||
/// 描述
|
||||
pub description: Option<String>,
|
||||
/// 缩略图 URL
|
||||
pub thumbnail_url: Option<String>,
|
||||
/// 是否免费
|
||||
#[serde(default = "default_true")]
|
||||
pub is_free: bool,
|
||||
/// 价格(积分)
|
||||
#[serde(default)]
|
||||
pub price: i32,
|
||||
/// 分类
|
||||
pub category: Option<String>,
|
||||
}
|
||||
|
||||
fn default_true() -> bool { true }
|
||||
|
||||
/// 创建贴纸请求
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct CreateStickerReq {
|
||||
/// 贴纸名称
|
||||
pub name: String,
|
||||
/// 图片 URL
|
||||
pub image_url: String,
|
||||
/// 分类
|
||||
pub category: Option<String>,
|
||||
}
|
||||
|
||||
/// 评语响应
|
||||
#[derive(Debug, Serialize, ToSchema)]
|
||||
pub struct CommentResp {
|
||||
|
||||
@@ -10,7 +10,7 @@ use erp_core::error::AppError;
|
||||
use erp_core::rbac::require_permission;
|
||||
use erp_core::types::{ApiResponse, TenantContext};
|
||||
|
||||
use crate::dto::{StickerPackResp, StickerResp, TemplateResp};
|
||||
use crate::dto::{CreateStickerPackReq, CreateStickerReq, StickerPackResp, StickerResp, TemplateResp};
|
||||
use crate::service::sticker_service::StickerService;
|
||||
use crate::state::DiaryState;
|
||||
|
||||
@@ -85,7 +85,125 @@ where
|
||||
Ok(Json(ApiResponse::ok(resp)))
|
||||
}
|
||||
|
||||
/// 模板查询参数
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/api/v1/diary/sticker-packs",
|
||||
request_body = CreateStickerPackReq,
|
||||
responses(
|
||||
(status = 200, description = "创建成功", body = ApiResponse<StickerPackResp>),
|
||||
(status = 400, description = "验证失败"),
|
||||
(status = 401, description = "未授权"),
|
||||
(status = 403, description = "权限不足"),
|
||||
),
|
||||
security(("bearer_auth" = [])),
|
||||
tag = "贴纸管理"
|
||||
)]
|
||||
/// POST /api/v1/diary/sticker-packs
|
||||
///
|
||||
/// 创建贴纸包。需要 `diary.class.manage` 权限(管理端)。
|
||||
pub async fn create_sticker_pack<S>(
|
||||
State(state): State<DiaryState>,
|
||||
Extension(ctx): Extension<TenantContext>,
|
||||
Json(req): Json<CreateStickerPackReq>,
|
||||
) -> Result<Json<ApiResponse<StickerPackResp>>, AppError>
|
||||
where
|
||||
DiaryState: FromRef<S>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
require_permission(&ctx, "diary.class.manage")?;
|
||||
|
||||
if req.name.trim().is_empty() {
|
||||
return Err(AppError::Validation("贴纸包名称不能为空".to_string()));
|
||||
}
|
||||
|
||||
let resp = StickerService::create_sticker_pack(
|
||||
ctx.tenant_id,
|
||||
ctx.user_id,
|
||||
&req,
|
||||
&state.db,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(ApiResponse::ok(resp)))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/api/v1/diary/sticker-packs/{pack_id}",
|
||||
params(("pack_id" = Uuid, Path, description = "贴纸包ID")),
|
||||
responses(
|
||||
(status = 200, description = "删除成功"),
|
||||
(status = 401, description = "未授权"),
|
||||
(status = 403, description = "权限不足"),
|
||||
(status = 404, description = "贴纸包不存在"),
|
||||
),
|
||||
security(("bearer_auth" = [])),
|
||||
tag = "贴纸管理"
|
||||
)]
|
||||
/// DELETE /api/v1/diary/sticker-packs/:pack_id
|
||||
///
|
||||
/// 删除贴纸包(软删除)。需要 `diary.class.manage` 权限。
|
||||
pub async fn delete_sticker_pack<S>(
|
||||
State(state): State<DiaryState>,
|
||||
Extension(ctx): Extension<TenantContext>,
|
||||
Path(pack_id): Path<Uuid>,
|
||||
) -> Result<Json<ApiResponse<()>>, AppError>
|
||||
where
|
||||
DiaryState: FromRef<S>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
require_permission(&ctx, "diary.class.manage")?;
|
||||
|
||||
StickerService::delete_sticker_pack(ctx.tenant_id, pack_id, ctx.user_id, &state.db).await?;
|
||||
|
||||
Ok(Json(ApiResponse::ok(())))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/api/v1/diary/sticker-packs/{pack_id}/stickers",
|
||||
params(("pack_id" = Uuid, Path, description = "贴纸包ID")),
|
||||
request_body = CreateStickerReq,
|
||||
responses(
|
||||
(status = 200, description = "创建成功", body = ApiResponse<StickerResp>),
|
||||
(status = 400, description = "验证失败"),
|
||||
(status = 401, description = "未授权"),
|
||||
(status = 403, description = "权限不足"),
|
||||
(status = 404, description = "贴纸包不存在"),
|
||||
),
|
||||
security(("bearer_auth" = [])),
|
||||
tag = "贴纸管理"
|
||||
)]
|
||||
/// POST /api/v1/diary/sticker-packs/:pack_id/stickers
|
||||
///
|
||||
/// 在贴纸包内添加贴纸。需要 `diary.class.manage` 权限。
|
||||
pub async fn create_sticker<S>(
|
||||
State(state): State<DiaryState>,
|
||||
Extension(ctx): Extension<TenantContext>,
|
||||
Path(pack_id): Path<Uuid>,
|
||||
Json(req): Json<CreateStickerReq>,
|
||||
) -> Result<Json<ApiResponse<StickerResp>>, AppError>
|
||||
where
|
||||
DiaryState: FromRef<S>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
require_permission(&ctx, "diary.class.manage")?;
|
||||
|
||||
if req.name.trim().is_empty() {
|
||||
return Err(AppError::Validation("贴纸名称不能为空".to_string()));
|
||||
}
|
||||
|
||||
let resp = StickerService::create_sticker(
|
||||
ctx.tenant_id,
|
||||
ctx.user_id,
|
||||
pack_id,
|
||||
&req,
|
||||
&state.db,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(ApiResponse::ok(resp)))
|
||||
}
|
||||
#[derive(Debug, Deserialize, IntoParams)]
|
||||
pub struct TemplateQuery {
|
||||
pub category: Option<String>,
|
||||
|
||||
@@ -8,7 +8,7 @@ use erp_core::error::AppError;
|
||||
use erp_core::rbac::require_permission;
|
||||
use erp_core::types::{ApiResponse, TenantContext};
|
||||
|
||||
use crate::dto::{CreateTopicReq, TopicResp};
|
||||
use crate::dto::{CreateTopicReq, TopicResp, UpdateTopicReq};
|
||||
use crate::service::topic_service::TopicService;
|
||||
use crate::state::DiaryState;
|
||||
|
||||
@@ -88,3 +88,90 @@ where
|
||||
let resp = TopicService::list_topics(ctx.tenant_id, class_id, &state.db).await?;
|
||||
Ok(Json(ApiResponse::ok(resp)))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
put,
|
||||
path = "/api/v1/diary/topics/{topic_id}",
|
||||
params(("topic_id" = Uuid, Path, description = "主题ID")),
|
||||
request_body = UpdateTopicReq,
|
||||
responses(
|
||||
(status = 200, description = "更新成功", body = ApiResponse<TopicResp>),
|
||||
(status = 400, description = "验证失败"),
|
||||
(status = 401, description = "未授权"),
|
||||
(status = 403, description = "权限不足"),
|
||||
(status = 404, description = "主题不存在"),
|
||||
(status = 409, description = "版本冲突"),
|
||||
),
|
||||
security(("bearer_auth" = [])),
|
||||
tag = "主题布置"
|
||||
)]
|
||||
/// PUT /api/v1/diary/topics/:topic_id
|
||||
///
|
||||
/// 更新主题信息。需要 `diary.topic.assign` 权限(仅布置者可编辑)。
|
||||
pub async fn update_topic<S>(
|
||||
State(state): State<DiaryState>,
|
||||
Extension(ctx): Extension<TenantContext>,
|
||||
Path(topic_id): Path<Uuid>,
|
||||
Json(req): Json<UpdateTopicReq>,
|
||||
) -> Result<Json<ApiResponse<TopicResp>>, AppError>
|
||||
where
|
||||
DiaryState: FromRef<S>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
require_permission(&ctx, "diary.topic.assign")?;
|
||||
|
||||
if let Some(ref title) = req.title {
|
||||
if title.trim().is_empty() {
|
||||
return Err(AppError::Validation("主题标题不能为空".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
let resp = TopicService::update_topic(
|
||||
ctx.tenant_id,
|
||||
ctx.user_id,
|
||||
topic_id,
|
||||
&req,
|
||||
&state.db,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(ApiResponse::ok(resp)))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
path = "/api/v1/diary/topics/{topic_id}/deactivate",
|
||||
params(("topic_id" = Uuid, Path, description = "主题ID")),
|
||||
responses(
|
||||
(status = 200, description = "停用成功", body = ApiResponse<TopicResp>),
|
||||
(status = 401, description = "未授权"),
|
||||
(status = 403, description = "权限不足"),
|
||||
(status = 404, description = "主题不存在"),
|
||||
),
|
||||
security(("bearer_auth" = [])),
|
||||
tag = "主题布置"
|
||||
)]
|
||||
/// PATCH /api/v1/diary/topics/:topic_id/deactivate
|
||||
///
|
||||
/// 停用主题。需要 `diary.topic.assign` 权限(仅布置者可停用)。
|
||||
pub async fn deactivate_topic<S>(
|
||||
State(state): State<DiaryState>,
|
||||
Extension(ctx): Extension<TenantContext>,
|
||||
Path(topic_id): Path<Uuid>,
|
||||
) -> Result<Json<ApiResponse<TopicResp>>, AppError>
|
||||
where
|
||||
DiaryState: FromRef<S>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
require_permission(&ctx, "diary.topic.assign")?;
|
||||
|
||||
let resp = TopicService::deactivate_topic(
|
||||
ctx.tenant_id,
|
||||
ctx.user_id,
|
||||
topic_id,
|
||||
&state.db,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(ApiResponse::ok(resp)))
|
||||
}
|
||||
|
||||
@@ -173,6 +173,14 @@ impl DiaryModule {
|
||||
axum::routing::post(topic_handler::assign_topic)
|
||||
.get(topic_handler::list_topics),
|
||||
)
|
||||
.route(
|
||||
"/diary/topics/{topic_id}",
|
||||
axum::routing::put(topic_handler::update_topic),
|
||||
)
|
||||
.route(
|
||||
"/diary/topics/{topic_id}/deactivate",
|
||||
axum::routing::patch(topic_handler::deactivate_topic),
|
||||
)
|
||||
// 评语管理
|
||||
.route(
|
||||
"/diary/journals/{journal_id}/comments",
|
||||
@@ -186,11 +194,17 @@ impl DiaryModule {
|
||||
// 贴纸管理
|
||||
.route(
|
||||
"/diary/sticker-packs",
|
||||
axum::routing::get(sticker_handler::list_sticker_packs),
|
||||
axum::routing::get(sticker_handler::list_sticker_packs)
|
||||
.post(sticker_handler::create_sticker_pack),
|
||||
)
|
||||
.route(
|
||||
"/diary/sticker-packs/{pack_id}",
|
||||
axum::routing::delete(sticker_handler::delete_sticker_pack),
|
||||
)
|
||||
.route(
|
||||
"/diary/sticker-packs/{pack_id}/stickers",
|
||||
axum::routing::get(sticker_handler::list_stickers_in_pack),
|
||||
axum::routing::get(sticker_handler::list_stickers_in_pack)
|
||||
.post(sticker_handler::create_sticker),
|
||||
)
|
||||
// 模板管理
|
||||
.route(
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// 贴纸服务 — 贴纸包与贴纸管理
|
||||
|
||||
use sea_orm::{
|
||||
ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder,
|
||||
ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait,
|
||||
QueryFilter, QueryOrder, Set,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::dto::{StickerPackResp, StickerResp, TemplateResp};
|
||||
use crate::dto::{CreateStickerPackReq, CreateStickerReq, StickerPackResp, StickerResp, TemplateResp};
|
||||
use crate::entity::{sticker, sticker_pack, template};
|
||||
use crate::error::{DiaryError, DiaryResult};
|
||||
|
||||
@@ -151,6 +152,116 @@ impl StickerService {
|
||||
is_free: true,
|
||||
})
|
||||
}
|
||||
|
||||
/// 创建贴纸包(管理端)
|
||||
pub async fn create_sticker_pack(
|
||||
tenant_id: Uuid,
|
||||
user_id: Uuid,
|
||||
req: &CreateStickerPackReq,
|
||||
db: &DatabaseConnection,
|
||||
) -> DiaryResult<StickerPackResp> {
|
||||
let now = chrono::Utc::now();
|
||||
let id = Uuid::now_v7();
|
||||
|
||||
let model = sticker_pack::ActiveModel {
|
||||
id: Set(id),
|
||||
tenant_id: Set(tenant_id),
|
||||
name: Set(req.name.clone()),
|
||||
description: Set(req.description.clone()),
|
||||
thumbnail_url: Set(req.thumbnail_url.clone()),
|
||||
is_free: Set(req.is_free),
|
||||
price: Set(req.price),
|
||||
category: Set(req.category.clone()),
|
||||
created_at: Set(now),
|
||||
updated_at: Set(now),
|
||||
created_by: Set(user_id),
|
||||
updated_by: Set(user_id),
|
||||
deleted_at: Set(None),
|
||||
version: Set(1),
|
||||
};
|
||||
let inserted = model.insert(db).await?;
|
||||
|
||||
Ok(StickerPackResp {
|
||||
id: inserted.id,
|
||||
name: inserted.name,
|
||||
description: inserted.description,
|
||||
cover_image_url: inserted.thumbnail_url,
|
||||
sticker_count: 0,
|
||||
is_free: inserted.is_free,
|
||||
category: inserted.category,
|
||||
})
|
||||
}
|
||||
|
||||
/// 删除贴纸包(软删除)
|
||||
pub async fn delete_sticker_pack(
|
||||
tenant_id: Uuid,
|
||||
pack_id: Uuid,
|
||||
user_id: Uuid,
|
||||
db: &DatabaseConnection,
|
||||
) -> DiaryResult<()> {
|
||||
let model = sticker_pack::Entity::find()
|
||||
.filter(sticker_pack::Column::Id.eq(pack_id))
|
||||
.filter(sticker_pack::Column::TenantId.eq(tenant_id))
|
||||
.filter(sticker_pack::Column::DeletedAt.is_null())
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or_else(|| DiaryError::NotFound(format!("贴纸包 {} 不存在", pack_id)))?;
|
||||
|
||||
let now = chrono::Utc::now();
|
||||
let mut active: sticker_pack::ActiveModel = model.into();
|
||||
active.deleted_at = Set(Some(now));
|
||||
active.updated_at = Set(now);
|
||||
active.updated_by = Set(user_id);
|
||||
active.update(db).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 创建贴纸(管理端)
|
||||
pub async fn create_sticker(
|
||||
tenant_id: Uuid,
|
||||
user_id: Uuid,
|
||||
pack_id: Uuid,
|
||||
req: &CreateStickerReq,
|
||||
db: &DatabaseConnection,
|
||||
) -> DiaryResult<StickerResp> {
|
||||
// 验证贴纸包存在
|
||||
let _pack = sticker_pack::Entity::find()
|
||||
.filter(sticker_pack::Column::Id.eq(pack_id))
|
||||
.filter(sticker_pack::Column::TenantId.eq(tenant_id))
|
||||
.filter(sticker_pack::Column::DeletedAt.is_null())
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or_else(|| DiaryError::NotFound(format!("贴纸包 {} 不存在", pack_id)))?;
|
||||
|
||||
let now = chrono::Utc::now();
|
||||
let id = Uuid::now_v7();
|
||||
|
||||
let model = sticker::ActiveModel {
|
||||
id: Set(id),
|
||||
tenant_id: Set(tenant_id),
|
||||
pack_id: Set(pack_id),
|
||||
name: Set(req.name.clone()),
|
||||
image_url: Set(req.image_url.clone()),
|
||||
category: Set(req.category.clone()),
|
||||
tags: Set(None),
|
||||
created_at: Set(now),
|
||||
updated_at: Set(now),
|
||||
created_by: Set(user_id),
|
||||
updated_by: Set(user_id),
|
||||
deleted_at: Set(None),
|
||||
version: Set(1),
|
||||
};
|
||||
let inserted = model.insert(db).await?;
|
||||
|
||||
Ok(StickerResp {
|
||||
id: inserted.id,
|
||||
pack_id: inserted.pack_id,
|
||||
name: inserted.name,
|
||||
image_url: inserted.image_url,
|
||||
category: inserted.category,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -7,7 +7,7 @@ use sea_orm::{
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::dto::{CreateTopicReq, TopicResp};
|
||||
use crate::dto::{CreateTopicReq, TopicResp, UpdateTopicReq};
|
||||
use crate::entity::topic_assignment;
|
||||
use crate::error::{DiaryError, DiaryResult};
|
||||
use crate::service::notification_service::NotificationService;
|
||||
@@ -112,6 +112,93 @@ impl TopicService {
|
||||
|
||||
Ok(topics.into_iter().map(topic_model_to_resp).collect())
|
||||
}
|
||||
|
||||
/// 更新主题信息(老师)
|
||||
///
|
||||
/// 仅主题创建者可修改标题、描述、截止日期。
|
||||
pub async fn update_topic(
|
||||
tenant_id: Uuid,
|
||||
user_id: Uuid,
|
||||
topic_id: Uuid,
|
||||
req: &UpdateTopicReq,
|
||||
db: &DatabaseConnection,
|
||||
) -> DiaryResult<TopicResp> {
|
||||
let model = topic_assignment::Entity::find()
|
||||
.filter(topic_assignment::Column::Id.eq(topic_id))
|
||||
.filter(topic_assignment::Column::TenantId.eq(tenant_id))
|
||||
.filter(topic_assignment::Column::DeletedAt.is_null())
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or_else(|| DiaryError::NotFound(format!("主题 {} 不存在", topic_id)))?;
|
||||
|
||||
// 仅布置者可编辑
|
||||
if model.teacher_id != user_id {
|
||||
return Err(DiaryError::Forbidden);
|
||||
}
|
||||
|
||||
// 乐观锁
|
||||
if model.version != req.version {
|
||||
return Err(DiaryError::VersionConflict {
|
||||
local: req.version,
|
||||
server: model.version,
|
||||
});
|
||||
}
|
||||
|
||||
let now = Utc::now();
|
||||
let mut active: topic_assignment::ActiveModel = model.into();
|
||||
if let Some(ref title) = req.title {
|
||||
active.title = Set(title.clone());
|
||||
}
|
||||
if let Some(ref desc) = req.description {
|
||||
active.description = Set(Some(desc.clone()));
|
||||
}
|
||||
if req.due_date.is_some() {
|
||||
active.due_date = Set(req.due_date);
|
||||
}
|
||||
active.updated_at = Set(now);
|
||||
active.updated_by = Set(user_id);
|
||||
active.version = Set(req.version + 1);
|
||||
|
||||
let updated = active.update(db).await?;
|
||||
Ok(topic_model_to_resp(updated))
|
||||
}
|
||||
|
||||
/// 停用主题(老师)
|
||||
///
|
||||
/// 停用后主题不再显示给学生,已提交的日记不受影响。
|
||||
pub async fn deactivate_topic(
|
||||
tenant_id: Uuid,
|
||||
user_id: Uuid,
|
||||
topic_id: Uuid,
|
||||
db: &DatabaseConnection,
|
||||
) -> DiaryResult<TopicResp> {
|
||||
let model = topic_assignment::Entity::find()
|
||||
.filter(topic_assignment::Column::Id.eq(topic_id))
|
||||
.filter(topic_assignment::Column::TenantId.eq(tenant_id))
|
||||
.filter(topic_assignment::Column::DeletedAt.is_null())
|
||||
.one(db)
|
||||
.await?
|
||||
.ok_or_else(|| DiaryError::NotFound(format!("主题 {} 不存在", topic_id)))?;
|
||||
|
||||
if model.teacher_id != user_id {
|
||||
return Err(DiaryError::Forbidden);
|
||||
}
|
||||
|
||||
if !model.is_active {
|
||||
return Err(DiaryError::BadRequest("主题已处于停用状态".to_string()));
|
||||
}
|
||||
|
||||
let now = Utc::now();
|
||||
let current_version = model.version;
|
||||
let mut active: topic_assignment::ActiveModel = model.into();
|
||||
active.is_active = Set(false);
|
||||
active.updated_at = Set(now);
|
||||
active.updated_by = Set(user_id);
|
||||
active.version = Set(current_version + 1);
|
||||
let updated = active.update(db).await?;
|
||||
|
||||
Ok(topic_model_to_resp(updated))
|
||||
}
|
||||
}
|
||||
|
||||
/// topic_assignment::Model -> TopicResp
|
||||
|
||||
Reference in New Issue
Block a user