feat(admin)!: move the admin api to rest and fix its defects (#2515)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-06 15:36:41 +02:00
1 parent a70924d4b0
commit 7f8f09ee51
143 files changed
+15238 -12790

No files matched your search

+176 -216
View File
@@ -7,209 +7,123 @@ use super::types::{BanAvatarResult, BanCheckResult, BulkBanResult};
impl AdminApiClient {
pub async fn ban_email(&self, email: &str) -> ApiResult<()> {
let body = generated_types::BanEmailRequest {
email: generated_types::EmailType::from(email.to_owned()),
};
self.generated()
.add_email_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.create_blocklist_entry(
"email",
generated_types::BanEmailRequest {
email: generated_types::EmailType::from(email.to_owned()),
}
.into(),
)
.await
}
pub async fn unban_email(&self, email: &str) -> ApiResult<()> {
let body = generated_types::BanEmailRequest {
email: generated_types::EmailType::from(email.to_owned()),
};
self.generated()
.remove_email_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.delete_blocklist_entry("email", email, None).await
}
pub async fn check_email_ban(&self, email: &str) -> ApiResult<BanCheckResult> {
let body = generated_types::BanEmailRequest {
email: generated_types::EmailType::from(email.to_owned()),
};
let response = self
.generated()
.check_email_ban_status(&body)
.await
.map_err(|e| self.generated_error(e))?;
self.generated_value(response.into_inner())
self.check_blocklist_entry("email", email, None).await
}
pub async fn ban_ip(&self, ip: &str) -> ApiResult<()> {
let body = generated_types::BanIpRequest { ip: ip.to_owned() };
self.generated()
.add_ip_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.create_blocklist_entry(
"ip",
generated_types::BanIpRequest { ip: ip.to_owned() }.into(),
)
.await
}
pub async fn unban_ip(&self, ip: &str) -> ApiResult<()> {
let body = generated_types::BanIpRequest { ip: ip.to_owned() };
self.generated()
.remove_ip_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.delete_blocklist_entry("ip", ip, None).await
}
pub async fn check_ip_ban(&self, ip: &str) -> ApiResult<BanCheckResult> {
let body = generated_types::BanIpRequest { ip: ip.to_owned() };
let response = self
.generated()
.check_ip_ban_status(&body)
.await
.map_err(|e| self.generated_error(e))?;
self.generated_value(response.into_inner())
self.check_blocklist_entry("ip", ip, None).await
}
pub async fn add_suspicious_email_domain(&self, domain: &str) -> ApiResult<()> {
let body = suspicious_email_domain_request(domain)?;
self.generated()
.add_suspicious_email_domain(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.create_blocklist_entry(
SUSPICIOUS_EMAIL_DOMAIN_LIST,
suspicious_email_domain_request(domain)?.into(),
)
.await
}
pub async fn remove_suspicious_email_domain(&self, domain: &str) -> ApiResult<()> {
let body = suspicious_email_domain_request(domain)?;
self.generated()
.remove_suspicious_email_domain(&body)
self.delete_blocklist_entry(SUSPICIOUS_EMAIL_DOMAIN_LIST, domain, None)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
}
pub async fn check_suspicious_email_domain(&self, domain: &str) -> ApiResult<BanCheckResult> {
let body = suspicious_email_domain_request(domain)?;
let response = self
.generated()
.check_suspicious_email_domain(&body)
self.check_blocklist_entry(SUSPICIOUS_EMAIL_DOMAIN_LIST, domain, None)
.await
.map_err(|e| self.generated_error(e))?;
self.generated_value(response.into_inner())
}
pub async fn ban_phrase(&self, phrase: &str) -> ApiResult<()> {
let body = generated_types::BanPhraseRequest {
phrase: phrase.to_owned(),
};
self.generated()
.add_phrase_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.create_blocklist_entry(
"phrase",
generated_types::BanPhraseRequest {
phrase: phrase.to_owned(),
}
.into(),
)
.await
}
pub async fn unban_phrase(&self, phrase: &str) -> ApiResult<()> {
let body = generated_types::BanPhraseRequest {
phrase: phrase.to_owned(),
};
self.generated()
.remove_phrase_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.delete_blocklist_entry("phrase", phrase, None).await
}
pub async fn check_phrase_ban(&self, phrase: &str) -> ApiResult<BanCheckResult> {
let body = generated_types::BanPhraseRequest {
phrase: phrase.to_owned(),
};
let response = self
.generated()
.check_phrase_ban_status(&body)
.await
.map_err(|e| self.generated_error(e))?;
self.generated_value(response.into_inner())
self.check_blocklist_entry("phrase", phrase, None).await
}
pub async fn ban_url(&self, url: &str) -> ApiResult<()> {
let body = generated_types::BanUrlRequest {
category: None,
notes: None,
severity: None,
source_url: None,
url: url.to_owned(),
};
self.generated()
.add_url_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.create_blocklist_entry(
"url",
generated_types::BanUrlRequest {
category: None,
notes: None,
severity: None,
source_url: None,
url: url.to_owned(),
}
.into(),
)
.await
}
pub async fn unban_url(&self, url: &str) -> ApiResult<()> {
let body = generated_types::UnbanUrlRequest {
url: url.to_owned(),
};
self.generated()
.remove_url_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.delete_blocklist_entry("url", url, None).await
}
pub async fn check_url_ban(&self, url: &str) -> ApiResult<BanCheckResult> {
let body = generated_types::CheckUrlBlocklistRequest {
url: url.to_owned(),
};
let response = self
.generated()
.check_url_ban_status(&body)
.await
.map_err(|e| self.generated_error(e))?;
self.generated_value(response.into_inner())
self.check_blocklist_entry("url", url, None).await
}
pub async fn ban_url_domain(&self, domain: &str, match_subdomains: bool) -> ApiResult<()> {
let body = generated_types::BanUrlDomainRequest {
category: None,
domain: domain.to_owned(),
match_subdomains: Some(match_subdomains),
notes: None,
severity: None,
source_url: None,
};
self.generated()
.add_url_domain_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.create_blocklist_entry(
"url-domain",
generated_types::BanUrlDomainRequest {
category: None,
domain: domain.to_owned(),
match_subdomains: Some(match_subdomains),
notes: None,
severity: None,
source_url: None,
}
.into(),
)
.await
}
pub async fn unban_url_domain(&self, domain: &str) -> ApiResult<()> {
let body = generated_types::UnbanUrlDomainRequest {
domain: domain.to_owned(),
};
self.generated()
.remove_url_domain_ban(&body)
self.delete_blocklist_entry("url-domain", domain, None)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
}
pub async fn check_url_domain_ban(&self, domain: &str) -> ApiResult<BanCheckResult> {
let body = generated_types::BanUrlDomainRequest {
category: None,
domain: domain.to_owned(),
match_subdomains: None,
notes: None,
severity: None,
source_url: None,
};
let response = self
.generated()
.check_url_domain_ban_status(&body)
.await
.map_err(|e| self.generated_error(e))?;
self.generated_value(response.into_inner())
self.check_blocklist_entry("url-domain", domain, None).await
}
pub async fn ban_file_sha(
@@ -217,16 +131,22 @@ impl AdminApiClient {
sha256_hex: &str,
audit_log_reason: Option<&str>,
) -> ApiResult<()> {
let body = generated_types::BanFileShaRequest {
category: None,
content_type: None,
notes: None,
severity: None,
sha256_hex: sha256_hex.to_owned(),
source_url: None,
};
self.post_typed_with_reason::<(), _>("/admin/bans/file-sha/add", &body, audit_log_reason)
.await
let body = generated_types::AdminBlocklistEntryCreateRequest::from(
generated_types::BanFileShaRequest {
category: None,
content_type: None,
notes: None,
severity: None,
sha256_hex: sha256_hex.to_owned(),
source_url: None,
},
);
self.post_void_with_reason(
"/admin/blocklists/file-sha/entries",
Some(&serde_json::to_value(&body).map_err(|e| ApiError::Parse(e.to_string()))?),
audit_log_reason,
)
.await
}
pub async fn unban_file_sha(
@@ -234,23 +154,17 @@ impl AdminApiClient {
sha256_hex: &str,
audit_log_reason: Option<&str>,
) -> ApiResult<()> {
let body = generated_types::UnbanFileShaRequest {
sha256_hex: sha256_hex.to_owned(),
};
self.post_typed_with_reason::<(), _>("/admin/bans/file-sha/remove", &body, audit_log_reason)
.await
self.delete_void_with_reason(
&blocklist_entry_path("file-sha", sha256_hex),
None,
audit_log_reason,
)
.await
}
pub async fn check_file_sha_ban(&self, sha256_hex: &str) -> ApiResult<BanCheckResult> {
let body = generated_types::CheckFileShaRequest {
sha256_hex: sha256_hex.to_owned(),
};
let response = self
.generated()
.check_file_sha_ban_status(&body)
self.check_blocklist_entry("file-sha", sha256_hex, None)
.await
.map_err(|e| self.generated_error(e))?;
self.generated_value(response.into_inner())
}
pub async fn bulk_ban_file_shas(
@@ -261,54 +175,45 @@ impl AdminApiClient {
let body = generated_types::BulkBanFileShasRequest {
sha256_list: sha256_list.to_vec(),
};
self.post_typed_with_reason("/admin/bans/file-sha/bulk-add", &body, audit_log_reason)
.await
self.put_typed_with_reason(
"/admin/blocklists/file-sha/entries",
&body,
audit_log_reason,
)
.await
}
pub async fn ban_avatar_hash(&self, hash_short: &str) -> ApiResult<()> {
let body = generated_types::BanAvatarHashRequest {
category: None,
hashes: vec![hash_short.to_owned()],
notes: None,
reason: None,
severity: None,
source_url: None,
};
self.generated()
.add_avatar_hash_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.create_blocklist_entry(
"avatar-hash",
generated_types::BanAvatarHashRequest {
category: None,
hashes: vec![hash_short.to_owned()],
notes: None,
reason: None,
severity: None,
source_url: None,
}
.into(),
)
.await
}
pub async fn unban_avatar_hash(&self, hash_short: &str) -> ApiResult<()> {
let body = generated_types::CheckAvatarHashRequest {
hashes: vec![hash_short.to_owned()],
};
self.generated()
.remove_avatar_hash_ban(&body)
self.delete_blocklist_entry("avatar-hash", hash_short, None)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
}
pub async fn check_avatar_hash_ban(&self, hash_short: &str) -> ApiResult<BanCheckResult> {
let body = generated_types::CheckAvatarHashRequest {
hashes: vec![hash_short.to_owned()],
};
let response = self
.generated()
.check_avatar_hash_ban_status(&body)
self.check_blocklist_entry("avatar-hash", hash_short, None)
.await
.map_err(|e| self.generated_error(e))?;
self.generated_value(response.into_inner())
}
pub async fn ban_user_avatar(&self, user_id: &str) -> ApiResult<BanAvatarResult> {
let body = generated_types::BanUserAvatarRequest::default();
let response = self
.generated()
.ban_user_avatar(
.ban_admin_user_avatar(
&generated_types::SnowflakeType::from(user_id.to_owned()),
&body,
)
@@ -318,21 +223,16 @@ impl AdminApiClient {
}
pub async fn ban_profile_substring(&self, scope: &str, substring: &str) -> ApiResult<()> {
let body = profile_substring_request(scope, substring)?;
self.generated()
.add_profile_substring_ban(&body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
self.create_blocklist_entry(
PROFILE_SUBSTRING_LIST,
profile_substring_request(scope, substring)?.into(),
)
.await
}
pub async fn unban_profile_substring(&self, scope: &str, substring: &str) -> ApiResult<()> {
let body = profile_substring_request(scope, substring)?;
self.generated()
.remove_profile_substring_ban(&body)
self.delete_blocklist_entry(PROFILE_SUBSTRING_LIST, substring, Some(scope))
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
}
pub async fn check_profile_substring_ban(
@@ -340,16 +240,76 @@ impl AdminApiClient {
scope: &str,
substring: &str,
) -> ApiResult<BanCheckResult> {
let body = profile_substring_request(scope, substring)?;
self.check_blocklist_entry(PROFILE_SUBSTRING_LIST, substring, Some(scope))
.await
}
async fn create_blocklist_entry(
&self,
list_type: &str,
body: generated_types::AdminBlocklistEntryCreateRequest,
) -> ApiResult<()> {
self.generated()
.create_admin_blocklist_entry(list_type, &body)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
}
async fn delete_blocklist_entry(
&self,
list_type: &str,
entry_value: &str,
scope: Option<&str>,
) -> ApiResult<()> {
let scope = scope.map(blocklist_delete_scope).transpose()?;
self.generated()
.delete_admin_blocklist_entry(list_type, entry_value, scope)
.await
.map_err(|e| self.generated_error(e))?;
Ok(())
}
async fn check_blocklist_entry(
&self,
list_type: &str,
entry_value: &str,
scope: Option<&str>,
) -> ApiResult<BanCheckResult> {
let scope = scope.map(blocklist_get_scope).transpose()?;
let response = self
.generated()
.check_profile_substring_ban_status(&body)
.get_admin_blocklist_entry(list_type, entry_value, scope)
.await
.map_err(|e| self.generated_error(e))?;
self.generated_value(response.into_inner())
}
}
const SUSPICIOUS_EMAIL_DOMAIN_LIST: &str = "email-domain-suspicious";
const PROFILE_SUBSTRING_LIST: &str = "profile-substring";
fn blocklist_entry_path(list_type: &str, entry_value: &str) -> String {
format!(
"/admin/blocklists/{}/entries/{}",
urlencoding::encode(list_type),
urlencoding::encode(entry_value)
)
}
fn blocklist_get_scope(scope: &str) -> ApiResult<generated_types::GetAdminBlocklistEntryScope> {
generated_types::GetAdminBlocklistEntryScope::try_from(scope)
.map_err(|e| ApiError::Parse(e.to_string()))
}
fn blocklist_delete_scope(
scope: &str,
) -> ApiResult<generated_types::DeleteAdminBlocklistEntryScope> {
generated_types::DeleteAdminBlocklistEntryScope::try_from(scope)
.map_err(|e| ApiError::Parse(e.to_string()))
}
fn suspicious_email_domain_request(
domain: &str,
) -> ApiResult<generated_types::SuspiciousEmailDomainRequest> {