use gotcha_gitea::{ Client, DEFAULT_PAGE_SIZE as PAGE_SIZE, IssueQuery, RepositoryId, api_date, diff, models, }; use crate::{ domain::{ HistoryCommit, HomeData, IssueDetails, IssueDraft, IssueEditorData, IssueFilter, MilestoneDetails, MilestoneDraft, Page, PullDetails, RepositoryData, Server, }, presentation::compact_date, }; pub async fn load_repositories(server: &Server, page: i32) -> Result, String> { let page = client(server)? .owned_repositories_page(page, PAGE_SIZE) .await .map_err(message)?; Ok(Page { has_more: page.has_more, items: page .items .into_iter() .filter_map(|repository| { Some(RepositoryData { owner: repository.owner?.login?, name: repository.name?, description: repository .description .filter(|text| !text.is_empty()) .unwrap_or_else(|| "No description".into()), language: repository .language .filter(|text| !text.is_empty()) .unwrap_or_else(|| "Unknown language".into()), open_issues: repository.open_issues_count.unwrap_or_default(), updated: compact_date(repository.updated_at.as_deref()), default_branch: repository.default_branch.unwrap_or_else(|| "main".into()), }) }) .collect(), }) } pub async fn load_issues( server: &Server, owner: &str, repository: &str, status: &str, filter: &IssueFilter, page: i32, ) -> Result, String> { client(server)? .issues( &scope(owner, repository)?, &IssueQuery { state: status.into(), labels: (!filter.labels.is_empty()) .then(|| filter.labels.iter().cloned().collect::>().join(",")), milestones: (!filter.milestone.is_empty()).then(|| filter.milestone.clone()), keyword: (!filter.search_text.is_empty()).then(|| filter.search_text.clone()), page, limit: PAGE_SIZE, ..Default::default() }, ) .await .map_err(message) } pub async fn load_milestones_page( server: &Server, owner: &str, repository: &str, page: i32, ) -> Result, String> { client(server)? .milestones_page(&scope(owner, repository)?, page, PAGE_SIZE) .await .map_err(message) } pub async fn load_labels( server: &Server, owner: &str, repository: &str, ) -> Result, String> { client(server)? .labels(&scope(owner, repository)?) .await .map_err(message) } pub async fn load_milestones( server: &Server, owner: &str, repository: &str, ) -> Result, String> { client(server)? .milestones(&scope(owner, repository)?) .await .map_err(message) } pub async fn load_milestone( server: &Server, owner: &str, repository: &str, id: i64, page: i32, ) -> Result { client(server)? .milestone_details(&scope(owner, repository)?, id, page) .await .map_err(message) } pub async fn load_milestone_editor( server: &Server, owner: &str, repository: &str, id: i64, ) -> Result { client(server)? .milestone(&scope(owner, repository)?, id) .await .map_err(message) } pub async fn save_milestone( server: &Server, owner: &str, repository: &str, id: Option, draft: MilestoneDraft, ) -> Result { client(server)? .save_milestone( &scope(owner, repository)?, id, gotcha_gitea::MilestoneDraft { title: draft.title, description: draft.description, due_on: draft.due_date.map(api_date), state: if draft.closed { "closed" } else { "open" }.into(), }, ) .await .map_err(message) } pub async fn set_milestone_closed( server: &Server, owner: &str, repository: &str, id: i64, closed: bool, ) -> Result<(), String> { client(server)? .set_milestone_closed(&scope(owner, repository)?, id, closed) .await .map(|_| ()) .map_err(message) } pub async fn delete_milestone( server: &Server, owner: &str, repository: &str, id: i64, ) -> Result<(), String> { client(server)? .delete_milestone(&scope(owner, repository)?, &id.to_string()) .await .map_err(message) } pub async fn load_pulls( server: &Server, status: &str, milestone: &str, search_text: &str, page: i32, ) -> Result, String> { client(server)? .search_pulls( status, (!milestone.is_empty()).then_some(milestone), (!search_text.is_empty()).then_some(search_text), page, PAGE_SIZE, ) .await .map_err(message) } pub async fn load_pull_milestones(server: &Server) -> Result, String> { client(server)?.pull_milestones().await.map_err(message) } pub async fn load_branches( server: &Server, owner: &str, repository: &str, default_branch: &str, ) -> Result, String> { client(server)? .branches(&scope(owner, repository)?, default_branch) .await .map_err(message) } pub async fn load_repository_contents( server: &Server, owner: &str, repository: &str, path: &str, ) -> Result, String> { client(server)? .repository_contents(&scope(owner, repository)?, path) .await .map_err(message) } pub async fn load_repository_file( server: &Server, owner: &str, repository: &str, path: &str, ) -> Result, String> { client(server)? .repository_file(&scope(owner, repository)?, path) .await .map_err(message) } pub async fn load_branch_commits( server: &Server, owner: &str, repository: &str, branch: &str, path: Option<&str>, pages: u32, ) -> Result, String> { client(server)? .branch_history(&scope(owner, repository)?, branch, path, pages) .await .map_err(message) } pub async fn load_all_commits( server: &Server, owner: &str, repository: &str, branches: &[String], path: Option<&str>, pages: u32, ) -> Result, String> { client(server)? .all_history(&scope(owner, repository)?, branches, path, pages) .await .map_err(message) } pub async fn load_issue( server: &Server, owner: &str, repository: &str, number: i64, _page: i32, ) -> Result { client(server)? .issue_details(&scope(owner, repository)?, number) .await .map_err(message) } pub async fn save_issue_comment( server: &Server, owner: &str, repository: &str, number: i64, comment_id: Option, body: String, ) -> Result<(), String> { client(server)? .save_issue_comment(&scope(owner, repository)?, number, comment_id, body) .await .map(|_| ()) .map_err(message) } pub async fn load_issue_editor( server: &Server, owner: &str, repository: &str, number: Option, ) -> Result { client(server)? .issue_editor(&scope(owner, repository)?, number) .await .map_err(message) } pub async fn create_issue( server: &Server, owner: &str, repository: &str, draft: IssueDraft, ) -> Result { client(server)? .create_issue_draft(&scope(owner, repository)?, shared_issue_draft(draft)) .await .map_err(message) } pub async fn edit_issue( server: &Server, owner: &str, repository: &str, number: i64, draft: IssueDraft, ) -> Result { client(server)? .edit_issue_draft( &scope(owner, repository)?, number, shared_issue_draft(draft), ) .await .map_err(message) } pub async fn set_issue_closed( server: &Server, owner: &str, repository: &str, number: i64, closed: bool, ) -> Result<(), String> { client(server)? .set_issue_state( &scope(owner, repository)?, &[number], if closed { "closed" } else { "open" }, ) .await .map(|_| ()) .map_err(message) } pub async fn delete_issue( server: &Server, owner: &str, repository: &str, number: i64, ) -> Result<(), String> { client(server)? .delete_issue(&scope(owner, repository)?, number) .await .map_err(message) } pub async fn load_pull( server: &Server, owner: &str, repository: &str, number: i64, page: i32, ) -> Result { client(server)? .pull_details(&scope(owner, repository)?, number, page) .await .map_err(message) } pub async fn load_commit( server: &Server, owner: &str, repository: &str, sha: &str, ) -> Result { client(server)? .commit(&scope(owner, repository)?, sha) .await .map_err(message) } pub async fn load_commit_diff( server: &Server, owner: &str, repository: &str, sha: &str, path: &str, ) -> Result { let client = client(server)?; let diff = client .commit_diff(&scope(owner, repository)?, sha) .await .map_err(message)?; Ok(diff::parse_file(&diff, path)) } pub async fn load_pull_diff( server: &Server, owner: &str, repository: &str, number: i64, path: &str, ) -> Result { let client = client(server)?; let diff = client .pull_diff(&scope(owner, repository)?, number) .await .map_err(message)?; Ok(diff::parse_file(&diff, path)) } pub async fn load_home( server: &Server, page: i32, filter: gotcha_gitea::ActivityFilter, ) -> Result { client(server)?.home(page, filter).await.map_err(message) } pub async fn load_activities(server: &Server, page: i32) -> Result, String> { client(server)? .activities(page, gotcha_gitea::ActivityFilter::All) .await .map_err(message) } fn client(server: &Server) -> Result { Client::with_provider(&server.url, Some(&server.token), server.provider).map_err(message) } fn scope(owner: &str, repository: &str) -> Result { RepositoryId::new(owner, repository).map_err(message) } fn shared_issue_draft(draft: IssueDraft) -> gotcha_gitea::IssueDraft { gotcha_gitea::IssueDraft { title: draft.title, body: draft.body, label_ids: draft.label_ids, milestone_id: draft.milestone_id, due_date: draft.due_date.map(api_date), closed: draft.closed, } } fn message(error: impl std::fmt::Display) -> String { error.to_string() }