use crate::AppService; use crate::error::AppError; use chrono::Utc; use models::projects::{project_audit_log, project_member_join_settings}; use sea_orm::*; use serde::{Deserialize, Serialize}; use session::Session; #[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] pub struct JoinSettingsResponse { pub project_uid: String, pub require_approval: bool, pub require_questions: bool, pub questions: serde_json::Value, } #[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)] pub struct UpdateJoinSettingsRequest { pub require_approval: bool, pub require_questions: bool, pub questions: Vec, } #[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)] pub struct QuestionSchema { pub question: String, } impl AppService { pub async fn project_get_join_settings( &self, project_name: String, ctx: &Session, ) -> Result { let _user_uid = ctx.user().ok_or(AppError::Unauthorized)?; let project = self.utils_find_project_by_name(project_name).await?; let settings = project_member_join_settings::Entity::find() .filter(project_member_join_settings::Column::Project.eq(project.id)) .one(&self.db) .await?; match settings { Some(s) => Ok(JoinSettingsResponse { project_uid: project.id.to_string(), require_approval: s.require_approval, require_questions: s.require_questions, questions: s.questions, }), None => Ok(JoinSettingsResponse { project_uid: project.id.to_string(), require_approval: false, require_questions: false, questions: serde_json::json!([]), }), } } pub async fn project_update_join_settings( &self, project_name: String, request: UpdateJoinSettingsRequest, ctx: &Session, ) -> Result { let user_uid = ctx.user().ok_or(AppError::Unauthorized)?; let project = self .utils_find_project_by_name(project_name.clone()) .await?; let role = self .utils_project_context_role(&ctx, project_name.clone()) .await .map_err(|_| AppError::NoPower)?; if role != models::projects::MemberRole::Owner && role != models::projects::MemberRole::Admin { return Err(AppError::NoPower); } let txn = self.db.begin().await?; let existing = project_member_join_settings::Entity::find() .filter(project_member_join_settings::Column::Project.eq(project.id)) .one(&txn) .await?; let questions_json: serde_json::Value = serde_json::json!( request .questions .iter() .map(|q| q.question.clone()) .collect::>() ); if let Some(settings) = existing { let mut active: project_member_join_settings::ActiveModel = settings.into(); active.require_approval = Set(request.require_approval); active.require_questions = Set(request.require_questions); active.questions = Set(questions_json.clone()); active.updated_at = Set(Utc::now()); active.update(&txn).await?; } else { let new_settings = project_member_join_settings::ActiveModel { id: Default::default(), project: Set(project.id), require_approval: Set(request.require_approval), require_questions: Set(request.require_questions), questions: Set(questions_json.clone()), created_at: Set(Utc::now()), updated_at: Set(Utc::now()), }; new_settings.insert(&txn).await?; } let log = project_audit_log::ActiveModel { project: Set(project.id), actor: Set(user_uid), action: Set("update_join_settings".to_string()), details: Set(Some(serde_json::json!({ "require_approval": request.require_approval, "require_questions": request.require_questions, "questions_count": request.questions.len(), }))), created_at: Set(Utc::now()), ..Default::default() }; log.insert(&txn).await?; txn.commit().await?; Ok(JoinSettingsResponse { project_uid: project.id.to_string(), require_approval: request.require_approval, require_questions: request.require_questions, questions: questions_json, }) } }