tdm_server_rust/repository/
episode_role_taker_repo.rs1use crate::{db::DbConn, error::AppError, sea_entity::episode_role_taker};
6use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, Set};
7use sqlx::postgres::PgPool;
8
9pub struct EpisodeRoleTakerRepository {
11 db: DbConn,
13}
14
15impl EpisodeRoleTakerRepository {
16 pub fn new(pool: PgPool) -> Self {
18 Self {
19 db: crate::db::from_sqlx_pool(pool),
20 }
21 }
22
23 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 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 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 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 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 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
138pub fn is_supported_role(role: &str) -> bool {
140 matches!(role, "translator" | "proofreader")
141}
142
143fn validate_role(role: &str) -> crate::error::ApiResult<()> {
145 if is_supported_role(role) {
146 Ok(())
147 } else {
148 Err(AppError::business("共同接稿仅支持翻译和校对喵"))
149 }
150}