From a785008b26227611e804a307ed4b65a72679683e Mon Sep 17 00:00:00 2001 From: ZhenYi <434836402@qq.com> Date: Tue, 17 Dec 2024 21:46:26 +0800 Subject: [PATCH] fix router --- src/api/app_docs.rs | 12 +++++- src/api/app_routes.rs | 13 ++++--- src/api/dto/repo_dto.rs | 11 ++++++ src/api/handler/mod.rs | 1 + src/api/handler/repos/info.rs | 41 ++++++++++++++++++++ src/api/handler/repos/mod.rs | 2 + src/api/handler/repos/search.rs | 35 +++++++++++++++++ src/api/handler/users/mod.rs | 3 +- src/api/handler/users/search.rs | 36 +++++++++++++++++ src/api/handler/users/starred.rs | 33 ++++++++++++++++ src/api/init.rs | 2 + src/http/config.rs | 1 - src/http/handler.rs | 1 + src/metadata/service/repos_service/info.rs | 21 ++++++++++ src/metadata/service/users_service/mod.rs | 1 + src/metadata/service/users_service/search.rs | 18 +++++++++ src/ssh/handler.rs | 17 ++++---- 17 files changed, 233 insertions(+), 15 deletions(-) create mode 100644 src/api/handler/repos/info.rs create mode 100644 src/api/handler/repos/mod.rs create mode 100644 src/api/handler/repos/search.rs create mode 100644 src/api/handler/users/starred.rs create mode 100644 src/metadata/service/users_service/search.rs diff --git a/src/api/app_docs.rs b/src/api/app_docs.rs index 91ff0a5..1cb6e61 100644 --- a/src/api/app_docs.rs +++ b/src/api/app_docs.rs @@ -1,3 +1,7 @@ +use crate::api::handler::repos::info::__path_api_repo_info_get; +use crate::api::handler::users::starred::__path_api_users_starred; +use crate::api::handler::users::search::__path_api_users_search; +use crate::api::handler::repos::search::__path_api_repo_search; use crate::api::handler::users::repos::__path_api_users_repos; use crate::api::handler::users::follower::__path_api_users_following; use crate::api::handler::users::follower::__path_api_users_followed; @@ -63,6 +67,9 @@ use utoipa::OpenApi; api_users_following, api_users_followed, api_users_repos, + api_users_search, + api_users_starred, + api_user_avatar, api_user_avatar_upload, @@ -104,7 +111,10 @@ use utoipa::OpenApi; api_groups_labels, api_groups_labels_create, api_groups_labels_delete, - api_groups_labels_update + api_groups_labels_update, + + api_repo_search, + api_repo_info_get, ), )] pub struct ApiDoc; diff --git a/src/api/app_routes.rs b/src/api/app_routes.rs index fa1504f..7dc6787 100644 --- a/src/api/app_routes.rs +++ b/src/api/app_routes.rs @@ -9,6 +9,8 @@ use crate::api::handler::groups::labels::{api_groups_labels, api_groups_labels_c use crate::api::handler::groups::members::{api_groups_member_add, api_groups_member_remove, api_groups_members, api_user_groups}; use crate::api::handler::groups::repos::{api_groups_repo, api_groups_repo_create}; use crate::api::handler::groups::search::api_groups_search; +use crate::api::handler::repos::info::api_repo_info_get; +use crate::api::handler::repos::search::api_repo_search; use crate::api::handler::user::avatar::{api_user_avatar, api_user_avatar_delete, api_user_avatar_upload}; use crate::api::handler::user::emails::{api_user_email, api_user_email_bind, api_user_email_unbind}; use crate::api::handler::user::follower::{api_user_follow, api_user_followed, api_user_follower, api_user_unfollow}; @@ -24,6 +26,8 @@ use crate::api::handler::users::login::{api_users_login_email, api_users_login_n use crate::api::handler::users::logout::api_users_logout; use crate::api::handler::users::repos::api_users_repos; use crate::api::handler::users::reset::{api_user_reset_passwd_forget, api_user_reset_passwd_profile}; +use crate::api::handler::users::search::api_users_search; +use crate::api::handler::users::starred::api_users_starred; pub fn routes(cfg: &mut web::ServiceConfig){ cfg @@ -88,14 +92,14 @@ pub fn routes(cfg: &mut web::ServiceConfig){ .route("/profile", web::post().to(api_user_reset_passwd_profile)) ) .route("/apply", web::post().to(api_users_apply)) - .route("/search", web::get().to(||async { "TODO" })) + .route("/search", web::get().to(api_users_search)) .service( web::scope("/once/{username}") .route("/", web::get().to(api_users_info)) .route("/followers", web::get().to(api_users_followed)) .route("/following", web::get().to(api_users_following)) .route("/repos", web::get().to(api_users_repos)) - .route("/starred", web::get().to(||async { "TODO" })) + .route("/starred", web::get().to(api_users_starred)) .route("/subscriptions", web::get().to(||async { "TODO" })) .route("/groups", web::get().to(||async { "TODO" })) .route("/groups/{group_name}/permissions", web::get().to(||async { "TODO" })) @@ -134,13 +138,12 @@ pub fn routes(cfg: &mut web::ServiceConfig){ ) .service( web::scope("/repos") - .route("/search", web::get().to(||async { "TODO" })) + .route("/search", web::get().to(api_repo_search)) .service( web::scope("/{owner}/{repo}") - .route("/", web::get().to(||async { "TODO" })) + .route("/", web::get().to(api_repo_info_get)) .route("/", web::post().to(||async { "TODO" })) .route("/", web::delete().to(||async { "TODO" })) - .route("/", web::patch().to(||async { "TODO" })) .service( web::scope("/avatar") .route("/", web::get().to(||async { "TODO" })) diff --git a/src/api/dto/repo_dto.rs b/src/api/dto/repo_dto.rs index c6cf982..03ffda3 100644 --- a/src/api/dto/repo_dto.rs +++ b/src/api/dto/repo_dto.rs @@ -15,6 +15,17 @@ pub struct RepoCreate{ pub default_branch: String, } +#[derive(Deserialize,Serialize,ToSchema)] +pub struct RepoSearch{ + pub keywords: String, + pub page: u64, + pub size: u64, +} +#[derive(Deserialize,Serialize,ToSchema)] +pub struct RepoInfo{ + pub owner: Uuid, +} + #[derive(Deserialize,Serialize, ToSchema)] pub struct RepoBranchNew{ pub from: String, diff --git a/src/api/handler/mod.rs b/src/api/handler/mod.rs index ec087ab..2bfb0d1 100644 --- a/src/api/handler/mod.rs +++ b/src/api/handler/mod.rs @@ -6,6 +6,7 @@ pub mod health; pub mod user; pub mod users; pub mod groups; +pub mod repos; pub async fn check_session(session: Session) -> anyhow::Result{ match session.get::(SessionModelKey){ diff --git a/src/api/handler/repos/info.rs b/src/api/handler/repos/info.rs new file mode 100644 index 0000000..a2f8e49 --- /dev/null +++ b/src/api/handler/repos/info.rs @@ -0,0 +1,41 @@ +use crate::api::dto::repo_dto::RepoInfo; +use crate::metadata::service::MetaService; +use actix_web::{web, Responder}; +use crate::api::app_write::AppWrite; + + +#[utoipa::path( + get, + tag = "repo", + path = "/api/v1/repo/info", + params( + ("uid" = String, Query, description = "Repo Uid"), + ), + responses( + (status = 200, description = "Success"), + (status = 400, description = "Bad Request") + ) +)] +pub async fn api_repo_info_get( + service: web::Data, + path: web::Path<(String,String)> +) -> impl Responder +{ + let (owner, repo) = path.into_inner(); + let repo_id = match service.repo_service().owner_name_by_uid(owner,repo).await{ + Ok(data) => { + data + } + Err(e) => { + return AppWrite::error(e.to_string()) + } + }; + match service.repo_service().info(repo_id).await{ + Ok(data) => { + AppWrite::ok(data) + } + Err(e) => { + AppWrite::error(e.to_string()) + } + } +} diff --git a/src/api/handler/repos/mod.rs b/src/api/handler/repos/mod.rs new file mode 100644 index 0000000..437b79e --- /dev/null +++ b/src/api/handler/repos/mod.rs @@ -0,0 +1,2 @@ +pub mod search; +pub mod info; \ No newline at end of file diff --git a/src/api/handler/repos/search.rs b/src/api/handler/repos/search.rs new file mode 100644 index 0000000..badd20e --- /dev/null +++ b/src/api/handler/repos/search.rs @@ -0,0 +1,35 @@ +use crate::api::dto::repo_dto::RepoSearch; +use crate::metadata::service::MetaService; +use actix_web::{web, Responder}; +use crate::api::app_write::AppWrite; + +#[utoipa::path( + get, + tag = "search", + path = "/api/v1/search", + params( + ("keywords" = String, Query, description = "Search Keywords"), + ("page" = u64, Query, description = "Page"), + ("size" = u64, Query, description = "Size"), + ), + responses( + (status = 200, description = "Success"), + (status = 400, description = "Bad Request") + ) +)] +pub async fn api_repo_search( + service: web::Data, + query: web::Query +) + -> impl Responder +{ + let (keywords, page, size) = (query.keywords.clone(), query.page, query.size); + match service.repo_service().search(keywords,page,size).await{ + Ok(data) => { + AppWrite::ok(data) + } + Err(e) => { + AppWrite::error(e.to_string()) + } + } +} \ No newline at end of file diff --git a/src/api/handler/users/mod.rs b/src/api/handler/users/mod.rs index a5ae207..4466e64 100644 --- a/src/api/handler/users/mod.rs +++ b/src/api/handler/users/mod.rs @@ -5,4 +5,5 @@ pub mod login; pub mod apply; pub mod reset; pub mod logout; -pub mod info; \ No newline at end of file +pub mod info; +pub mod starred; \ No newline at end of file diff --git a/src/api/handler/users/search.rs b/src/api/handler/users/search.rs index e69de29..db3d4b0 100644 --- a/src/api/handler/users/search.rs +++ b/src/api/handler/users/search.rs @@ -0,0 +1,36 @@ +use actix_web::{web, Responder}; +use crate::api::app_write::AppWrite; +use crate::api::dto::repo_dto::RepoSearch; +use crate::api::dto::user_dto::UserOv; +use crate::metadata::service::MetaService; + +#[utoipa::path( + get, + tag = "users", + path = "/api/v1/users/search", + params( + ("keywords" = String, Query, description = "Search Keywords"), + ("page" = u64, Query, description = "Page"), + ("size" = u64, Query, description = "Size"), + ), + responses( + (status = 200, description = "Success"), + (status = 400, description = "Bad Request") + ) +)] +pub async fn api_users_search( + service: web::Data, + query: web::Query +) + -> impl Responder +{ + let (keywords, page, size) = (query.keywords.clone(), query.page, query.size); + match service.user_service().search(keywords,page,size).await{ + Ok(data) => { + AppWrite::>::ok(data) + } + Err(e) => { + AppWrite::error(e.to_string()) + } + } +} \ No newline at end of file diff --git a/src/api/handler/users/starred.rs b/src/api/handler/users/starred.rs new file mode 100644 index 0000000..59da53e --- /dev/null +++ b/src/api/handler/users/starred.rs @@ -0,0 +1,33 @@ +use actix_web::{web, Responder}; +use crate::api::app_write::AppWrite; +use crate::metadata::service::MetaService; + +#[utoipa::path( + get, + tag = "users", + path = "/api/v1/users/{username}/starred", + responses( + ( status = 200, description = "Success" ), + ( status = 400, description = "Bad Request" ) + ) +)] +pub async fn api_users_starred( + service: web::Data, + path: web::Path +) + -> impl Responder +{ + let username = path.into_inner(); + let uid = match service.user_service().username_to_uid(username).await{ + Ok(uid) => uid, + Err(e) => return AppWrite::error(e.to_string()) + }; + match service.user_service().star(uid).await{ + Ok(data) => { + AppWrite::ok(data) + } + Err(e) => { + AppWrite::error(e.to_string()) + } + } +} \ No newline at end of file diff --git a/src/api/init.rs b/src/api/init.rs index 1416bf9..7e60f2f 100644 --- a/src/api/init.rs +++ b/src/api/init.rs @@ -2,6 +2,7 @@ use actix_web::{web, App, HttpServer}; use actix_web::web::scope; use tracing::info; use crate::api::app_error::Error; +use crate::api::app_routes; use crate::api::handler::version::api_version; use crate::api::middleware::service::ActixServer; use crate::config::{init_config, CFG}; @@ -26,6 +27,7 @@ pub async fn init_api() -> Result<(), Error>{ .service( scope("/api") .route("/version", web::get().to(api_version)) + .configure(app_routes::routes) ) }) .bind(cfg.http.starter())? diff --git a/src/http/config.rs b/src/http/config.rs index 8e347af..6364f86 100644 --- a/src/http/config.rs +++ b/src/http/config.rs @@ -1,4 +1,3 @@ -use actix_web::{HttpRequest, HttpResponse, Responder}; use tracing::info; use crate::ROOT_PATH; diff --git a/src/http/handler.rs b/src/http/handler.rs index 67705c9..8bf761e 100644 --- a/src/http/handler.rs +++ b/src/http/handler.rs @@ -368,6 +368,7 @@ pub async fn objects_pack(http_request: HttpRequest, path: web::Path<(String, St map.insert("Date".to_string(), time.format(&format_description::parse("%a, %d %b %Y %H:%M:%S GMT").unwrap()).unwrap()); map.insert("Expires".to_string(), expires.format(&format_description::parse("%a, %d %b %Y %H:%M:%S GMT").unwrap()).unwrap()); map.insert("Cache-Control".to_string(), "public, max-age=86400".to_string()); + #[allow(unused_assignments)] let mut xtype = "application/x-git-loose-object".to_string(); if url.ends_with(".pack") { xtype = "application/x-git-packed-objects".to_string(); diff --git a/src/metadata/service/repos_service/info.rs b/src/metadata/service/repos_service/info.rs index 1f17a2d..d9c3f25 100644 --- a/src/metadata/service/repos_service/info.rs +++ b/src/metadata/service/repos_service/info.rs @@ -14,4 +14,25 @@ impl RepoService { } Ok(model.unwrap().uid) } + pub async fn search(&self, keyword: String, page: u64, size: u64) -> anyhow::Result>{ + let models = repo::Entity::find() + .filter(repo::Column::Name.contains(keyword.clone())) + .filter(repo::Column::Description.contains(keyword.clone())) + .filter(repo::Column::Topic.contains(keyword)) + .filter(repo::Column::Visible.eq(true)) + .offset(page * size) + .limit(size) + .all(&self.db) + .await?; + Ok(models) + } + pub async fn info(&self, uid: Uuid) -> anyhow::Result{ + let model = repo::Entity::find_by_id(uid) + .one(&self.db) + .await?; + if model.is_none(){ + return Err(anyhow::anyhow!("repo not found")) + } + Ok(model.unwrap()) + } } \ No newline at end of file diff --git a/src/metadata/service/users_service/mod.rs b/src/metadata/service/users_service/mod.rs index 0c2a7ee..9f80bd0 100644 --- a/src/metadata/service/users_service/mod.rs +++ b/src/metadata/service/users_service/mod.rs @@ -19,6 +19,7 @@ pub mod reset; pub mod info; pub mod check; pub mod setting; +pub mod search; #[derive(Clone)] diff --git a/src/metadata/service/users_service/search.rs b/src/metadata/service/users_service/search.rs new file mode 100644 index 0000000..14a961b --- /dev/null +++ b/src/metadata/service/users_service/search.rs @@ -0,0 +1,18 @@ +use crate::api::dto::user_dto::UserOv; +use crate::metadata::model::users::users; +use crate::metadata::service::users_service::UserService; +use sea_orm::*; + +impl UserService { + pub async fn search(&self, keywords: String, page: u64, size: u64) -> anyhow::Result>{ + let models = users::Entity::find() + .filter(users::Column::Username.contains(keywords.clone())) + .filter(users::Column::Name.contains(keywords.clone())) + .filter(users::Column::Description.contains(keywords)) + .offset(page * size) + .limit(size) + .all(&self.db) + .await?; + Ok(models.into_iter().map(|model| UserOv::from(model)).collect()) + } +} \ No newline at end of file diff --git a/src/ssh/handler.rs b/src/ssh/handler.rs index eef5f79..5d95c1c 100644 --- a/src/ssh/handler.rs +++ b/src/ssh/handler.rs @@ -51,8 +51,7 @@ impl SshHandler { Ok(()) } - // Helper to validate and parse the repository path - fn parse_git_command(&self, git_shell_cmd: &str) -> Result<(GitService, String), anyhow::Error> { + async fn parse_git_command(&self, git_shell_cmd: &str) -> Result<(GitService, String), anyhow::Error> { let (service, path) = if let Some(rec_pack_path) = git_shell_cmd.strip_prefix("git-receive-pack ") { (GitService::ReceivePack, strip_apostrophes(rec_pack_path)) } else if let Some(upl_ref_path) = git_shell_cmd.strip_prefix("git-upload-pack ") { @@ -69,14 +68,18 @@ impl SshHandler { return Err(anyhow::anyhow!("Invalid repository path: {path}")); } - let owner = path_segments[0]; - let repo_name = path_segments[1].split('.').next().unwrap_or_default(); + let owner = path_segments[0].to_string(); + let repo_name = path_segments[1].split('.').next().unwrap_or_default().to_string(); if repo_name.is_empty() { return Err(anyhow::anyhow!("Invalid repository name in path: {path}")); } - - Ok((service, format!("{}/{}", owner, repo_name))) + let repo = self.server.repo_service().owner_name_by_uid(owner.clone(), repo_name).await; + if repo.is_err() { + return Err(anyhow::anyhow!("Repository not found: {path}")); + } + let repo_path = repo?.to_string(); + Ok((service, repo_path)) } async fn forward( session_handle: Arc, @@ -148,7 +151,7 @@ impl Handler for SshHandler { let git_shell_cmd = std::str::from_utf8(data).map_err(|_| anyhow::anyhow!("Invalid UTF-8 input"))?; info!("Executing command: {git_shell_cmd}"); - let (service, path) = self.parse_git_command(git_shell_cmd)?; + let (service, path) = self.parse_git_command(git_shell_cmd).await?; let cmd = tokio::process::Command::new("git") .arg(service.to_string())