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, } #[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] pub struct JoinAnswersListResponse { pub request_id: i64, pub project_uid: String, pub answers: Vec, } impl AppService { pub async fn project_get_join_answers( &self, project_name: String, request_id: i64, ctx: &Session, ) -> Result { 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, 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(()) } }