135 lines
4.4 KiB
Rust
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(())
|
|
}
|
|
}
|