143 lines
4.5 KiB
Rust
143 lines
4.5 KiB
Rust
use crate::AppService;
|
|
use crate::error::AppError;
|
|
use chrono::Utc;
|
|
use models::projects::{project, project_members};
|
|
use models::users::user;
|
|
use sea_orm::prelude::*;
|
|
use sea_orm::*;
|
|
use serde::{Deserialize, Serialize};
|
|
use session::Session;
|
|
use utoipa::{IntoParams, ToSchema};
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
|
pub struct UserProjectInfo {
|
|
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: chrono::DateTime<Utc>,
|
|
pub updated_at: chrono::DateTime<Utc>,
|
|
pub member_count: i64,
|
|
pub is_member: bool,
|
|
}
|
|
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
|
pub struct UserProjectsResponse {
|
|
pub username: String,
|
|
pub projects: Vec<UserProjectInfo>,
|
|
pub total_count: u64,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, IntoParams)]
|
|
pub struct UserProjectsQuery {
|
|
pub page: Option<u64>,
|
|
pub per_page: Option<u64>,
|
|
}
|
|
|
|
impl AppService {
|
|
pub async fn get_user_projects(
|
|
&self,
|
|
context: Session,
|
|
username: String,
|
|
query: UserProjectsQuery,
|
|
) -> Result<UserProjectsResponse, AppError> {
|
|
let target_user = user::Entity::find()
|
|
.filter(user::Column::Username.eq(&username))
|
|
.one(&self.db)
|
|
.await?
|
|
.ok_or(AppError::UserNotFound)?;
|
|
|
|
let current_user_uid = context.user();
|
|
|
|
let is_owner = current_user_uid
|
|
.map(|uid| uid == target_user.uid)
|
|
.unwrap_or(false);
|
|
let has_admin_privilege = false;
|
|
|
|
let page = std::cmp::Ord::max(query.page.unwrap_or(1), 1);
|
|
let per_page = std::cmp::Ord::min(std::cmp::Ord::max(query.per_page.unwrap_or(20), 1), 100);
|
|
let offset = (page - 1) * per_page;
|
|
|
|
let mut condition = Condition::all().add(project::Column::CreatedBy.eq(target_user.uid));
|
|
|
|
if !is_owner && !has_admin_privilege {
|
|
condition = condition.add(project::Column::IsPublic.eq(true));
|
|
}
|
|
|
|
let total_count = project::Entity::find()
|
|
.filter(condition.clone())
|
|
.count(&self.db)
|
|
.await?;
|
|
|
|
let project_list = project::Entity::find()
|
|
.filter(condition)
|
|
.order_by_desc(project::Column::CreatedAt)
|
|
.limit(per_page)
|
|
.offset(offset)
|
|
.all(&self.db)
|
|
.await?;
|
|
|
|
let user_project_memberships: std::collections::HashSet<Uuid> =
|
|
if let Some(uid) = current_user_uid {
|
|
project_members::Entity::find()
|
|
.filter(project_members::Column::User.eq(uid))
|
|
.select_only()
|
|
.column(project_members::Column::Project)
|
|
.into_tuple::<Uuid>()
|
|
.all(&self.db)
|
|
.await?
|
|
.into_iter()
|
|
.collect()
|
|
} else {
|
|
std::collections::HashSet::new()
|
|
};
|
|
|
|
let mut project_infos: Vec<UserProjectInfo> = Vec::new();
|
|
for project in project_list {
|
|
let member_count = project_members::Entity::find()
|
|
.filter(project_members::Column::Project.eq(project.id))
|
|
.count(&self.db)
|
|
.await?;
|
|
|
|
let is_member = user_project_memberships.contains(&project.id);
|
|
|
|
project_infos.push(UserProjectInfo {
|
|
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,
|
|
member_count: member_count as i64,
|
|
is_member,
|
|
});
|
|
}
|
|
|
|
Ok(UserProjectsResponse {
|
|
username: target_user.username,
|
|
projects: project_infos,
|
|
total_count,
|
|
})
|
|
}
|
|
|
|
pub async fn get_current_user_projects(
|
|
&self,
|
|
context: Session,
|
|
query: UserProjectsQuery,
|
|
) -> Result<UserProjectsResponse, AppError> {
|
|
let user_uid = context.user().ok_or(AppError::Unauthorized)?;
|
|
|
|
let user = user::Entity::find()
|
|
.filter(user::Column::Uid.eq(user_uid))
|
|
.one(&self.db)
|
|
.await?
|
|
.ok_or(AppError::UserNotFound)?;
|
|
|
|
self.get_user_projects(context, user.username, query).await
|
|
}
|
|
}
|