gitdataai/libs/service/project/join_answers.rs
2026-04-15 09:08:09 +08:00

135 lines
4.4 KiB
Rust

use crate::AppService;
use crate::error::AppError;
use chrono::{DateTime, Utc};
use models::projects::{
project_audit_log, project_member_join_answers, project_member_join_request,
};
use sea_orm::*;
use serde::{Deserialize, Serialize};
use session::Session;
#[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)]
pub struct AnswerRequest {
pub question: String,
pub answer: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct JoinAnswerResponse {
pub question: String,
pub answer: String,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct JoinAnswersListResponse {
pub request_id: i64,
pub project_uid: String,
pub answers: Vec<JoinAnswerResponse>,
}
impl AppService {
pub async fn project_get_join_answers(
&self,
project_name: String,
request_id: i64,
ctx: &Session,
) -> Result<JoinAnswersListResponse, AppError> {
let _user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
let project = self.utils_find_project_by_name(project_name).await?;
// Verify the request exists and belongs to this project
let join_request = project_member_join_request::Entity::find_by_id(request_id)
.filter(project_member_join_request::Column::Project.eq(project.id))
.one(&self.db)
.await?
.ok_or(AppError::NotFound("Join request not found".to_string()))?;
let answers = project_member_join_answers::Entity::find()
.filter(project_member_join_answers::Column::RequestId.eq(request_id))
.order_by_asc(project_member_join_answers::Column::Id)
.all(&self.db)
.await?;
let answer_responses = answers
.into_iter()
.map(|a| JoinAnswerResponse {
question: a.question,
answer: a.answer,
created_at: a.created_at,
})
.collect();
Ok(JoinAnswersListResponse {
request_id: join_request.id,
project_uid: project.id.to_string(),
answers: answer_responses,
})
}
pub async fn project_submit_join_answers(
&self,
project_name: String,
request_id: i64,
answers: Vec<AnswerRequest>,
ctx: &Session,
) -> Result<(), AppError> {
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
let project = self
.utils_find_project_by_name(project_name.clone())
.await?;
// Verify the request exists, belongs to this project, and belongs to the user
let join_request = project_member_join_request::Entity::find_by_id(request_id)
.filter(project_member_join_request::Column::Project.eq(project.id))
.filter(project_member_join_request::Column::User.eq(user_uid))
.one(&self.db)
.await?
.ok_or(AppError::NotFound("Join request not found".to_string()))?;
if join_request.status != "pending" {
return Err(AppError::InternalServerError(
"Cannot update answers for processed request".to_string(),
));
}
// Delete existing answers
project_member_join_answers::Entity::delete_many()
.filter(project_member_join_answers::Column::RequestId.eq(request_id))
.exec(&self.db)
.await?;
let txn = self.db.begin().await?;
// Insert new answers
for answer in answers {
let answer_model = project_member_join_answers::ActiveModel {
id: Default::default(),
project: Set(project.id),
user: Set(user_uid),
request_id: Set(request_id),
question: Set(answer.question),
answer: Set(answer.answer),
created_at: Set(Utc::now()),
};
answer_model.insert(&txn).await?;
}
let log = project_audit_log::ActiveModel {
project: Set(project.id),
actor: Set(user_uid),
action: Set("submit_join_answers".to_string()),
details: Set(Some(serde_json::json!({
"request_id": request_id,
}))),
created_at: Set(Utc::now()),
..Default::default()
};
log.insert(&txn).await?;
txn.commit().await?;
Ok(())
}
}