use std::fmt;
use std::sync::Arc;
use reqwest::Method;
use crate::{Config, Result};
use crate::{
list_opts::{ListOptions, ListResponse},
types::{ApiKey, ApiKeyToken, CreateApiKeyOptions},
};
#[derive(Clone)]
pub struct ApiKeysSvc(pub(crate) Arc<Config>);
impl ApiKeysSvc {
#[maybe_async::maybe_async]
#[allow(clippy::needless_pass_by_value)]
pub async fn create(&self, api_key: CreateApiKeyOptions) -> Result<ApiKeyToken> {
let request = self.0.build(Method::POST, "/api-keys");
let response = self.0.send(request.json(&api_key)).await?;
let content = response.json::<ApiKeyToken>().await?;
Ok(content)
}
#[maybe_async::maybe_async]
#[allow(clippy::needless_pass_by_value)]
pub async fn list<T>(&self, list_opts: ListOptions<T>) -> Result<ListResponse<ApiKey>> {
let request = self.0.build(Method::GET, "/api-keys").query(&list_opts);
let response = self.0.send(request).await?;
let content = response.json::<ListResponse<ApiKey>>().await?;
Ok(content)
}
#[maybe_async::maybe_async]
#[allow(clippy::needless_pass_by_value)]
pub async fn delete(&self, api_key_id: &str) -> Result<()> {
let path = format!("/api-keys/{api_key_id}");
let request = self.0.build(Method::DELETE, &path);
let _response = self.0.send(request).await?;
Ok(())
}
}
impl fmt::Debug for ApiKeysSvc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
#[allow(unreachable_pub)]
pub mod types {
use serde::{Deserialize, Serialize};
use crate::types::DomainId;
crate::define_id_type!(ApiKeyId);
#[must_use]
#[derive(Debug, Clone, Serialize)]
pub struct CreateApiKeyOptions {
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
permission: Option<Permission>,
#[serde(skip_serializing_if = "Option::is_none")]
domain_id: Option<DomainId>,
}
impl CreateApiKeyOptions {
#[inline]
pub fn new(name: &str) -> Self {
Self {
name: name.to_owned(),
permission: None,
domain_id: None,
}
}
#[inline]
pub const fn with_full_access(mut self) -> Self {
self.permission = Some(Permission::FullAccess);
self
}
#[inline]
pub const fn with_sending_access(mut self) -> Self {
self.permission = Some(Permission::SendingAccess);
self
}
#[inline]
pub fn with_domain_access(mut self, domain_id: &DomainId) -> Self {
self.permission = Some(Permission::SendingAccess);
self.domain_id = Some(domain_id.clone());
self
}
}
#[must_use]
#[derive(Debug, Copy, Clone, Serialize)]
pub enum Permission {
#[serde(rename = "full_access")]
FullAccess,
#[serde(rename = "sending_access")]
SendingAccess,
}
#[must_use]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiKeyToken {
pub id: ApiKeyId,
pub token: String,
}
#[must_use]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiKey {
pub id: ApiKeyId,
pub name: String,
pub created_at: String,
pub last_used_at: Option<String>,
}
}
#[cfg(test)]
#[allow(clippy::needless_return)]
mod test {
use crate::list_opts::ListOptions;
use crate::test::{CLIENT, DebugResult};
use crate::types::CreateApiKeyOptions;
#[tokio_shared_rt::test(shared = true)]
#[cfg(not(feature = "blocking"))]
async fn all() -> DebugResult<()> {
let resend = &*CLIENT;
let api_key = "test_";
let request = CreateApiKeyOptions::new(api_key).with_full_access();
let response = resend.api_keys.create(request).await?;
let id = response.id;
let api_keys = resend.api_keys.list(ListOptions::default()).await?;
let api_keys_amt = api_keys.len();
resend.api_keys.delete(&id).await?;
let api_keys = resend.api_keys.list(ListOptions::default()).await?;
assert!(api_keys_amt == api_keys.len() + 1);
Ok(())
}
}