use crate::{AppService, error::AppError}; use chrono::Utc; use models::projects::{MemberRole, project_audit_log, project_history_name}; use models::repos::{Repo, repo}; use models::users::user; use sea_orm::*; use serde::{Deserialize, Serialize}; use session::Session; #[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)] pub struct ExchangeProjectVisibility { pub is_public: bool, } #[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)] pub struct ExchangeProjectTitle { pub display_name: Option, pub description: Option, } #[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)] pub struct ExchangeProjectName { pub name: String, } impl AppService { pub async fn project_exchange_name( &self, ctx: &Session, project_name: String, params: ExchangeProjectName, ) -> Result<(), AppError> { let user_uid = ctx.user().ok_or(AppError::Unauthorized)?; let project = self .utils_find_project_by_name(project_name.clone()) .await?; let oper = user::Entity::find() .filter(user::Column::Uid.eq(user_uid)) .one(&self.db) .await? .ok_or(AppError::UserNotFound)?; if let Ok(role) = self.utils_project_context_role(&ctx, project_name).await { if role != MemberRole::Owner { return Err(AppError::NoPower); } } else { return Err(AppError::NoPower); } let txn = self.db.begin().await?; let mut active = project.clone().into_active_model(); active.name = Set(params.name.clone()); active.update(&txn).await?; // Update repo names for all repos in this project let repos = Repo::find() .filter(repo::Column::Project.eq(project.id)) .all(&txn) .await?; for r in repos { let repo_name = r.repo_name.clone(); let mut ra: repo::ActiveModel = r.into(); ra.repo_name = Set(format!("{}/{}", params.name.clone(), repo_name)); ra.update(&txn).await?; } let log = project_audit_log::ActiveModel { project: Set(project.id), actor: Set(user_uid), action: Set("exchange_name".to_string()), details: Set(Some(serde_json::json!({ "name": params.name, "old_name": project.name, "username": oper.username, "user_uid": user_uid, }))), created_at: Set(Utc::now()), ..Default::default() }; let history = project_history_name::ActiveModel { id: NotSet, project_uid: Set(project.id), history_name: Set(project.name), changed_at: Set(Utc::now()), }; history.insert(&txn).await?; log.insert(&txn).await?; txn.commit().await?; Ok(()) } pub async fn project_exchange_visibility( &self, ctx: &Session, project_name: String, params: ExchangeProjectVisibility, ) -> Result<(), AppError> { let user_uid = ctx.user().ok_or(AppError::Unauthorized)?; let project = self .utils_find_project_by_name(project_name.clone()) .await?; if let Ok(role) = self.utils_project_context_role(&ctx, project_name).await { if role == MemberRole::Member { return Err(AppError::NoPower); } } else { return Err(AppError::NoPower); } if project.is_public != params.is_public { let txn = self.db.begin().await?; let mut active = project.clone().into_active_model(); active.is_public = Set(params.is_public); active.update(&txn).await?; let oper = user::Entity::find() .filter(user::Column::Uid.eq(user_uid)) .one(&txn) .await? .ok_or(AppError::UserNotFound)?; let log = project_audit_log::ActiveModel { project: Set(project.id), actor: Set(user_uid), action: Set("exchange_visibility".to_string()), details: Set(Some(serde_json::json!({ "is_public": params.is_public, "old_is_public": project.is_public, "username": oper.username, "user_uid": user_uid, }))), created_at: Set(Utc::now()), ..Default::default() }; log.insert(&txn).await?; txn.commit().await?; } Ok(()) } pub async fn project_exchange_title( &self, ctx: &Session, project_name: String, params: ExchangeProjectTitle, ) -> Result<(), AppError> { let user_uid = ctx.user().ok_or(AppError::Unauthorized)?; let project = self .utils_find_project_by_name(project_name.clone()) .await?; if let Ok(role) = self.utils_project_context_role(&ctx, project_name).await { if role == MemberRole::Member { return Err(AppError::NoPower); } } else { return Err(AppError::NoPower); } let txn = self.db.begin().await?; let mut active = project.clone().into_active_model(); if let Some(description) = params.description.clone() { active.description = Set(Some(description)); } if let Some(display_name) = params.display_name.clone() { active.display_name = Set(display_name); } active.update(&txn).await?; let oper = user::Entity::find() .filter(user::Column::Uid.eq(user_uid)) .one(&txn) .await? .ok_or(AppError::UserNotFound)?; let log = project_audit_log::ActiveModel { project: Set(project.id), actor: Set(user_uid), action: Set("exchange_description".to_string()), details: Set(Some(serde_json::json!({ "description": params.description, "username": oper.username, "user_uid": user_uid, "old_description": project.description, "display_name": params.display_name, "old_display_name": project.display_name, }))), created_at: Set(Utc::now()), ..Default::default() }; log.insert(&txn).await?; txn.commit().await?; Ok(()) } }