1
0
Fork 0

Merge pull request 'fill in Repository struct fields' (#14) from full-repo-struct into main

Reviewed-on: https://codeberg.org/Cyborus/forgejo-api/pulls/14
This commit is contained in:
Cyborus 2023-11-19 19:10:14 +00:00
commit 5ea0c4d9f3
4 changed files with 180 additions and 54 deletions

View file

@ -200,61 +200,13 @@ pub struct Comment {
pub issue_url: Url,
pub original_author: String,
pub original_author_id: u64,
#[serde(deserialize_with = "none_if_blank_url")]
#[serde(deserialize_with = "crate::none_if_blank_url")]
pub pull_request_url: Option<Url>,
#[serde(with = "time::serde::rfc3339")]
pub updated_at: time::OffsetDateTime,
pub user: User,
}
fn none_if_blank_url<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Option<Url>, D::Error> {
use serde::de::{Error, Unexpected, Visitor};
use std::fmt;
struct EmptyUrlVisitor;
impl<'de> Visitor<'de> for EmptyUrlVisitor
{
type Value = Option<Url>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("option")
}
#[inline]
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(None)
}
#[inline]
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(None)
}
#[inline]
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: Error,
{
if s.is_empty() {
return Ok(None);
}
Url::parse(s).map_err(|err| {
let err_s = format!("{}", err);
Error::invalid_value(Unexpected::Str(s), &err_s.as_str())
}).map(Some)
}
}
deserializer.deserialize_str(EmptyUrlVisitor)
}
#[derive(Default, Debug)]
pub struct IssueQuery {
pub state: Option<State>,

View file

@ -8,10 +8,12 @@ pub struct Forgejo {
client: Client,
}
mod organization;
mod issue;
mod repository;
mod user;
pub use organization::*;
pub use issue::*;
pub use repository::*;
pub use user::*;
@ -156,3 +158,54 @@ struct ErrorMessage {
// intentionally ignored, no need for now
// url: Url
}
// Forgejo can return blank strings for URLs. This handles that by deserializing
// that as `None`
fn none_if_blank_url<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Option<Url>, D::Error> {
use serde::de::{Error, Unexpected, Visitor};
use std::fmt;
struct EmptyUrlVisitor;
impl<'de> Visitor<'de> for EmptyUrlVisitor
{
type Value = Option<Url>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("option")
}
#[inline]
fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(None)
}
#[inline]
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(None)
}
#[inline]
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: Error,
{
if s.is_empty() {
return Ok(None);
}
Url::parse(s).map_err(|err| {
let err_s = format!("{}", err);
Error::invalid_value(Unexpected::Str(s), &err_s.as_str())
}).map(Some)
}
}
deserializer.deserialize_str(EmptyUrlVisitor)
}

30
src/organization.rs Normal file
View file

@ -0,0 +1,30 @@
use std::collections::BTreeMap;
use crate::*;
#[derive(serde::Deserialize, Debug, PartialEq)]
pub struct Organization {
#[serde(deserialize_with = "crate::none_if_blank_url")]
pub avatar_url: Option<Url>,
pub description: String,
pub full_name: String,
pub id: u64,
pub location: Option<String>,
pub name: String,
pub repo_admin_change_team_access: bool,
pub visibility: String,
#[serde(deserialize_with = "crate::none_if_blank_url")]
pub website: Option<Url>,
}
#[derive(serde::Deserialize, Debug, PartialEq)]
pub struct Team {
pub can_create_org_repo: bool,
pub description: String,
pub id: u64,
pub includes_all_repositories: bool,
pub name: String,
pub organization: Organization,
pub permission: String,
pub units: Vec<String>,
pub units_map: BTreeMap<String, String>,
}

View file

