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

144 lines
4.5 KiB
Rust

use crate::AppService;
use crate::error::AppError;
use chrono::{DateTime, Utc};
use models::projects::{MemberRole, project_label, project_like, project_members, project_watch};
use models::system::label;
use models::users::user;
use sea_orm::*;
use serde::{Deserialize, Serialize};
use session::Session;
use utoipa::ToSchema;
use uuid::Uuid;
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
pub struct ProjectInfoRelational {
pub uid: Uuid,
pub name: String,
pub display_name: String,
pub avatar_url: Option<String>,
pub description: Option<String>,
pub is_public: bool,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub created_by: Uuid,
pub created_username_name: String,
pub created_display_name: Option<String>,
pub created_avatar_url: Option<String>,
pub member_count: i64,
pub like_count: i64,
pub watch_count: i64,
pub keys: Vec<ProjectInfoKeyValue>,
pub labels: Vec<ProjectInfoLabel>,
pub role: Option<MemberRole>,
pub is_like: bool,
pub is_watch: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
pub struct ProjectInfoKeyValue {
pub key: String,
pub value: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
pub struct ProjectInfoLabel {
pub name: String,
pub color: String,
}
impl AppService {
pub async fn project_info(
&self,
ctx: &Session,
project_name: String,
) -> Result<ProjectInfoRelational, AppError> {
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
let project = self.utils_find_project_by_name(project_name).await?;
let is_member = self
.utils_project_context_role(&ctx, project.name.clone())
.await
.ok();
if !project.is_public && is_member.is_none() {
return Err(AppError::NotFound("Project not found".to_string()));
}
let creator = user::Entity::find()
.filter(user::Column::Uid.eq(project.created_by))
.one(&self.db)
.await?
.ok_or(AppError::UserNotFound)?;
let member_count = project_members::Entity::find()
.filter(project_members::Column::Project.eq(project.id))
.count(&self.db)
.await?;
let like_count = project_like::Entity::find()
.filter(project_like::Column::Project.eq(project.id))
.count(&self.db)
.await?;
let watch_count = project_watch::Entity::find()
.filter(project_watch::Column::Project.eq(project.id))
.count(&self.db)
.await?;
let labels_model = project_label::Entity::find()
.filter(project_label::Column::Project.eq(project.id))
.all(&self.db)
.await?
.iter()
.map(|x| x.label)
.collect::<Vec<i64>>();
let labes = label::Entity::find()
.filter(label::Column::Id.is_in(labels_model))
.all(&self.db)
.await?;
let labels = labes
.into_iter()
.map(|l| ProjectInfoLabel {
name: l.name,
color: l.color,
})
.collect();
let is_like = project_like::Entity::find()
.filter(project_like::Column::Project.eq(project.id))
.filter(project_like::Column::User.eq(user_uid))
.count(&self.db)
.await?
> 0;
let is_watch = project_watch::Entity::find()
.filter(project_watch::Column::Project.eq(project.id))
.filter(project_watch::Column::User.eq(user_uid))
.count(&self.db)
.await?
> 0;
Ok(ProjectInfoRelational {
uid: project.id,
name: project.name,
display_name: project.display_name,
avatar_url: project.avatar_url,
description: project.description,
is_public: project.is_public,
created_at: project.created_at,
updated_at: project.updated_at,
created_by: project.created_by,
created_username_name: creator.username,
created_display_name: creator.display_name,
created_avatar_url: creator.avatar_url,
member_count: member_count as i64,
like_count: like_count as i64,
watch_count: watch_count as i64,
keys: Vec::new(),
labels,
role: is_member,
is_like,
is_watch,
})
}
}