replace with generated api
This commit is contained in:
parent
77b390575a
commit
81b17abc8a
502
src/admin.rs
502
src/admin.rs
|
@ -1,502 +0,0 @@
|
|||
use super::*;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Write;
|
||||
|
||||
impl Forgejo {
|
||||
pub async fn admin_get_crons(&self, query: CronQuery) -> Result<Vec<Cron>, ForgejoError> {
|
||||
self.get(&query.path()).await
|
||||
}
|
||||
|
||||
pub async fn admin_run_cron(&self, name: &str) -> Result<(), ForgejoError> {
|
||||
self.post_unit(&format!("admin/cron/{name}"), &()).await
|
||||
}
|
||||
|
||||
pub async fn admin_get_emails(
|
||||
&self,
|
||||
query: EmailListQuery,
|
||||
) -> Result<Vec<Email>, ForgejoError> {
|
||||
self.get(&query.path()).await
|
||||
}
|
||||
|
||||
pub async fn admin_search_emails(
|
||||
&self,
|
||||
query: EmailSearchQuery,
|
||||
) -> Result<Vec<Email>, ForgejoError> {
|
||||
self.get(&query.path()).await
|
||||
}
|
||||
|
||||
pub async fn admin_get_hooks(&self, query: HookQuery) -> Result<Vec<Hook>, ForgejoError> {
|
||||
self.get(&query.path()).await
|
||||
}
|
||||
|
||||
pub async fn admin_create_hook(&self, opt: CreateHookOption) -> Result<Hook, ForgejoError> {
|
||||
self.post("admin/hooks", &opt).await
|
||||
}
|
||||
|
||||
pub async fn admin_get_hook(&self, id: u64) -> Result<Option<Hook>, ForgejoError> {
|
||||
self.get_opt(&format!("admin/hooks/{id}")).await
|
||||
}
|
||||
|
||||
pub async fn admin_delete_hook(&self, id: u64) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!("admin/hooks/{id}")).await
|
||||
}
|
||||
|
||||
pub async fn admin_edit_hook(
|
||||
&self,
|
||||
id: u64,
|
||||
opt: EditHookOption,
|
||||
) -> Result<Hook, ForgejoError> {
|
||||
self.patch(&format!("admin/hooks/{id}"), &opt).await
|
||||
}
|
||||
|
||||
pub async fn admin_get_orgs(
|
||||
&self,
|
||||
query: AdminOrganizationQuery,
|
||||
) -> Result<Vec<Organization>, ForgejoError> {
|
||||
self.get(&query.path()).await
|
||||
}
|
||||
|
||||
pub async fn admin_unadopted_repos(
|
||||
&self,
|
||||
query: UnadoptedRepoQuery,
|
||||
) -> Result<Vec<String>, ForgejoError> {
|
||||
self.get(&query.path()).await
|
||||
}
|
||||
|
||||
pub async fn admin_adopt(&self, owner: &str, repo: &str) -> Result<(), ForgejoError> {
|
||||
self.post(&format!("admin/unadopted/{owner}/{repo}"), &())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn admin_delete_unadopted(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!("admin/unadopted/{owner}/{repo}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn admin_users(&self, query: AdminUserQuery) -> Result<Vec<User>, ForgejoError> {
|
||||
self.get(&query.path()).await
|
||||
}
|
||||
|
||||
pub async fn admin_create_user(&self, opt: CreateUserOption) -> Result<User, ForgejoError> {
|
||||
self.post("admin/users", &opt).await
|
||||
}
|
||||
|
||||
pub async fn admin_delete_user(&self, user: &str, purge: bool) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!("admin/users/{user}?purge={purge}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn admin_edit_user(
|
||||
&self,
|
||||
user: &str,
|
||||
opt: CreateUserOption,
|
||||
) -> Result<User, ForgejoError> {
|
||||
self.patch(&format!("admin/users/{user}"), &opt).await
|
||||
}
|
||||
|
||||
pub async fn admin_add_key(
|
||||
&self,
|
||||
user: &str,
|
||||
opt: CreateKeyOption,
|
||||
) -> Result<PublicKey, ForgejoError> {
|
||||
self.post(&format!("admin/users/{user}/keys"), &opt).await
|
||||
}
|
||||
|
||||
pub async fn admin_delete_key(&self, user: &str, id: u64) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!("admin/users/{user}/keys/{id}")).await
|
||||
}
|
||||
|
||||
pub async fn admin_create_org(
|
||||
&self,
|
||||
owner: &str,
|
||||
opt: CreateOrgOption,
|
||||
) -> Result<Organization, ForgejoError> {
|
||||
self.post(&format!("admin/users/{owner}/orgs"), &opt).await
|
||||
}
|
||||
|
||||
pub async fn admin_rename_user(
|
||||
&self,
|
||||
user: &str,
|
||||
opt: RenameUserOption,
|
||||
) -> Result<(), ForgejoError> {
|
||||
self.post_unit(&format!("admin/users/{user}/rename"), &opt)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn admin_create_repo(
|
||||
&self,
|
||||
owner: &str,
|
||||
opt: CreateRepoOption,
|
||||
) -> Result<Repository, ForgejoError> {
|
||||
self.post(&format!("admin/users/{owner}/repos"), &opt).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Cron {
|
||||
pub exec_times: u64,
|
||||
pub name: String,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub next: time::OffsetDateTime,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub prev: time::OffsetDateTime,
|
||||
pub schedule: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct CronQuery {
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl CronQuery {
|
||||
fn path(&self) -> String {
|
||||
let mut s = String::from("admin/cron?");
|
||||
if let Some(page) = self.page {
|
||||
s.push_str("page=");
|
||||
s.write_fmt(format_args!("{page}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(limit) = self.limit {
|
||||
s.push_str("limit=");
|
||||
s.write_fmt(format_args!("{limit}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Email {
|
||||
pub email: String,
|
||||
pub primary: bool,
|
||||
pub user_id: u64,
|
||||
pub username: String,
|
||||
pub verified: bool,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct EmailListQuery {
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl EmailListQuery {
|
||||
fn path(&self) -> String {
|
||||
let mut s = String::from("admin/emails?");
|
||||
if let Some(page) = self.page {
|
||||
s.push_str("page=");
|
||||
s.write_fmt(format_args!("{page}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(limit) = self.limit {
|
||||
s.push_str("limit=");
|
||||
s.write_fmt(format_args!("{limit}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct EmailSearchQuery {
|
||||
pub query: String,
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl EmailSearchQuery {
|
||||
fn path(&self) -> String {
|
||||
let mut s = String::from("admin/emails/search?");
|
||||
if !self.query.is_empty() {
|
||||
s.push_str("q=");
|
||||
s.push_str(&self.query);
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(page) = self.page {
|
||||
s.push_str("page=");
|
||||
s.write_fmt(format_args!("{page}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(limit) = self.limit {
|
||||
s.push_str("limit=");
|
||||
s.write_fmt(format_args!("{limit}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Hook {
|
||||
pub active: bool,
|
||||
pub authorization_header: String,
|
||||
pub branch_filter: String,
|
||||
pub config: std::collections::BTreeMap<String, String>,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created_at: time::OffsetDateTime,
|
||||
pub events: Vec<String>,
|
||||
pub id: u64,
|
||||
#[serde(rename = "type")]
|
||||
pub _type: HookType,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub updated_at: time::OffsetDateTime,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum HookType {
|
||||
Forgejo,
|
||||
Dingtalk,
|
||||
Discord,
|
||||
Gitea,
|
||||
Gogs,
|
||||
Msteams,
|
||||
Slack,
|
||||
Telegram,
|
||||
Feishu,
|
||||
Wechatwork,
|
||||
Packagist,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct HookQuery {
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl HookQuery {
|
||||
fn path(&self) -> String {
|
||||
let mut s = String::from("admin/hooks?");
|
||||
if let Some(page) = self.page {
|
||||
s.push_str("page=");
|
||||
s.write_fmt(format_args!("{page}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(limit) = self.limit {
|
||||
s.push_str("limit=");
|
||||
s.write_fmt(format_args!("{limit}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq)]
|
||||
pub struct CreateHookOption {
|
||||
pub active: Option<bool>,
|
||||
pub authorization_header: Option<String>,
|
||||
pub branch_filter: Option<String>,
|
||||
pub config: CreateHookOptionConfig,
|
||||
pub events: Vec<String>,
|
||||
#[serde(rename = "type")]
|
||||
pub _type: HookType,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq)]
|
||||
pub struct CreateHookOptionConfig {
|
||||
pub content_type: String,
|
||||
pub url: Url,
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct EditHookOption {
|
||||
pub active: Option<bool>,
|
||||
pub authorization_header: Option<String>,
|
||||
pub branch_filter: Option<String>,
|
||||
pub config: Option<BTreeMap<String, String>>,
|
||||
pub events: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct AdminOrganizationQuery {
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl AdminOrganizationQuery {
|
||||
fn path(&self) -> String {
|
||||
let mut s = String::from("admin/orgs?");
|
||||
if let Some(page) = self.page {
|
||||
s.push_str("page=");
|
||||
s.write_fmt(format_args!("{page}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(limit) = self.limit {
|
||||
s.push_str("limit=");
|
||||
s.write_fmt(format_args!("{limit}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct UnadoptedRepoQuery {
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
pub pattern: String,
|
||||
}
|
||||
|
||||
impl UnadoptedRepoQuery {
|
||||
fn path(&self) -> String {
|
||||
let mut s = String::from("admin/unadopted?");
|
||||
if let Some(page) = self.page {
|
||||
s.push_str("page=");
|
||||
s.write_fmt(format_args!("{page}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(limit) = self.limit {
|
||||
s.push_str("limit=");
|
||||
s.write_fmt(format_args!("{limit}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if !self.pattern.is_empty() {
|
||||
s.push_str("pattern=");
|
||||
s.push_str(&self.pattern);
|
||||
s.push('&');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct AdminUserQuery {
|
||||
pub source_id: Option<u64>,
|
||||
pub login_name: String,
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl AdminUserQuery {
|
||||
fn path(&self) -> String {
|
||||
let mut s = String::from("admin/users?");
|
||||
if let Some(source_id) = self.source_id {
|
||||
s.push_str("source_id=");
|
||||
s.write_fmt(format_args!("{source_id}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if !self.login_name.is_empty() {
|
||||
s.push_str("login_name=");
|
||||
s.push_str(&self.login_name);
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(page) = self.page {
|
||||
s.push_str("page=");
|
||||
s.write_fmt(format_args!("{page}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(limit) = self.limit {
|
||||
s.push_str("limit=");
|
||||
s.write_fmt(format_args!("{limit}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq)]
|
||||
pub struct CreateUserOption {
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub created_at: Option<time::OffsetDateTime>,
|
||||
pub email: String,
|
||||
pub full_name: Option<String>,
|
||||
pub login_name: Option<String>,
|
||||
pub must_change_password: bool,
|
||||
pub password: String,
|
||||
pub restricted: bool,
|
||||
pub send_notify: bool,
|
||||
pub source_id: Option<u64>,
|
||||
pub username: String,
|
||||
pub visibility: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct EditUserOption {
|
||||
pub active: Option<bool>,
|
||||
pub admin: Option<bool>,
|
||||
pub allow_create_organization: Option<bool>,
|
||||
pub allow_git_hook: Option<bool>,
|
||||
pub allow_import_local: Option<bool>,
|
||||
pub description: Option<String>,
|
||||
pub email: Option<String>,
|
||||
pub full_name: Option<String>,
|
||||
pub location: Option<String>,
|
||||
pub login_name: Option<String>,
|
||||
pub max_repo_creation: Option<u64>,
|
||||
pub must_change_password: Option<bool>,
|
||||
pub password: Option<String>,
|
||||
pub prohibit_login: Option<bool>,
|
||||
pub restricted: Option<bool>,
|
||||
pub source_id: Option<u64>,
|
||||
pub visibility: Option<String>,
|
||||
pub website: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq)]
|
||||
pub struct CreateKeyOption {
|
||||
pub key: String,
|
||||
pub read_only: Option<bool>,
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct PublicKey {
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created_at: time::OffsetDateTime,
|
||||
pub fingerprint: String,
|
||||
pub id: u64,
|
||||
pub key: String,
|
||||
pub key_type: String,
|
||||
pub read_only: Option<bool>,
|
||||
pub title: String,
|
||||
pub url: Option<Url>,
|
||||
pub user: User,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq)]
|
||||
pub struct CreateOrgOption {
|
||||
pub description: Option<String>,
|
||||
pub full_name: Option<String>,
|
||||
pub location: Option<String>,
|
||||
pub repo_admin_change_team_access: Option<bool>,
|
||||
pub username: String,
|
||||
pub visibility: OrgVisibility,
|
||||
pub website: Option<Url>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum OrgVisibility {
|
||||
Public,
|
||||
Limited,
|
||||
Private,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq)]
|
||||
pub struct RenameUserOption {
|
||||
pub new_username: String,
|
||||
}
|
12253
src/generated.rs
Normal file
12253
src/generated.rs
Normal file
File diff suppressed because it is too large
Load diff
347
src/issue.rs
347
src/issue.rs
|
@ -1,347 +0,0 @@
|
|||
use super::*;
|
||||
|
||||
impl Forgejo {
|
||||
pub async fn get_repo_issues(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
query: IssueQuery,
|
||||
) -> Result<Vec<Issue>, ForgejoError> {
|
||||
self.get(&query.to_string(owner, repo)).await
|
||||
}
|
||||
|
||||
pub async fn create_issue(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
opts: CreateIssueOption,
|
||||
) -> Result<Issue, ForgejoError> {
|
||||
self.post(&format!("repos/{owner}/{repo}/issues"), &opts)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_issue(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
id: u64,
|
||||
) -> Result<Option<Issue>, ForgejoError> {
|
||||
self.get_opt(&format!("repos/{owner}/{repo}/issues/{id}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_issue(&self, owner: &str, repo: &str, id: u64) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!("repos/{owner}/{repo}/issues/{id}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn edit_issue(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
id: u64,
|
||||
opts: EditIssueOption,
|
||||
) -> Result<Issue, ForgejoError> {
|
||||
self.patch(&format!("repos/{owner}/{repo}/issues/{id}"), &opts)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_repo_comments(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
query: RepoCommentQuery,
|
||||
) -> Result<Vec<Comment>, ForgejoError> {
|
||||
self.get(&query.to_string(owner, repo)).await
|
||||
}
|
||||
|
||||
pub async fn get_issue_comments(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
issue_id: u64,
|
||||
query: IssueCommentQuery,
|
||||
) -> Result<Vec<Comment>, ForgejoError> {
|
||||
self.get(&query.to_string(owner, repo, issue_id)).await
|
||||
}
|
||||
|
||||
pub async fn create_comment(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
issue_id: u64,
|
||||
opts: CreateIssueCommentOption,
|
||||
) -> Result<Comment, ForgejoError> {
|
||||
self.post(
|
||||
&format!("repos/{owner}/{repo}/issues/{issue_id}/comments"),
|
||||
&opts,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_comment(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
id: u64,
|
||||
) -> Result<Option<Comment>, ForgejoError> {
|
||||
self.get_opt(&format!("repos/{owner}/{repo}/issues/comments/{id}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_comment(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
id: u64,
|
||||
) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!("repos/{owner}/{repo}/issues/comments/{id}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn edit_comment(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
id: u64,
|
||||
opts: EditIssueCommentOption,
|
||||
) -> Result<Comment, ForgejoError> {
|
||||
self.patch(&format!("repos/{owner}/{repo}/issues/comments/{id}"), &opts)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Issue {
|
||||
pub assets: Vec<Attachment>,
|
||||
pub assignee: Option<User>,
|
||||
pub assignees: Option<Vec<User>>,
|
||||
pub body: String,
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub closed_at: Option<time::OffsetDateTime>,
|
||||
pub comments: u64,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created_at: time::OffsetDateTime,
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub due_date: Option<time::OffsetDateTime>,
|
||||
pub html_url: Url,
|
||||
pub id: u64,
|
||||
pub is_locked: bool,
|
||||
pub labels: Vec<Label>,
|
||||
pub milestone: Option<Milestone>,
|
||||
pub number: u64,
|
||||
pub original_author: String,
|
||||
pub original_author_id: u64,
|
||||
pub pin_order: u64,
|
||||
pub pull_request: Option<PullRequestMeta>,
|
||||
#[serde(rename = "ref")]
|
||||
pub _ref: String,
|
||||
pub repository: RepositoryMeta,
|
||||
pub state: State,
|
||||
pub title: String,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub updated_at: time::OffsetDateTime,
|
||||
pub url: Url,
|
||||
pub user: User,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Label {
|
||||
pub color: String,
|
||||
pub description: String,
|
||||
pub exclusive: bool,
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub url: Url,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Attachment {
|
||||
pub browser_download_url: Url,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created_at: time::OffsetDateTime,
|
||||
pub download_count: u64,
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub size: u64,
|
||||
pub uuid: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct EditAttachmentOption {
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone, Copy)]
|
||||
pub enum State {
|
||||
#[serde(rename = "open")]
|
||||
Open,
|
||||
#[serde(rename = "closed")]
|
||||
Closed,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub(crate) fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
State::Open => "open",
|
||||
State::Closed => "closed",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Comment {
|
||||
pub assets: Vec<Attachment>,
|
||||
pub body: String,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created_at: time::OffsetDateTime,
|
||||
pub html_url: Url,
|
||||
pub id: u64,
|
||||
pub issue_url: Url,
|
||||
pub original_author: String,
|
||||
pub original_author_id: u64,
|
||||
#[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,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct IssueQuery {
|
||||
pub state: Option<State>,
|
||||
pub labels: Vec<String>,
|
||||
pub query: Option<String>,
|
||||
pub _type: Option<IssueQueryType>,
|
||||
pub milestones: Vec<String>,
|
||||
pub since: Option<time::OffsetDateTime>,
|
||||
pub before: Option<time::OffsetDateTime>,
|
||||
pub created_by: Option<String>,
|
||||
pub assigned_by: Option<String>,
|
||||
pub mentioned_by: Option<String>,
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl IssueQuery {
|
||||
fn to_string(&self, owner: &str, repo: &str) -> String {
|
||||
format!("repos/{owner}/{repo}/issues?state={}&labels={}&q={}&type={}&milestones={}&since={}&before={}&created_by={}&assigned_by={}&mentioned_by={}&page={}&limit={}",
|
||||
self.state.map(|s| s.as_str()).unwrap_or_default(),
|
||||
self.labels.join(","),
|
||||
self.query.as_deref().unwrap_or_default(),
|
||||
self._type.map(|t| t.as_str()).unwrap_or_default(),
|
||||
self.milestones.join(","),
|
||||
self.since.map(|t| t.format(&time::format_description::well_known::Rfc3339).unwrap()).unwrap_or_default(),
|
||||
self.before.map(|t| t.format(&time::format_description::well_known::Rfc3339).unwrap()).unwrap_or_default(),
|
||||
self.created_by.as_deref().unwrap_or_default(),
|
||||
self.assigned_by.as_deref().unwrap_or_default(),
|
||||
self.mentioned_by.as_deref().unwrap_or_default(),
|
||||
self.page.map(|page| page.to_string()).unwrap_or_default(),
|
||||
self.limit.map(|page| page.to_string()).unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum IssueQueryType {
|
||||
Issues,
|
||||
Pulls,
|
||||
}
|
||||
|
||||
impl IssueQueryType {
|
||||
fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
IssueQueryType::Issues => "issues",
|
||||
IssueQueryType::Pulls => "pulls",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct IssueCommentQuery {
|
||||
pub since: Option<time::OffsetDateTime>,
|
||||
pub before: Option<time::OffsetDateTime>,
|
||||
}
|
||||
|
||||
impl IssueCommentQuery {
|
||||
fn to_string(&self, owner: &str, repo: &str, issue_id: u64) -> String {
|
||||
format!(
|
||||
"repos/{owner}/{repo}/issues/{issue_id}/comments?since={}&before={}",
|
||||
self.since
|
||||
.map(|t| t
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap())
|
||||
.unwrap_or_default(),
|
||||
self.before
|
||||
.map(|t| t
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap())
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct RepoCommentQuery {
|
||||
pub since: Option<time::OffsetDateTime>,
|
||||
pub before: Option<time::OffsetDateTime>,
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl RepoCommentQuery {
|
||||
fn to_string(&self, owner: &str, repo: &str) -> String {
|
||||
format!(
|
||||
"repos/{owner}/{repo}/issues/comments?since={}&before={}&page={}&limit={}",
|
||||
self.since
|
||||
.map(|t| t
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap())
|
||||
.unwrap_or_default(),
|
||||
self.before
|
||||
.map(|t| t
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap())
|
||||
.unwrap_or_default(),
|
||||
self.page.map(|page| page.to_string()).unwrap_or_default(),
|
||||
self.limit.map(|page| page.to_string()).unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct CreateIssueOption {
|
||||
pub assignees: Vec<String>,
|
||||
pub body: Option<String>,
|
||||
pub closed: Option<bool>,
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub due_date: Option<time::OffsetDateTime>,
|
||||
pub labels: Vec<u64>,
|
||||
pub milestone: Option<u64>,
|
||||
pub _ref: Option<String>,
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct EditIssueOption {
|
||||
pub assignees: Vec<String>,
|
||||
pub body: Option<String>,
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub due_date: Option<time::OffsetDateTime>,
|
||||
pub labels: Vec<u64>,
|
||||
pub milestone: Option<u64>,
|
||||
pub _ref: Option<String>,
|
||||
pub state: Option<State>,
|
||||
pub title: Option<String>,
|
||||
pub unset_due_date: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct CreateIssueCommentOption {
|
||||
pub body: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct EditIssueCommentOption {
|
||||
pub body: String,
|
||||
}
|
220
src/lib.rs
220
src/lib.rs
|
@ -1,5 +1,4 @@
|
|||
use reqwest::{Client, Request, StatusCode};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use soft_assert::*;
|
||||
use url::Url;
|
||||
use zeroize::Zeroize;
|
||||
|
@ -9,23 +8,9 @@ pub struct Forgejo {
|
|||
client: Client,
|
||||
}
|
||||
|
||||
mod admin;
|
||||
mod issue;
|
||||
mod misc;
|
||||
mod notification;
|
||||
mod organization;
|
||||
mod package;
|
||||
mod repository;
|
||||
mod user;
|
||||
mod generated;
|
||||
|
||||
pub use admin::*;
|
||||
pub use issue::*;
|
||||
pub use misc::*;
|
||||
pub use notification::*;
|
||||
pub use organization::*;
|
||||
pub use package::*;
|
||||
pub use repository::*;
|
||||
pub use user::*;
|
||||
pub use generated::structs;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum ForgejoError {
|
||||
|
@ -134,202 +119,35 @@ impl Forgejo {
|
|||
Ok(Self { url, client })
|
||||
}
|
||||
|
||||
async fn get<T: DeserializeOwned>(&self, path: &str) -> Result<T, ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.get(url).build()?;
|
||||
self.execute(request).await
|
||||
fn get(&self, path: &str) -> reqwest::RequestBuilder {
|
||||
let url = self.url.join("api/v1").unwrap().join(path).unwrap();
|
||||
self.client.get(url)
|
||||
}
|
||||
|
||||
async fn get_opt<T: DeserializeOwned>(&self, path: &str) -> Result<Option<T>, ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.get(url).build()?;
|
||||
self.execute_opt(request).await
|
||||
fn put(&self, path: &str) -> reqwest::RequestBuilder {
|
||||
let url = self.url.join("api/v1").unwrap().join(path).unwrap();
|
||||
self.client.put(url)
|
||||
}
|
||||
|
||||
async fn get_str(&self, path: &str) -> Result<String, ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.get(url).build()?;
|
||||
self.execute_str(request).await
|
||||
fn post(&self, path: &str) -> reqwest::RequestBuilder {
|
||||
let url = self.url.join("api/v1").unwrap().join(path).unwrap();
|
||||
self.client.post(url)
|
||||
}
|
||||
|
||||
async fn get_exists(&self, path: &str) -> Result<bool, ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.get(url).build()?;
|
||||
self.execute_exists(request).await
|
||||
fn delete(&self, path: &str) -> reqwest::RequestBuilder {
|
||||
let url = self.url.join("api/v1").unwrap().join(path).unwrap();
|
||||
self.client.post(url)
|
||||
}
|
||||
|
||||
async fn post<T: Serialize, U: DeserializeOwned>(
|
||||
&self,
|
||||
path: &str,
|
||||
body: &T,
|
||||
) -> Result<U, ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
self.execute(request).await
|
||||
fn patch(&self, path: &str) -> reqwest::RequestBuilder {
|
||||
let url = self.url.join("api/v1").unwrap().join(path).unwrap();
|
||||
self.client.post(url)
|
||||
}
|
||||
|
||||
async fn post_multipart<T: DeserializeOwned>(
|
||||
&self,
|
||||
path: &str,
|
||||
body: reqwest::multipart::Form,
|
||||
) -> Result<T, ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.post(url).multipart(body).build()?;
|
||||
self.execute(request).await
|
||||
}
|
||||
|
||||
async fn post_str_out<T: Serialize>(
|
||||
&self,
|
||||
path: &str,
|
||||
body: &T,
|
||||
) -> Result<String, ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
self.execute_str(request).await
|
||||
}
|
||||
|
||||
async fn post_unit<T: Serialize>(&self, path: &str, body: &T) -> Result<(), ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.post(url).json(body).build()?;
|
||||
self.execute_unit(request).await
|
||||
}
|
||||
|
||||
async fn post_raw(&self, path: &str, body: String) -> Result<String, ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.post(url).body(body).build()?;
|
||||
self.execute_str(request).await
|
||||
}
|
||||
|
||||
async fn delete(&self, path: &str) -> Result<(), ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.delete(url).build()?;
|
||||
self.execute_unit(request).await
|
||||
}
|
||||
|
||||
async fn patch<T: Serialize, U: DeserializeOwned>(
|
||||
&self,
|
||||
path: &str,
|
||||
body: &T,
|
||||
) -> Result<U, ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.patch(url).json(body).build()?;
|
||||
self.execute(request).await
|
||||
}
|
||||
|
||||
async fn put<T: DeserializeOwned>(&self, path: &str) -> Result<T, ForgejoError> {
|
||||
let url = self.url.join("api/v1/").unwrap().join(path).unwrap();
|
||||
let request = self.client.put(url).build()?;
|
||||
self.execute(request).await
|
||||
}
|
||||
|
||||
async fn execute<T: DeserializeOwned>(&self, request: Request) -> Result<T, ForgejoError> {
|
||||
async fn execute(&self, request: Request) -> Result<reqwest::Response, ForgejoError> {
|
||||
let response = self.client.execute(request).await?;
|
||||
match response.status() {
|
||||
status if status.is_success() => {
|
||||
let body = response.text().await?;
|
||||
let out =
|
||||
serde_json::from_str(&body).map_err(|e| ForgejoError::BadStructure(e, body))?;
|
||||
Ok(out)
|
||||
}
|
||||
status if status.is_client_error() => Err(ForgejoError::ApiError(
|
||||
status,
|
||||
response
|
||||
.json::<ErrorMessage>()
|
||||
.await?
|
||||
.message
|
||||
.unwrap_or_else(|| String::from("[no message]")),
|
||||
)),
|
||||
status => Err(ForgejoError::UnexpectedStatusCode(status)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `execute`, but returns a `String`.
|
||||
async fn execute_opt_raw(
|
||||
&self,
|
||||
request: Request,
|
||||
) -> Result<Option<bytes::Bytes>, ForgejoError> {
|
||||
let response = self.client.execute(request).await?;
|
||||
match response.status() {
|
||||
status if status.is_success() => Ok(Some(response.bytes().await?)),
|
||||
StatusCode::NOT_FOUND => Ok(None),
|
||||
status if status.is_client_error() => Err(ForgejoError::ApiError(
|
||||
status,
|
||||
response
|
||||
.json::<ErrorMessage>()
|
||||
.await?
|
||||
.message
|
||||
.unwrap_or_else(|| String::from("[no message]")),
|
||||
)),
|
||||
status => Err(ForgejoError::UnexpectedStatusCode(status)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `execute`, but returns a `String`.
|
||||
async fn execute_str(&self, request: Request) -> Result<String, ForgejoError> {
|
||||
let response = self.client.execute(request).await?;
|
||||
match response.status() {
|
||||
status if status.is_success() => Ok(response.text().await?),
|
||||
status if status.is_client_error() => Err(ForgejoError::ApiError(
|
||||
status,
|
||||
response
|
||||
.json::<ErrorMessage>()
|
||||
.await?
|
||||
.message
|
||||
.unwrap_or_else(|| String::from("[no message]")),
|
||||
)),
|
||||
status => Err(ForgejoError::UnexpectedStatusCode(status)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `execute`, but returns unit.
|
||||
async fn execute_unit(&self, request: Request) -> Result<(), ForgejoError> {
|
||||
let response = self.client.execute(request).await?;
|
||||
match response.status() {
|
||||
status if status.is_success() => Ok(()),
|
||||
status if status.is_client_error() => Err(ForgejoError::ApiError(
|
||||
status,
|
||||
response
|
||||
.json::<ErrorMessage>()
|
||||
.await?
|
||||
.message
|
||||
.unwrap_or_else(|| String::from("[no message]")),
|
||||
)),
|
||||
status => Err(ForgejoError::UnexpectedStatusCode(status)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `execute`, but returns `Ok(None)` on 404.
|
||||
async fn execute_opt<T: DeserializeOwned>(
|
||||
&self,
|
||||
request: Request,
|
||||
) -> Result<Option<T>, ForgejoError> {
|
||||
let response = self.client.execute(request).await?;
|
||||
match response.status() {
|
||||
status if status.is_success() => {
|
||||
let body = response.text().await?;
|
||||
let out =
|
||||
serde_json::from_str(&body).map_err(|e| ForgejoError::BadStructure(e, body))?;
|
||||
Ok(out)
|
||||
}
|
||||
StatusCode::NOT_FOUND => Ok(None),
|
||||
status if status.is_client_error() => Err(ForgejoError::ApiError(
|
||||
status,
|
||||
response
|
||||
.json::<ErrorMessage>()
|
||||
.await?
|
||||
.message
|
||||
.unwrap_or_else(|| String::from("[no message]")),
|
||||
)),
|
||||
status => Err(ForgejoError::UnexpectedStatusCode(status)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `execute`, but returns `false` on 404.
|
||||
async fn execute_exists(&self, request: Request) -> Result<bool, ForgejoError> {
|
||||
let response = self.client.execute(request).await?;
|
||||
match response.status() {
|
||||
status if status.is_success() => Ok(true),
|
||||
StatusCode::NOT_FOUND => Ok(false),
|
||||
status if status.is_success() => Ok(response),
|
||||
status if status.is_client_error() => Err(ForgejoError::ApiError(
|
||||
status,
|
||||
response
|
||||
|
|
162
src/misc.rs
162
src/misc.rs
|
@ -1,162 +0,0 @@
|
|||
use super::*;
|
||||
|
||||
impl Forgejo {
|
||||
pub async fn get_gitignore_templates(&self) -> Result<Vec<String>, ForgejoError> {
|
||||
self.get("gitignore/templates").await
|
||||
}
|
||||
|
||||
pub async fn get_gitignore_template(
|
||||
&self,
|
||||
name: &str,
|
||||
) -> Result<Option<GitignoreTemplateInfo>, ForgejoError> {
|
||||
self.get_opt(&format!("gitignore/templates/{name}")).await
|
||||
}
|
||||
|
||||
pub async fn get_label_templates(&self) -> Result<Vec<String>, ForgejoError> {
|
||||
self.get("label/templates").await
|
||||
}
|
||||
|
||||
pub async fn get_label_template(&self, name: &str) -> Result<Vec<LabelTemplate>, ForgejoError> {
|
||||
self.get(&format!("label/templates/{name}")).await
|
||||
}
|
||||
|
||||
pub async fn get_licenses(&self) -> Result<Vec<LicenseTemplateListEntry>, ForgejoError> {
|
||||
self.get("licenses").await
|
||||
}
|
||||
|
||||
pub async fn get_license(
|
||||
&self,
|
||||
name: &str,
|
||||
) -> Result<Option<GitignoreTemplateInfo>, ForgejoError> {
|
||||
self.get_opt(&format!("license/{name}")).await
|
||||
}
|
||||
|
||||
pub async fn render_markdown(&self, opt: MarkdownOption) -> Result<String, ForgejoError> {
|
||||
self.post_str_out("markdown", &opt).await
|
||||
}
|
||||
|
||||
pub async fn render_markdown_raw(&self, body: String) -> Result<String, ForgejoError> {
|
||||
self.post_raw("markdown/raw", body).await
|
||||
}
|
||||
|
||||
pub async fn render_markup(&self, opt: MarkupOption) -> Result<String, ForgejoError> {
|
||||
self.post_str_out("markup", &opt).await
|
||||
}
|
||||
|
||||
pub async fn nodeinfo(&self) -> Result<NodeInfo, ForgejoError> {
|
||||
self.get("nodeinfo").await
|
||||
}
|
||||
|
||||
pub async fn signing_key(&self) -> Result<String, ForgejoError> {
|
||||
self.get_str("signing-key.gpg").await
|
||||
}
|
||||
|
||||
pub async fn version(&self) -> Result<ServerVersion, ForgejoError> {
|
||||
self.get("version").await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct GitignoreTemplateInfo {
|
||||
pub name: String,
|
||||
pub source: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct LabelTemplate {
|
||||
pub color: String,
|
||||
pub description: String,
|
||||
pub exclusive: bool,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct LicenseTemplateListEntry {
|
||||
pub key: String,
|
||||
pub name: String,
|
||||
pub url: Url,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct LicenseTemplateInfo {
|
||||
pub body: String,
|
||||
pub implementation: String,
|
||||
pub key: String,
|
||||
pub name: String,
|
||||
pub url: Url,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct MarkdownOption {
|
||||
#[serde(rename = "Context")]
|
||||
pub context: String,
|
||||
#[serde(rename = "Mode")]
|
||||
pub mode: String,
|
||||
#[serde(rename = "Text")]
|
||||
pub text: String,
|
||||
#[serde(rename = "Wiki")]
|
||||
pub wiki: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct MarkupOption {
|
||||
#[serde(rename = "Context")]
|
||||
pub context: String,
|
||||
#[serde(rename = "FilePath")]
|
||||
pub file_path: String,
|
||||
#[serde(rename = "Mode")]
|
||||
pub mode: String,
|
||||
#[serde(rename = "Text")]
|
||||
pub text: String,
|
||||
#[serde(rename = "Wiki")]
|
||||
pub wiki: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct NodeInfo {
|
||||
pub metadata: std::collections::BTreeMap<String, String>,
|
||||
#[serde(rename = "openRegistrations")]
|
||||
pub open_registrations: bool,
|
||||
pub protocols: Vec<String>,
|
||||
pub services: NodeInfoServices,
|
||||
pub software: NodeInfoSoftware,
|
||||
pub usage: NodeInfoUsage,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct NodeInfoServices {
|
||||
pub inbound: Vec<String>,
|
||||
pub outbound: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct NodeInfoSoftware {
|
||||
pub homepage: Url,
|
||||
pub name: String,
|
||||
pub repository: Url,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct NodeInfoUsage {
|
||||
#[serde(rename = "localComments")]
|
||||
pub local_comments: u64,
|
||||
#[serde(rename = "localPosts")]
|
||||
pub local_posts: u64,
|
||||
pub users: NodeInfoUsageUsers,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct NodeInfoUsageUsers {
|
||||
#[serde(rename = "activeHalfYear")]
|
||||
pub active_half_year: u64,
|
||||
#[serde(rename = "activeMonth")]
|
||||
pub active_month: u64,
|
||||
pub total: u64,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct ServerVersion {
|
||||
pub version: String,
|
||||
}
|
|
@ -1,273 +0,0 @@
|
|||
use super::*;
|
||||
|
||||
impl Forgejo {
|
||||
pub async fn notifications(
|
||||
&self,
|
||||
query: NotificationQuery,
|
||||
) -> Result<Vec<NotificationThread>, ForgejoError> {
|
||||
self.get(&format!("notifications?{}", query.query_string()))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn set_notifications_state(
|
||||
&self,
|
||||
query: NotificationPutQuery,
|
||||
) -> Result<Vec<NotificationThread>, ForgejoError> {
|
||||
self.put(&format!("notifications?{}", query.query_string()))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn notification_count(&self) -> Result<Vec<NotificationCount>, ForgejoError> {
|
||||
self.get("notifications/new").await
|
||||
}
|
||||
|
||||
pub async fn get_notification(
|
||||
&self,
|
||||
id: u64,
|
||||
) -> Result<Option<NotificationThread>, ForgejoError> {
|
||||
self.get_opt(&format!("notifications/threads/{id}")).await
|
||||
}
|
||||
|
||||
pub async fn set_notification_state(
|
||||
&self,
|
||||
id: u64,
|
||||
to_status: ToStatus,
|
||||
) -> Result<Option<NotificationThread>, ForgejoError> {
|
||||
self.patch(
|
||||
&format!(
|
||||
"notifications/threads/{id}?to-status={}",
|
||||
to_status.as_str()
|
||||
),
|
||||
&(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_repo_notifications(
|
||||
&self,
|
||||
owner: &str,
|
||||
name: &str,
|
||||
query: NotificationQuery,
|
||||
) -> Result<Vec<NotificationThread>, ForgejoError> {
|
||||
self.get(&format!(
|
||||
"repos/{owner}/{name}/notifications?{}",
|
||||
query.query_string()
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn set_repo_notifications_state(
|
||||
&self,
|
||||
owner: &str,
|
||||
name: &str,
|
||||
query: NotificationPutQuery,
|
||||
) -> Result<Vec<NotificationThread>, ForgejoError> {
|
||||
self.put(&format!(
|
||||
"repos/{owner}/{name}/notifications?{}",
|
||||
query.query_string()
|
||||
))
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NotificationQuery {
|
||||
pub all: bool,
|
||||
pub include_unread: bool,
|
||||
pub include_read: bool,
|
||||
pub include_pinned: bool,
|
||||
pub subject_type: Option<NotificationSubjectType>,
|
||||
pub since: Option<time::OffsetDateTime>,
|
||||
pub before: Option<time::OffsetDateTime>,
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl Default for NotificationQuery {
|
||||
fn default() -> Self {
|
||||
NotificationQuery {
|
||||
all: false,
|
||||
include_unread: true,
|
||||
include_read: false,
|
||||
include_pinned: true,
|
||||
subject_type: None,
|
||||
since: None,
|
||||
before: None,
|
||||
page: None,
|
||||
limit: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NotificationQuery {
|
||||
fn query_string(&self) -> String {
|
||||
use std::fmt::Write;
|
||||
let mut s = String::new();
|
||||
if self.all {
|
||||
s.push_str("all=true&");
|
||||
}
|
||||
if self.include_unread {
|
||||
s.push_str("status-types=unread&");
|
||||
}
|
||||
if self.include_read {
|
||||
s.push_str("status-types=read&");
|
||||
}
|
||||
if self.include_pinned {
|
||||
s.push_str("status-types=pinned&");
|
||||
}
|
||||
if let Some(subject_type) = self.subject_type {
|
||||
s.push_str("subject-type=");
|
||||
s.push_str(subject_type.as_str());
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(since) = &self.since {
|
||||
s.push_str("since=");
|
||||
s.push_str(
|
||||
&since
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap(),
|
||||
);
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(before) = &self.before {
|
||||
s.push_str("before=");
|
||||
s.push_str(
|
||||
&before
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap(),
|
||||
);
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(page) = self.page {
|
||||
s.push_str("page=");
|
||||
s.write_fmt(format_args!("{page}"))
|
||||
.expect("writing to a string never fails");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(limit) = self.limit {
|
||||
s.push_str("limit=");
|
||||
s.write_fmt(format_args!("{limit}"))
|
||||
.expect("writing to a string never fails");
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum NotificationSubjectType {
|
||||
Issue,
|
||||
Pull,
|
||||
Commit,
|
||||
Repository,
|
||||
}
|
||||
|
||||
impl NotificationSubjectType {
|
||||
fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
NotificationSubjectType::Issue => "issue",
|
||||
NotificationSubjectType::Pull => "pull",
|
||||
NotificationSubjectType::Commit => "commit",
|
||||
NotificationSubjectType::Repository => "repository",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct NotificationThread {
|
||||
pub id: u64,
|
||||
pub pinned: bool,
|
||||
pub repository: Repository,
|
||||
pub subject: NotificationSubject,
|
||||
pub unread: bool,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub updated_at: time::OffsetDateTime,
|
||||
pub url: Url,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct NotificationSubject {
|
||||
pub html_url: Url,
|
||||
pub latest_comment_html_url: Url,
|
||||
pub latest_comment_url: Url,
|
||||
pub state: String,
|
||||
pub title: String,
|
||||
#[serde(rename = "type")]
|
||||
pub _type: String,
|
||||
pub url: Url,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NotificationPutQuery {
|
||||
pub last_read_at: Option<time::OffsetDateTime>,
|
||||
pub all: bool,
|
||||
pub include_unread: bool,
|
||||
pub include_read: bool,
|
||||
pub include_pinned: bool,
|
||||
pub to_status: ToStatus,
|
||||
}
|
||||
|
||||
impl Default for NotificationPutQuery {
|
||||
fn default() -> Self {
|
||||
NotificationPutQuery {
|
||||
last_read_at: None,
|
||||
all: false,
|
||||
include_unread: true,
|
||||
include_read: false,
|
||||
include_pinned: false,
|
||||
to_status: ToStatus::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NotificationPutQuery {
|
||||
fn query_string(&self) -> String {
|
||||
let mut s = String::new();
|
||||
if let Some(last_read_at) = &self.last_read_at {
|
||||
s.push_str("since=");
|
||||
s.push_str(
|
||||
&last_read_at
|
||||
.format(&time::format_description::well_known::Rfc3339)
|
||||
.unwrap(),
|
||||
);
|
||||
s.push('&');
|
||||
}
|
||||
if self.all {
|
||||
s.push_str("all=true&");
|
||||
}
|
||||
if self.include_unread {
|
||||
s.push_str("status-types=unread&");
|
||||
}
|
||||
if self.include_read {
|
||||
s.push_str("status-types=read&");
|
||||
}
|
||||
if self.include_pinned {
|
||||
s.push_str("status-types=pinned&");
|
||||
}
|
||||
s.push_str("subject-type=");
|
||||
s.push_str(self.to_status.as_str());
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub enum ToStatus {
|
||||
#[default]
|
||||
Read,
|
||||
Unread,
|
||||
Pinned,
|
||||
}
|
||||
|
||||
impl ToStatus {
|
||||
fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
ToStatus::Read => "read",
|
||||
ToStatus::Unread => "unread",
|
||||
ToStatus::Pinned => "pinned",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct NotificationCount {
|
||||
pub new: u64,
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
use crate::*;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[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>,
|
||||
}
|
174
src/package.rs
174
src/package.rs
|
@ -1,174 +0,0 @@
|
|||
use std::fmt::Write;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl Forgejo {
|
||||
pub async fn get_user_packages(
|
||||
&self,
|
||||
owner: &str,
|
||||
query: PackagesQuery,
|
||||
) -> Result<Vec<Package>, ForgejoError> {
|
||||
self.get(&query.path(owner)).await
|
||||
}
|
||||
|
||||
pub async fn get_package(
|
||||
&self,
|
||||
owner: &str,
|
||||
_type: PackageType,
|
||||
name: &str,
|
||||
version: &str,
|
||||
) -> Result<Option<Package>, ForgejoError> {
|
||||
self.get_opt(&format!(
|
||||
"packages/{owner}/{}/{name}/{version}",
|
||||
_type.as_str()
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_package(
|
||||
&self,
|
||||
owner: &str,
|
||||
_type: PackageType,
|
||||
name: &str,
|
||||
version: &str,
|
||||
) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!(
|
||||
"packages/{owner}/{}/{name}/{version}",
|
||||
_type.as_str()
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_package_files(
|
||||
&self,
|
||||
owner: &str,
|
||||
_type: PackageType,
|
||||
name: &str,
|
||||
version: &str,
|
||||
) -> Result<Vec<PackageFile>, ForgejoError> {
|
||||
self.get(&format!(
|
||||
"packages/{owner}/{}/{name}/{version}",
|
||||
_type.as_str()
|
||||
))
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct PackagesQuery {
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
pub kind: Option<PackageType>,
|
||||
pub query: String,
|
||||
}
|
||||
|
||||
impl PackagesQuery {
|
||||
fn path(&self, owner: &str) -> String {
|
||||
let mut s = String::from("packages/");
|
||||
s.push_str(owner);
|
||||
s.push('?');
|
||||
if let Some(page) = self.page {
|
||||
s.push_str("page=");
|
||||
s.write_fmt(format_args!("{page}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(limit) = self.limit {
|
||||
s.push_str("limit=");
|
||||
s.write_fmt(format_args!("{limit}"))
|
||||
.expect("writing to string can't fail");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(kind) = self.kind {
|
||||
s.push_str("type=");
|
||||
s.push_str(kind.as_str());
|
||||
s.push('&');
|
||||
}
|
||||
if !self.query.is_empty() {
|
||||
s.push_str("q=");
|
||||
s.push_str(&self.query);
|
||||
s.push('&');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[non_exhaustive]
|
||||
pub enum PackageType {
|
||||
Alpine,
|
||||
Cargo,
|
||||
Chef,
|
||||
Composer,
|
||||
Conan,
|
||||
Conda,
|
||||
Container,
|
||||
Cran,
|
||||
Debian,
|
||||
Generic,
|
||||
Go,
|
||||
Helm,
|
||||
Maven,
|
||||
Npm,
|
||||
Nuget,
|
||||
Pub,
|
||||
Pypi,
|
||||
Rpm,
|
||||
RubyGems,
|
||||
Swift,
|
||||
Vagrant,
|
||||
}
|
||||
|
||||
impl PackageType {
|
||||
fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
PackageType::Alpine => "alpine",
|
||||
PackageType::Cargo => "cargo",
|
||||
PackageType::Chef => "chef",
|
||||
PackageType::Composer => "composer",
|
||||
PackageType::Conan => "conan",
|
||||
PackageType::Conda => "conda",
|
||||
PackageType::Container => "container",
|
||||
PackageType::Cran => "cran",
|
||||
PackageType::Debian => "debian",
|
||||
PackageType::Generic => "generic",
|
||||
PackageType::Go => "go",
|
||||
PackageType::Helm => "helm",
|
||||
PackageType::Maven => "maven",
|
||||
PackageType::Npm => "npm",
|
||||
PackageType::Nuget => "nuget",
|
||||
PackageType::Pub => "pub",
|
||||
PackageType::Pypi => "pypi",
|
||||
PackageType::Rpm => "rpm",
|
||||
PackageType::RubyGems => "rubygems",
|
||||
PackageType::Swift => "swift",
|
||||
PackageType::Vagrant => "vagrant",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Package {
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created_at: time::OffsetDateTime,
|
||||
pub creator: User,
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub owner: User,
|
||||
pub repository: Option<Repository>,
|
||||
pub _type: PackageType,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct PackageFile {
|
||||
#[serde(rename = "Size")]
|
||||
pub size: u64,
|
||||
pub id: u64,
|
||||
pub md5: String,
|
||||
pub name: String,
|
||||
pub sha1: String,
|
||||
pub sha256: String,
|
||||
pub sha512: String,
|
||||
}
|
|
@ -1,743 +0,0 @@
|
|||
use super::*;
|
||||
|
||||
/// Repository operations.
|
||||
impl Forgejo {
|
||||
/// Gets info about the specified repository.
|
||||
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<Repository, ForgejoError> {
|
||||
self.post("user/repos", &repo).await
|
||||
}
|
||||
|
||||
pub async fn get_pulls(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
query: PullQuery,
|
||||
) -> Result<Vec<PullRequest>, ForgejoError> {
|
||||
self.get(&query.to_string(owner, repo)).await
|
||||
}
|
||||
|
||||
pub async fn create_pr(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
opts: CreatePullRequestOption,
|
||||
) -> Result<PullRequest, ForgejoError> {
|
||||
self.post(&format!("repos/{owner}/{repo}/pulls"), &opts)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn is_merged(&self, owner: &str, repo: &str, pr: u64) -> Result<bool, ForgejoError> {
|
||||
self.get_exists(&format!("repos/{owner}/{repo}/pulls/{pr}/merge"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn merge_pr(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
pr: u64,
|
||||
opts: MergePullRequestOption,
|
||||
) -> Result<(), ForgejoError> {
|
||||
self.post_unit(&format!("repos/{owner}/{repo}/pulls/{pr}/merge"), &opts)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn cancel_merge(&self, owner: &str, repo: &str, pr: u64) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!("repos/{owner}/{repo}/pulls/{pr}/merge"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_releases(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
query: ReleaseQuery,
|
||||
) -> Result<Vec<Release>, ForgejoError> {
|
||||
self.get(&query.to_string(owner, repo)).await
|
||||
}
|
||||
|
||||
pub async fn get_release(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
id: u64,
|
||||
) -> Result<Option<Release>, ForgejoError> {
|
||||
self.get_opt(&format!("repos/{owner}/{repo}/releases/{id}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_release_by_tag(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
tag: &str,
|
||||
) -> Result<Option<Release>, ForgejoError> {
|
||||
self.get_opt(&format!("repos/{owner}/{repo}/releases/tags/{tag}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_release(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
id: u64,
|
||||
) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!("repos/{owner}/{repo}/releases/{id}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_release_by_tag(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
tag: &str,
|
||||
) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!("repos/{owner}/{repo}/releases/tags/{tag}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn edit_release(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
id: u64,
|
||||
opts: EditReleaseOption,
|
||||
) -> Result<Release, ForgejoError> {
|
||||
self.patch(&format!("repos/{owner}/{repo}/releases/{id}"), &opts)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_release_attachments(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
id: u64,
|
||||
) -> Result<Vec<Attachment>, ForgejoError> {
|
||||
self.get(&format!("repos/{owner}/{repo}/releases/{id}/assets"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_release_attachment(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
release_id: u64,
|
||||
attachment_id: u64,
|
||||
) -> Result<Attachment, ForgejoError> {
|
||||
self.get(&format!(
|
||||
"repos/{owner}/{repo}/releases/{release_id}/assets/{attachment_id}"
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_release_attachment(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
id: u64,
|
||||
name: &str,
|
||||
file: Vec<u8>,
|
||||
) -> Result<Attachment, ForgejoError> {
|
||||
self.post_multipart(
|
||||
&format!("repos/{owner}/{repo}/releases/{id}/assets?name={name}"),
|
||||
reqwest::multipart::Form::new().part(
|
||||
"attachment",
|
||||
reqwest::multipart::Part::bytes(file)
|
||||
.file_name("file")
|
||||
.mime_str("*/*")
|
||||
.unwrap(),
|
||||
),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_release_attachment(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
release_id: u64,
|
||||
attachment_id: u64,
|
||||
) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!(
|
||||
"repos/{owner}/{repo}/releases/{release_id}/assets/{attachment_id}"
|
||||
))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn edit_release_attachment(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
release_id: u64,
|
||||
attachment_id: u64,
|
||||
opts: EditAttachmentOption,
|
||||
) -> Result<Attachment, ForgejoError> {
|
||||
self.patch(
|
||||
&format!("repos/{owner}/{repo}/releases/{release_id}/assets/{attachment_id}"),
|
||||
&opts,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create_release(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
opts: CreateReleaseOption,
|
||||
) -> Result<Release, ForgejoError> {
|
||||
self.post(&format!("repos/{owner}/{repo}/releases"), &opts)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn latest_release(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
) -> Result<Option<Release>, ForgejoError> {
|
||||
self.get_opt(&format!("repos/{owner}/{repo}/releases/latest"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn download_zip_archive(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
target: &str,
|
||||
) -> Result<Option<bytes::Bytes>, ForgejoError> {
|
||||
let request = self
|
||||
.client
|
||||
.get(
|
||||
self.url
|
||||
.join(&format!("api/v1/repos/{owner}/{repo}/archive/{target}.zip"))
|
||||
.unwrap(),
|
||||
)
|
||||
.build()?;
|
||||
self.execute_opt_raw(request).await
|
||||
}
|
||||
|
||||
pub async fn download_tarball_archive(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
target: &str,
|
||||
) -> Result<Option<bytes::Bytes>, ForgejoError> {
|
||||
let request = self
|
||||
.client
|
||||
.get(
|
||||
self.url
|
||||
.join(&format!(
|
||||
"api/v1/repos/{owner}/{repo}/archive/{target}.tar.gz"
|
||||
))
|
||||
.unwrap(),
|
||||
)
|
||||
.build()?;
|
||||
self.execute_opt_raw(request).await
|
||||
}
|
||||
|
||||
pub async fn download_release_attachment(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
release: u64,
|
||||
attach: u64,
|
||||
) -> Result<Option<bytes::Bytes>, ForgejoError> {
|
||||
let release = self
|
||||
.get_release_attachment(owner, repo, release, attach)
|
||||
.await?;
|
||||
let request = self.client.get(release.browser_download_url).build()?;
|
||||
self.execute_opt_raw(request).await
|
||||
}
|
||||
|
||||
pub async fn get_tags(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
query: TagQuery,
|
||||
) -> Result<Vec<Tag>, ForgejoError> {
|
||||
self.get(&query.to_string(owner, repo)).await
|
||||
}
|
||||
|
||||
pub async fn create_tag(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
opts: CreateTagOption,
|
||||
) -> Result<Tag, ForgejoError> {
|
||||
self.post(&format!("repos/{owner}/{repo}/tags"), &opts)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_tag(
|
||||
&self,
|
||||
owner: &str,
|
||||
repo: &str,
|
||||
tag: &str,
|
||||
) -> Result<Option<Tag>, ForgejoError> {
|
||||
self.get_opt(&format!("repos/{owner}/{repo}/tags/{tag}"))
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_tag(&self, owner: &str, repo: &str, tag: &str) -> Result<(), ForgejoError> {
|
||||
self.delete(&format!("repos/{owner}/{repo}/tags/{tag}"))
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
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_requests: 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_issues_count: u64,
|
||||
pub open_pr_counter: u64,
|
||||
#[serde(deserialize_with = "crate::none_if_blank_url")]
|
||||
pub original_url: Option<Url>,
|
||||
pub owner: User,
|
||||
pub parent: Option<Box<Repository>>,
|
||||
pub permissions: Permission,
|
||||
pub private: bool,
|
||||
pub release_counter: u64,
|
||||
pub repo_transfer: Option<RepoTransfer>,
|
||||
pub size: u64,
|
||||
pub ssh_url: String,
|
||||
pub stars_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)]
|
||||
pub struct RepositoryMeta {
|
||||
pub full_name: String,
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub owner: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq)]
|
||||
pub struct CreateRepoOption {
|
||||
pub auto_init: bool,
|
||||
pub default_branch: String,
|
||||
pub description: Option<String>,
|
||||
pub gitignores: String,
|
||||
pub issue_labels: String,
|
||||
pub license: String,
|
||||
pub name: String,
|
||||
pub private: bool,
|
||||
pub readme: String,
|
||||
pub template: bool,
|
||||
pub trust_model: TrustModel,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq)]
|
||||
pub enum TrustModel {
|
||||
Default,
|
||||
Collaborator,
|
||||
Committer,
|
||||
#[serde(rename = "collaboratorcommiter")]
|
||||
CollaboratorCommitter,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Milestone {
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub closed_at: Option<time::OffsetDateTime>,
|
||||
pub closed_issues: u64,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created_at: time::OffsetDateTime,
|
||||
pub description: String,
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub due_on: Option<time::OffsetDateTime>,
|
||||
pub id: u64,
|
||||
pub open_issues: u64,
|
||||
pub state: State,
|
||||
pub title: String,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub updated_at: time::OffsetDateTime,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct PullRequest {
|
||||
pub allow_maintainer_edit: bool,
|
||||
pub assignee: User,
|
||||
pub assignees: Vec<User>,
|
||||
pub base: PrBranchInfo,
|
||||
pub body: String,
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub closed_at: Option<time::OffsetDateTime>,
|
||||
pub comments: u64,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created_at: time::OffsetDateTime,
|
||||
pub diff_url: Url,
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub due_date: Option<time::OffsetDateTime>,
|
||||
pub head: PrBranchInfo,
|
||||
pub html_url: Url,
|
||||
pub id: u64,
|
||||
pub is_locked: bool,
|
||||
pub labels: Vec<Label>,
|
||||
pub merge_base: String,
|
||||
pub merge_commit_sha: Option<String>,
|
||||
pub mergeable: bool,
|
||||
pub merged: bool,
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub merged_at: Option<time::OffsetDateTime>,
|
||||
pub merged_by: Option<User>,
|
||||
pub milestone: Option<Milestone>,
|
||||
pub number: u64,
|
||||
pub patch_url: Url,
|
||||
pub pin_order: u64,
|
||||
pub requested_reviewers: Option<Vec<User>>,
|
||||
pub state: State,
|
||||
pub title: String,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub updated_at: time::OffsetDateTime,
|
||||
pub url: Url,
|
||||
pub user: User,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct PrBranchInfo {
|
||||
pub label: String,
|
||||
#[serde(rename = "ref")]
|
||||
pub _ref: String,
|
||||
pub repo: Repository,
|
||||
pub repo_id: u64,
|
||||
pub sha: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct PullRequestMeta {
|
||||
pub merged: bool,
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub merged_at: Option<time::OffsetDateTime>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PullQuery {
|
||||
pub state: Option<State>,
|
||||
pub sort: Option<PullQuerySort>,
|
||||
pub milestone: Option<u64>,
|
||||
pub labels: Vec<u64>,
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl PullQuery {
|
||||
fn to_string(&self, owner: &str, repo: &str) -> String {
|
||||
use std::fmt::Write;
|
||||
// This is different to other query struct serialization because
|
||||
// `labels` is serialized so strangely
|
||||
let mut s = String::new();
|
||||
s.push_str("repos/");
|
||||
s.push_str(owner);
|
||||
s.push('/');
|
||||
s.push_str(repo);
|
||||
s.push_str("/pulls?");
|
||||
if let Some(state) = self.state {
|
||||
s.push_str("state=");
|
||||
s.push_str(state.as_str());
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(sort) = self.sort {
|
||||
s.push_str("sort=");
|
||||
s.push_str(sort.as_str());
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(milestone) = self.milestone {
|
||||
s.push_str("sort=");
|
||||
s.write_fmt(format_args!("{milestone}"))
|
||||
.expect("writing to a string never fails");
|
||||
s.push('&');
|
||||
}
|
||||
for label in &self.labels {
|
||||
s.push_str("labels=");
|
||||
s.write_fmt(format_args!("{label}"))
|
||||
.expect("writing to a string never fails");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(page) = self.page {
|
||||
s.push_str("page=");
|
||||
s.write_fmt(format_args!("{page}"))
|
||||
.expect("writing to a string never fails");
|
||||
s.push('&');
|
||||
}
|
||||
if let Some(limit) = self.limit {
|
||||
s.push_str("limit=");
|
||||
s.write_fmt(format_args!("{limit}"))
|
||||
.expect("writing to a string never fails");
|
||||
s.push('&');
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum PullQuerySort {
|
||||
Oldest,
|
||||
RecentUpdate,
|
||||
LeastUpdate,
|
||||
MostComment,
|
||||
LeastComment,
|
||||
Priority,
|
||||
}
|
||||
|
||||
impl PullQuerySort {
|
||||
fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
PullQuerySort::Oldest => "oldest",
|
||||
PullQuerySort::RecentUpdate => "recentupdate",
|
||||
PullQuerySort::LeastUpdate => "leastupdate",
|
||||
PullQuerySort::MostComment => "mostcomment",
|
||||
PullQuerySort::LeastComment => "leastcomment",
|
||||
PullQuerySort::Priority => "priority",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct CreatePullRequestOption {
|
||||
pub assignee: Option<String>,
|
||||
pub assignees: Vec<String>,
|
||||
pub base: String,
|
||||
pub body: String,
|
||||
#[serde(with = "time::serde::rfc3339::option")]
|
||||
pub due_date: Option<time::OffsetDateTime>,
|
||||
pub head: String,
|
||||
pub labels: Vec<u64>,
|
||||
pub milestone: Option<u64>,
|
||||
pub title: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct MergePullRequestOption {
|
||||
#[serde(rename = "Do")]
|
||||
pub act: MergePrAction,
|
||||
#[serde(rename = "MergeCommitId")]
|
||||
pub merge_commit_id: Option<String>,
|
||||
#[serde(rename = "MergeMessageField")]
|
||||
pub merge_message_field: Option<String>,
|
||||
#[serde(rename = "MergeTitleField")]
|
||||
pub merge_title_field: Option<String>,
|
||||
pub delete_branch_after_merge: Option<bool>,
|
||||
pub force_merge: Option<bool>,
|
||||
pub head_commit_id: Option<String>,
|
||||
pub merge_when_checks_succeed: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub enum MergePrAction {
|
||||
#[serde(rename = "merge")]
|
||||
#[default]
|
||||
Merge,
|
||||
#[serde(rename = "rebase")]
|
||||
Rebase,
|
||||
#[serde(rename = "rebase-merge")]
|
||||
RebaseMerge,
|
||||
#[serde(rename = "squash")]
|
||||
Squash,
|
||||
#[serde(rename = "manually-merged")]
|
||||
ManuallyMerged,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Release {
|
||||
pub assets: Vec<Attachment>,
|
||||
pub author: User,
|
||||
pub body: String,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created_at: time::OffsetDateTime,
|
||||
pub draft: bool,
|
||||
pub html_url: Url,
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub prerelease: bool,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub published_at: time::OffsetDateTime,
|
||||
pub tag_name: String,
|
||||
pub tarball_url: Url,
|
||||
pub target_commitish: String,
|
||||
pub url: Url,
|
||||
pub zipball_url: Url,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct CreateReleaseOption {
|
||||
pub body: String,
|
||||
pub draft: bool,
|
||||
pub name: String,
|
||||
pub prerelease: bool,
|
||||
pub tag_name: String,
|
||||
pub target_commitish: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct EditReleaseOption {
|
||||
pub body: Option<String>,
|
||||
pub draft: Option<bool>,
|
||||
pub name: Option<String>,
|
||||
pub prerelease: Option<bool>,
|
||||
pub tag_name: Option<String>,
|
||||
pub target_commitish: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ReleaseQuery {
|
||||
pub draft: Option<bool>,
|
||||
pub prerelease: Option<bool>,
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl ReleaseQuery {
|
||||
fn to_string(&self, owner: &str, repo: &str) -> String {
|
||||
format!(
|
||||
"repos/{owner}/{repo}/releases?draft={}&pre-release={}&page={}&limit={}",
|
||||
opt_bool_s(self.draft),
|
||||
opt_bool_s(self.prerelease),
|
||||
self.page.map(|page| page.to_string()).unwrap_or_default(),
|
||||
self.limit.map(|page| page.to_string()).unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn opt_bool_s(b: Option<bool>) -> &'static str {
|
||||
match b {
|
||||
Some(true) => "true",
|
||||
Some(false) => "false",
|
||||
None => "",
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct Tag {
|
||||
pub commit: CommitMeta,
|
||||
pub id: String,
|
||||
pub message: String,
|
||||
pub name: String,
|
||||
pub tarball_url: Url,
|
||||
pub zipball_url: Url,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Debug, PartialEq, Default)]
|
||||
pub struct CreateTagOption {
|
||||
pub message: Option<String>,
|
||||
pub tag_name: String,
|
||||
pub target: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct TagQuery {
|
||||
pub page: Option<u32>,
|
||||
pub limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl TagQuery {
|
||||
fn to_string(&self, owner: &str, repo: &str) -> String {
|
||||
format!(
|
||||
"repos/{owner}/{repo}/tags?page={}&limit={}",
|
||||
self.page.map(|page| page.to_string()).unwrap_or_default(),
|
||||
self.limit.map(|page| page.to_string()).unwrap_or_default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct CommitMeta {
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created: time::OffsetDateTime,
|
||||
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>,
|
||||
}
|
59
src/user.rs
59
src/user.rs
|
@ -1,59 +0,0 @@
|
|||
use super::*;
|
||||
|
||||
/// User operations.
|
||||
impl Forgejo {
|
||||
/// Returns info about the authorized user.
|
||||
pub async fn myself(&self) -> Result<User, ForgejoError> {
|
||||
self.get("user").await
|
||||
}
|
||||
|
||||
/// Returns info about the specified user.
|
||||
pub async fn get_user(&self, user: &str) -> Result<Option<User>, ForgejoError> {
|
||||
self.get_opt(&format!("users/{user}/")).await
|
||||
}
|
||||
|
||||
/// Gets the list of users that follow the specified user.
|
||||
pub async fn get_followers(&self, user: &str) -> Result<Option<Vec<User>>, ForgejoError> {
|
||||
self.get_opt(&format!("users/{user}/followers/")).await
|
||||
}
|
||||
|
||||
/// Gets the list of users the specified user is following.
|
||||
pub async fn get_following(&self, user: &str) -> Result<Option<Vec<User>>, ForgejoError> {
|
||||
self.get_opt(&format!("users/{user}/following/")).await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub struct User {
|
||||
pub active: bool,
|
||||
pub avatar_url: Url,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created: time::OffsetDateTime,
|
||||
pub description: String,
|
||||
pub email: String,
|
||||
pub followers_count: u64,
|
||||
pub following_count: u64,
|
||||
pub full_name: String,
|
||||
pub id: u64,
|
||||
pub is_admin: bool,
|
||||
pub language: String,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub last_login: time::OffsetDateTime,
|
||||
pub location: String,
|
||||
pub login: String,
|
||||
pub login_name: String,
|
||||
pub prohibit_login: bool,
|
||||
pub restricted: bool,
|
||||
pub starred_repos_count: u64,
|
||||
pub website: String,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug, PartialEq)]
|
||||
pub enum UserVisibility {
|
||||
#[serde(rename = "public")]
|
||||
Public,
|
||||
#[serde(rename = "limited")]
|
||||
Limited,
|
||||
#[serde(rename = "private")]
|
||||
Private,
|
||||
}
|
Loading…
Reference in a new issue