use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::client::Client;
use crate::error::BoxxkiteError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum WebhookEventType {
#[serde(rename = "sandbox.created")]
SandboxCreated,
#[serde(rename = "sandbox.destroyed")]
SandboxDestroyed,
#[serde(rename = "audit_log.entry")]
AuditLogEntry,
}
#[derive(Debug, Clone, Default, Serialize)]
pub struct CreateWebhookOptions {
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
}
impl CreateWebhookOptions {
pub fn new() -> Self {
Self::default()
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct Webhook {
pub id: String,
pub url: String,
pub event_types: Vec<String>,
pub description: Option<String>,
pub is_active: bool,
#[serde(default)]
pub payload_format: String,
pub created_at: String,
pub last_triggered_at: Option<String>,
pub secret: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct WebhookDelivery {
pub id: String,
pub event_type: String,
pub status: String,
pub attempt_count: i64,
pub next_attempt_at: String,
pub last_attempt_at: Option<String>,
pub response_status_code: Option<i32>,
pub failure_reason: Option<String>,
pub created_at: String,
pub delivered_at: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct ListWebhookDeliveriesOptions {
limit: Option<u32>,
offset: Option<u32>,
}
impl ListWebhookDeliveriesOptions {
pub fn new() -> Self {
Self::default()
}
pub fn limit(mut self, limit: u32) -> Self {
self.limit = Some(limit);
self
}
pub fn offset(mut self, offset: u32) -> Self {
self.offset = Some(offset);
self
}
}
impl Client {
pub async fn create_webhook(
&self,
url: &str,
event_types: &[WebhookEventType],
options: CreateWebhookOptions,
) -> Result<Webhook, BoxxkiteError> {
#[derive(Serialize)]
struct Body<'a> {
url: &'a str,
event_types: &'a [WebhookEventType],
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<&'a str>,
}
let body = Body {
url,
event_types,
description: options.description.as_deref(),
};
let builder = self.request(Method::POST, "/v1/webhooks").json(&body);
self.send(builder).await
}
pub async fn list_webhooks(&self) -> Result<Vec<Webhook>, BoxxkiteError> {
let builder = self.request(Method::GET, "/v1/webhooks");
self.send_or_default(builder).await
}
pub async fn delete_webhook(&self, subscription_id: &str) -> Result<(), BoxxkiteError> {
let builder = self.request(Method::DELETE, &format!("/v1/webhooks/{subscription_id}"));
self.send_no_content(builder).await
}
pub async fn list_webhook_deliveries(
&self,
subscription_id: &str,
options: ListWebhookDeliveriesOptions,
) -> Result<Vec<WebhookDelivery>, BoxxkiteError> {
let mut query = Vec::new();
if let Some(limit) = options.limit {
query.push(("limit", limit.to_string()));
}
if let Some(offset) = options.offset {
query.push(("offset", offset.to_string()));
}
let builder = self
.request(
Method::GET,
&format!("/v1/webhooks/{subscription_id}/deliveries"),
)
.query(&query);
self.send_or_default(builder).await
}
}