Skip to main content

tdm_server_rust/repository/
episode_role_taker_repo.rs

1//! 话级共同接稿仓储。
2//!
3//! 仅服务翻译 / 校对岗位的多人共同接稿记录,不改动原有话数主负责人列。
4
5use crate::{db::DbConn, error::AppError, sea_entity::episode_role_taker};
6use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, Set};
7use sqlx::postgres::PgPool;
8
9/// 共同接稿仓储。
10pub struct EpisodeRoleTakerRepository {
11    /// SeaORM 数据库连接。
12    db: DbConn,
13}
14
15impl EpisodeRoleTakerRepository {
16    /// 从 `PgPool` 构造仓储。
17    pub fn new(pool: PgPool) -> Self {
18        Self {
19            db: crate::db::from_sqlx_pool(pool),
20        }
21    }
22
23    /// 新增共同接稿人。
24    pub async fn add_taker(
25        &self,
26        episode_id: i32,
27        role: &str,
28        member_id: i32,
29    ) -> crate::error::ApiResult<()> {
30        validate_role(role)?;
31        if self
32            .find_taker(episode_id, role, member_id)
33            .await?
34            .is_some()
35        {
36            return Err(AppError::business("你已经共同接稿了喵"));
37        }
38        episode_role_taker::ActiveModel {
39            episode_id: Set(episode_id),
40            role: Set(role.to_string()),
41            member_id: Set(member_id),
42            setup_time: Set(chrono::Utc::now().naive_utc()),
43            ..Default::default()
44        }
45        .insert(&self.db)
46        .await?;
47        Ok(())
48    }
49
50    /// 批量查询话数的共同接稿人。
51    pub async fn list_takers_for_episodes(
52        &self,
53        episode_ids: &[i32],
54    ) -> crate::error::ApiResult<Vec<episode_role_taker::Model>> {
55        if episode_ids.is_empty() {
56            return Ok(vec![]);
57        }
58        let rows = episode_role_taker::Entity::find()
59            .filter(episode_role_taker::Column::EpisodeId.is_in(episode_ids.to_vec()))
60            .order_by_asc(episode_role_taker::Column::SetupTime)
61            .all(&self.db)
62            .await?;
63        Ok(rows)
64    }
65
66    /// 查询某个组员是否为指定话数指定岗位的共同接稿人。
67    pub async fn find_taker(
68        &self,
69        episode_id: i32,
70        role: &str,
71        member_id: i32,
72    ) -> crate::error::ApiResult<Option<episode_role_taker::Model>> {
73        validate_role(role)?;
74        let row = episode_role_taker::Entity::find()
75            .filter(episode_role_taker::Column::EpisodeId.eq(episode_id))
76            .filter(episode_role_taker::Column::Role.eq(role))
77            .filter(episode_role_taker::Column::MemberId.eq(member_id))
78            .one(&self.db)
79            .await?;
80        Ok(row)
81    }
82
83    /// 标记共同接稿人已交稿。
84    pub async fn submit_taker(
85        &self,
86        episode_id: i32,
87        role: &str,
88        member_id: i32,
89    ) -> crate::error::ApiResult<()> {
90        let row = self
91            .find_taker(episode_id, role, member_id)
92            .await?
93            .ok_or_else(|| AppError::business("你还没有共同接这份稿喵"))?;
94        let mut am: episode_role_taker::ActiveModel = row.into();
95        am.update_time = Set(Some(chrono::Utc::now().naive_utc()));
96        am.update(&self.db).await?;
97        Ok(())
98    }
99
100    /// 清空共同接稿人的交稿与文件,返回旧 OSS ID。
101    pub async fn rollback_taker(
102        &self,
103        episode_id: i32,
104        role: &str,
105        member_id: i32,
106    ) -> crate::error::ApiResult<Option<i32>> {
107        let row = self
108            .find_taker(episode_id, role, member_id)
109            .await?
110            .ok_or_else(|| AppError::business("你还没有共同接这份稿喵"))?;
111        let old_oss_id = row.file_oss_id;
112        let mut am: episode_role_taker::ActiveModel = row.into();
113        am.update_time = Set(None);
114        am.file_oss_id = Set(None);
115        am.update(&self.db).await?;
116        Ok(old_oss_id)
117    }
118
119    /// 绑定共同接稿人的独立稿件 OSS ID。
120    pub async fn set_taker_file_oss(
121        &self,
122        episode_id: i32,
123        role: &str,
124        member_id: i32,
125        oss_id: i32,
126    ) -> crate::error::ApiResult<()> {
127        let row = self
128            .find_taker(episode_id, role, member_id)
129            .await?
130            .ok_or_else(|| AppError::business("你还没有共同接这份稿喵"))?;
131        let mut am: episode_role_taker::ActiveModel = row.into();
132        am.file_oss_id = Set(Some(oss_id));
133        am.update(&self.db).await?;
134        Ok(())
135    }
136}
137
138/// 共同接稿当前只开放翻译 / 校对。
139pub fn is_supported_role(role: &str) -> bool {
140    matches!(role, "translator" | "proofreader")
141}
142
143/// 校验共同接稿岗位。
144fn validate_role(role: &str) -> crate::error::ApiResult<()> {
145    if is_supported_role(role) {
146        Ok(())
147    } else {
148        Err(AppError::business("共同接稿仅支持翻译和校对喵"))
149    }
150}