@ -3,12 +3,12 @@ use super::*;
/// Repository operations.
impl Forgejo {
/// Gets info about the specified repository.
pub async fn get_repo(&self, user: &str, repo: &str) -> Result<Option<Repo>, ForgejoError> {
pub async fn get_repo(&self, user: &str, repo: &str) -> Result<Option<Repository>, ForgejoError> {
self.get_opt(&format!("repos/{user}/{repo}/")).await
}
/// Creates a repository.
pub async fn create_repo(&self, repo: CreateRepoOption) -> Result<Repo, ForgejoError> {
pub async fn create_repo(&self, repo: CreateRepoOption) -> Result<Repository, ForgejoError> {
self.post("user/repos", &repo).await
}
@ -216,17 +216,68 @@ impl Forgejo {
}
#[derive(serde::Deserialize, Debug, PartialEq)]
pub struct Repo {
pub struct Repository {
pub allow_merge_commits: bool,
pub allow_rebase: bool,
pub allow_rebase_explicit: bool,
pub allow_rebase_update: bool,
pub allow_squash_merge: bool,
pub archived: bool,
#[serde(with = "time::serde::rfc3339::option")]
pub archived_at: Option<time::OffsetDateTime>,
#[serde(deserialize_with = "crate::none_if_blank_url")]
pub avatar_url: Option<Url>,
pub clone_url: Url,
#[serde(with = "time::serde::rfc3339")]
pub created_at: time::OffsetDateTime,
pub default_allow_maintainer_edit: bool,
pub default_branch: String,
pub default_delete_branch_after_merge: bool,
pub default_merge_style: String,
pub description: String,
pub empty: bool,
pub external_tracker: Option<ExternalTracker>,
pub external_wiki: Option<ExternalWiki>,
pub fork: bool,
pub forks_count: u64,
pub full_name: String,
pub has_actions: bool,
pub has_issues: bool,
pub has_packages: bool,
pub has_projects: bool,
pub has_pull_request: bool,
pub has_releases: bool,
pub has_wiki: bool,
pub html_url: Url,
pub id: u64,
pub ignore_whitespace_conflicts: bool,
pub internal: bool,
pub internal_tracker: Option<InternalTracker>,
pub language: String,
pub languages_url: Url,
pub link: String,
pub mirror: bool,
pub mirror_interval: Option<String>,
#[serde(with = "time::serde::rfc3339::option")]
pub mirror_updated: Option<time::OffsetDateTime>,
pub name: String,
pub open_issue_count: u64,
pub open_pr_counter: u64,
pub original_url: Url,
pub owner: User,
pub permissions: Permission,
pub private: bool,
pub release_counter: u64,
pub repo_transfer: Option<RepoTransfer>,
pub size: u64,
pub ssh_url: Url,
pub starts_count: u64,
pub template: bool,
#[serde(with = "time::serde::rfc3339")]
pub updated_at: time::OffsetDateTime,
pub url: Url,
pub watchers_count: u64,
pub website: Option<String>,
}
#[derive(serde::Deserialize, Debug, PartialEq)]
@ -324,7 +375,7 @@ pub struct PrBranchInfo {
pub label: String,
#[serde(rename = "ref")]
pub _ref: String,
pub repo: Repo,
pub repo: Repository,
pub repo_id: u64,
pub sha: String,
}
@ -571,3 +622,43 @@ pub struct CommitMeta {
pub url: Url,
pub sha: String,
}
#[derive(serde::Deserialize, Debug, PartialEq)]
pub struct ExternalTracker {
#[serde(rename = "external_tracker_format")]
pub format: String,
#[serde(rename = "external_tracker_regexp_pattern")]
pub regexp_pattern: String,
#[serde(rename = "external_tracker_style")]
pub style: String,
#[serde(rename = "external_tracker_url")]
pub url: Url,
}
#[derive(serde::Deserialize, Debug, PartialEq)]
pub struct InternalTracker {
pub allow_only_contributors_to_track_time: bool,
pub enable_issue_dependencies: bool,
pub enable_time_tracker: bool,
}
#[derive(serde::Deserialize, Debug, PartialEq)]
pub struct ExternalWiki {
#[serde(rename = "external_wiki_url")]
pub url: Url,
}
#[derive(serde::Deserialize, Debug, PartialEq)]
pub struct Permission {
pub admin: bool,
pub pull: bool,
pub push: bool,
}
#[derive(serde::Deserialize, Debug, PartialEq)]
pub struct RepoTransfer {
pub doer: User,
pub recipient: User,
pub teams: Vec<Team>,
}