1use chrono::{DateTime, Utc};
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq)]
15#[serde(rename_all = "UPPERCASE")]
16pub enum EpisodeType {
17 #[default]
19 Main,
20 Extra,
22}
23
24impl EpisodeType {
25 pub const fn as_str(self) -> &'static str {
26 match self {
27 Self::Main => "MAIN",
28 Self::Extra => "EXTRA",
29 }
30 }
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, Default)]
35#[serde(rename_all = "camelCase")]
36pub struct EpisodeSimpleListVo {
37 pub id: i32,
39 pub manga_episode: Option<String>,
41 pub manga_episode_name: Option<String>,
43 pub episode_type: EpisodeType,
45 pub translator_file: Option<String>,
47 pub proofreader_file: Option<String>,
49 pub timer_file: Option<String>,
51 pub provider_file_oss_id: Option<i32>,
53 pub editor_page_count: i64,
55 pub translator_file_oss_id: Option<i32>,
57 pub proofreader_file_oss_id: Option<i32>,
59 pub letterer_file_oss_id: Option<i32>,
61 pub timer_file_oss_id: Option<i32>,
63 pub publish_link: Option<String>,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize, Default)]
69#[serde(rename_all = "camelCase")]
70pub struct EpisodeListVo {
71 pub id: i32,
73 pub manga_id: i32,
75 pub manga_episode: Option<String>,
77 pub manga_episode_name: Option<String>,
79 pub episode_type: EpisodeType,
81 pub provider_id: Option<i32>,
83 pub translator_id: Option<i32>,
85 pub proofreader_id: Option<i32>,
87 pub letterer_id: Option<i32>,
89 pub timer_id: Option<i32>,
91 pub reviewer_id: Option<i32>,
93 pub setup_time: Option<DateTime<Utc>>,
95 pub update_time: Option<DateTime<Utc>>,
97 pub translator_file: Option<String>,
99 pub proofreader_file: Option<String>,
101 pub timer_file: Option<String>,
103 pub publish_link: Option<String>,
105 pub provider_file_oss_id: Option<i32>,
107 pub editor_page_count: i64,
109 pub translator_file_oss_id: Option<i32>,
111 pub proofreader_file_oss_id: Option<i32>,
113 pub letterer_file_oss_id: Option<i32>,
115 pub timer_file_oss_id: Option<i32>,
117 #[serde(skip_serializing_if = "Option::is_none")]
119 pub translator_setup_time: Option<DateTime<Utc>>,
120 #[serde(skip_serializing_if = "Option::is_none")]
122 pub translator_update_time: Option<DateTime<Utc>>,
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub proofreader_setup_time: Option<DateTime<Utc>>,
126 #[serde(skip_serializing_if = "Option::is_none")]
128 pub proofreader_update_time: Option<DateTime<Utc>>,
129 #[serde(skip_serializing_if = "Option::is_none")]
131 pub letterer_setup_time: Option<DateTime<Utc>>,
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub letterer_update_time: Option<DateTime<Utc>>,
135 #[serde(skip_serializing_if = "Option::is_none")]
137 pub timer_setup_time: Option<DateTime<Utc>>,
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub timer_update_time: Option<DateTime<Utc>>,
141 #[serde(skip_serializing_if = "Option::is_none")]
143 pub reviewer_setup_time: Option<DateTime<Utc>>,
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub reviewer_update_time: Option<DateTime<Utc>>,
147 #[serde(skip_serializing_if = "Option::is_none")]
149 pub provider_name: Option<String>,
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub translator_name: Option<String>,
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub proofreader_name: Option<String>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub letterer_name: Option<String>,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub timer_name: Option<String>,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub reviewer_name: Option<String>,
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub provider_filename: Option<String>,
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub translator_filename: Option<String>,
171 #[serde(skip_serializing_if = "Option::is_none")]
173 pub proofreader_filename: Option<String>,
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub letterer_filename: Option<String>,
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub timer_filename: Option<String>,
180 #[serde(default)]
182 pub translator_co_takers: Vec<RoleTakerVo>,
183 #[serde(default)]
185 pub proofreader_co_takers: Vec<RoleTakerVo>,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize, Default)]
190#[serde(rename_all = "camelCase")]
191pub struct RoleTakerVo {
192 pub member_id: i32,
194 pub member_name: Option<String>,
196 pub avatar_url: Option<String>,
198 pub setup_time: Option<DateTime<Utc>>,
200 pub update_time: Option<DateTime<Utc>>,
202 pub file_oss_id: Option<i32>,
204 pub filename: Option<String>,
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize, Default)]
210#[serde(rename_all = "camelCase")]
211pub struct EpisodeDetailVo {
212 pub id: i32,
214 pub manga_id: i32,
216 pub manga_episode: Option<String>,
218 pub manga_episode_name: Option<String>,
220 pub episode_type: EpisodeType,
222 pub provider_id: Option<i32>,
224 pub translator_id: Option<i32>,
226 pub proofreader_id: Option<i32>,
228 pub letterer_id: Option<i32>,
230 pub timer_id: Option<i32>,
232 pub reviewer_id: Option<i32>,
234 pub setup_time: Option<DateTime<Utc>>,
236 pub update_time: Option<DateTime<Utc>>,
238 pub publish_link: Option<String>,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize, Default)]
244#[serde(rename_all = "camelCase")]
245pub struct NewestEpisodeVo {
246 pub manga_episode: Option<String>,
248 pub translator_id: Option<i32>,
250 pub proofreader_id: Option<i32>,
252 pub letterer_id: Option<i32>,
254 pub reviewer_id: Option<i32>,
256}
257
258#[derive(Debug, Clone, Deserialize, Serialize)]
266#[serde(rename_all = "camelCase")]
267pub struct EpisodeEditDto {
268 #[serde(
270 default,
271 deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose"
272 )]
273 pub id: Option<i32>,
274 #[serde(
276 default,
277 deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose"
278 )]
279 pub manga_id: Option<i32>,
280 pub manga_episode: Option<String>,
282 pub manga_episode_end: Option<String>,
284 pub manga_episode_name: Option<String>,
286 pub episode_type: Option<EpisodeType>,
288 #[serde(
290 default,
291 deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose"
292 )]
293 pub provider_id: Option<i32>,
294 #[serde(
296 default,
297 deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose"
298 )]
299 pub translator_id: Option<i32>,
300 #[serde(
302 default,
303 deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose"
304 )]
305 pub proofreader_id: Option<i32>,
306 #[serde(
308 default,
309 deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose"
310 )]
311 pub letterer_id: Option<i32>,
312 #[serde(
314 default,
315 deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose"
316 )]
317 pub timer_id: Option<i32>,
318 #[serde(
320 default,
321 deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose"
322 )]
323 pub reviewer_id: Option<i32>,
324 pub publish_link: Option<String>,
326}
327
328#[derive(Debug, Clone, Deserialize, Serialize)]
330#[serde(rename_all = "camelCase")]
331pub struct PublishLinkRequest {
332 pub id: i32,
334 pub publish_link: Option<String>,
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize, Default)]
340#[serde(rename_all = "camelCase")]
341pub struct UploadPageVo {
342 pub id: i32,
344 pub manga_id: i32,
346 pub manga_name: Option<String>,
348 pub manga_episode: Option<String>,
350 pub update_time: Option<DateTime<Utc>>,
352 pub translator_file: Option<String>,
354 pub proofreader_file: Option<String>,
356 pub timer_file: Option<String>,
358 pub provider_id: Option<i32>,
360 pub translator_id: Option<i32>,
362 pub proofreader_id: Option<i32>,
364 pub letterer_id: Option<i32>,
366 pub timer_id: Option<i32>,
368 pub reviewer_id: Option<i32>,
370 #[serde(skip_serializing_if = "Option::is_none")]
372 pub provider_name: Option<String>,
373 #[serde(skip_serializing_if = "Option::is_none")]
375 pub translator_name: Option<String>,
376 #[serde(skip_serializing_if = "Option::is_none")]
378 pub proofreader_name: Option<String>,
379 #[serde(skip_serializing_if = "Option::is_none")]
381 pub letterer_name: Option<String>,
382 #[serde(skip_serializing_if = "Option::is_none")]
384 pub timer_name: Option<String>,
385 #[serde(skip_serializing_if = "Option::is_none")]
387 pub reviewer_name: Option<String>,
388 #[serde(skip_serializing_if = "Option::is_none")]
390 pub provider_file_oss_id: Option<i32>,
391 #[serde(skip_serializing_if = "Option::is_none")]
393 pub translator_file_oss_id: Option<i32>,
394 #[serde(skip_serializing_if = "Option::is_none")]
396 pub proofreader_file_oss_id: Option<i32>,
397 #[serde(skip_serializing_if = "Option::is_none")]
399 pub letterer_file_oss_id: Option<i32>,
400 #[serde(skip_serializing_if = "Option::is_none")]
402 pub timer_file_oss_id: Option<i32>,
403 #[serde(skip_serializing_if = "Option::is_none")]
405 pub provider_filename: Option<String>,
406 #[serde(skip_serializing_if = "Option::is_none")]
408 pub translator_filename: Option<String>,
409 #[serde(skip_serializing_if = "Option::is_none")]
411 pub proofreader_filename: Option<String>,
412 #[serde(skip_serializing_if = "Option::is_none")]
414 pub letterer_filename: Option<String>,
415 #[serde(skip_serializing_if = "Option::is_none")]
417 pub timer_filename: Option<String>,
418 #[serde(skip_serializing_if = "Option::is_none")]
420 pub email: Option<String>,
421 #[serde(skip_serializing_if = "Option::is_none")]
423 pub email_now: Option<String>,
424}
425
426#[derive(Debug, Clone, Serialize, Deserialize, Default)]
428#[serde(rename_all = "camelCase")]
429pub struct Statistics {
430 #[serde(default)]
432 pub translator_count: i32,
433 #[serde(default)]
435 pub proofreader_count: i32,
436 #[serde(default)]
438 pub letterer_count: i32,
439 #[serde(default)]
441 pub reviewer_count: i32,
442}
443
444#[derive(Debug, Clone, Serialize, Deserialize, Default)]
446#[serde(rename_all = "camelCase")]
447pub struct MemberStatistics {
448 pub user_name: Option<String>,
450 pub user_id: Option<String>,
452 pub translator_count: i32,
454 pub proofreader_count: i32,
456 pub letterer_count: i32,
458 pub timer_count: i32,
460 pub reviewer_count: i32,
462}
463
464#[derive(Debug, Clone, Serialize, Deserialize, Default)]
466#[serde(rename_all = "camelCase")]
467pub struct EpisodeTask {
468 pub manga_id: Option<i32>,
470 pub episode_id: Option<i32>,
472 pub manga_episode: Option<String>,
474 pub episode_name: Option<String>,
476 pub member_id: Option<i32>,
478 pub setup_time: Option<DateTime<Utc>>,
480 pub previous_update_time: Option<DateTime<Utc>>,
482 pub post: Option<String>,
484}
485
486#[derive(Debug, Clone, Serialize, Deserialize, Default)]
488#[serde(rename_all = "camelCase")]
489pub struct MemberTaskCount {
490 pub user_name: Option<String>,
492 pub user_id: Option<String>,
494 pub intern: Option<i32>,
496 pub email: Option<String>,
498 pub last_update_time: Option<String>,
500 pub stationed_count: i32,
502 pub translator_count: i32,
504 pub proofreader_count: i32,
506 pub letterer_count: i32,
508 pub timer_count: i32,
510 pub reviewer_count: i32,
512}
513
514impl MemberTaskCount {
515 pub fn total_count(&self) -> i32 {
517 self.translator_count
518 + self.proofreader_count
519 + self.letterer_count
520 + self.timer_count
521 + self.reviewer_count
522 }
523}
524
525#[derive(Debug, Clone, Serialize, Deserialize, Default)]
531#[serde(rename_all = "camelCase")]
532pub struct TaskTrackingResponse {
533 pub translator_task_list: Vec<EpisodeTask>,
535 pub proofreader_task_list: Vec<EpisodeTask>,
537 pub letterer_task_list: Vec<EpisodeTask>,
539 pub timer_task_list: Vec<EpisodeTask>,
541 pub reviewer_task_list: Vec<EpisodeTask>,
543 pub publish_task_list: Vec<EpisodeTask>,
545 pub all_task_list: Vec<EpisodeTask>,
547}
548
549impl TaskTrackingResponse {
550 pub fn empty() -> Self {
552 Self::default()
553 }
554}
555
556#[derive(Debug, Clone, Serialize, Deserialize, Default)]
558#[serde(rename_all = "camelCase")]
559pub struct WorkflowEpisodeItem {
560 pub manga_id: i32,
562 pub episode_id: i32,
564 pub manga_episode: Option<String>,
566 pub episode_name: Option<String>,
568 pub manga_tran_name: Option<String>,
570 pub category: Option<i16>,
572 pub member_id: Option<i32>,
574 pub member_name: Option<String>,
576 pub step_label: Option<String>,
578 pub match_step: Option<String>,
580 pub intern: Option<i32>,
582 pub previous_update_time: Option<DateTime<Utc>>,
584 pub setup_time: Option<DateTime<Utc>>,
586}
587
588#[derive(Debug, Clone, Serialize, Deserialize)]
590#[serde(rename_all = "camelCase")]
591pub struct MangaEpisode {
592 #[serde(rename = "Id")]
594 pub id: i32,
595 pub manga_id: i32,
597 pub manga_episode: Option<String>,
599 pub manga_name: Option<String>,
601 pub category: Option<i16>,
603}
604
605#[derive(Debug, Clone, Serialize, Deserialize)]
615#[serde(rename_all = "camelCase")]
616pub struct PendingMangaTask {
617 pub mangatb: crate::entity::manga::Mangatb,
619 pub newest_manga_episode: Option<String>,
621 pub pending_episode_list: Vec<PendingEpisode>,
623}
624#[derive(Debug, Clone, Serialize, Deserialize, Default)]
628#[serde(rename_all = "camelCase")]
629pub struct MangaEpisodeTb {
630 pub id: i32,
632 pub manga_id: i32,
634 pub manga_episode: Option<String>,
636 pub manga_episode_name: Option<String>,
638 pub episode_type: EpisodeType,
640 pub provider_id: Option<i32>,
642 pub translator_id: Option<i32>,
644 pub proofreader_id: Option<i32>,
646 pub letterer_id: Option<i32>,
648 pub timer_id: Option<i32>,
650 pub reviewer_id: Option<i32>,
652 pub setup_time: Option<DateTime<Utc>>,
654 pub update_time: Option<DateTime<Utc>>,
656 pub translator_file: Option<String>,
658 pub proofreader_file: Option<String>,
660 pub timer_file: Option<String>,
662 pub publish_link: Option<String>,
664 pub provider_file_oss_id: Option<i32>,
666 pub translator_file_oss_id: Option<i32>,
668 pub proofreader_file_oss_id: Option<i32>,
670 pub letterer_file_oss_id: Option<i32>,
672 pub timer_file_oss_id: Option<i32>,
674}
675
676#[derive(Debug, Clone, Serialize, Deserialize)]
678#[serde(rename_all = "camelCase")]
679pub struct PendingEpisode {
680 pub mangaepisodetb: MangaEpisodeTb,
682 pub status: String,
684 pub next_publish: bool,
686}
687
688#[cfg(test)]
689mod episode_type_tests {
690 use super::EpisodeType;
691
692 #[test]
693 fn episode_type_uses_api_contract_values() {
694 assert_eq!(serde_json::to_string(&EpisodeType::Main).unwrap(), "\"MAIN\"");
695 assert_eq!(serde_json::to_string(&EpisodeType::Extra).unwrap(), "\"EXTRA\"");
696 assert_eq!(
697 serde_json::from_str::<EpisodeType>("\"EXTRA\"").unwrap(),
698 EpisodeType::Extra
699 );
700 }
701}