use serde::{Deserialize, Serialize}; use session::Session; use utoipa::ToSchema; use crate::{AppService, error::AppError}; #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] pub struct ReadmeDto { pub content: String, pub html: String, } impl AppService { pub async fn git_repo_readme( &self, ctx: &Session, wk_name: &str, repo_name: &str, ) -> Result, AppError> { let repo = self.git_require_member(ctx, wk_name, repo_name).await?; let readme_names = [ "README.md", "README.markdown", "README.txt", "README", "Readme.md", "readme.md", ]; for name in &readme_names { match self .git_tree_entry_by_path_from_commit_for_readme( &repo.id, name, ) .await? { Some((content, oid)) => { return self .git_blob_load_for_readme( &repo, &content, &oid, ) .await; } None => continue, } } Ok(None) } } impl AppService { async fn git_tree_entry_by_path_from_commit_for_readme( &self, repo_id: &uuid::Uuid, readme_name: &str, ) -> Result, AppError> { use git::rpc::proto as p; use git::rpc::proto::tree_service_client::TreeServiceClient; use crate::git::rpc_err; let mut client = TreeServiceClient::new(self.git.clone()); let mut commit_client = git::rpc::proto::commit_service_client::CommitServiceClient::new(self.git.clone()); let summary_resp = commit_client .commit_summary(tonic::Request::new(p::CommitSummaryRequest { repo_id: repo_id.to_string(), })) .await .map_err(rpc_err)? .into_inner(); let head_commit = match summary_resp.summary.and_then(|s| s.head) { Some(c) => c, None => return Ok(None), }; let tree_id = match head_commit.tree_id { Some(id) => id.value, None => return Ok(None), }; let resp = client .tree_entry_by_path(tonic::Request::new(p::TreeEntryByPathRequest { repo_id: repo_id.to_string(), tree_oid: Some(p::ObjectId { value: tree_id.clone() }), path: readme_name.to_string(), })) .await .map_err(rpc_err)? .into_inner(); match resp.entry { Some(entry) => { let oid = entry.oid.map(|o| o.value).unwrap_or_default(); if oid.is_empty() { Ok(None) } else { Ok(Some((readme_name.to_string(), oid))) } } None => Ok(None), } } async fn git_blob_load_for_readme( &self, repo: &model::repos::RepoModel, _path: &str, oid: &str, ) -> Result, AppError> { use git::rpc::proto as p; use git::rpc::proto::blob_service_client::BlobServiceClient; use crate::git::rpc_err; let mut client = BlobServiceClient::new(self.git.clone()); let resp = client .blob_load(tonic::Request::new(p::BlobLoadRequest { repo_id: repo.id.to_string(), id: Some(p::ObjectId { value: oid.to_string() }), path: String::new(), })) .await .map_err(rpc_err)? .into_inner(); let content = String::from_utf8_lossy(&resp.blob).to_string(); if content.is_empty() { return Ok(None); } let html = comrak::markdown_to_html(&content, &comrak::ComrakOptions::default()); Ok(Some(super::readme::ReadmeDto { content, html, })) } }