From 34590297c1fa31ef8fe1c5fb5628a02d110078e3 Mon Sep 17 00:00:00 2001 From: Mubelotix Date: Thu, 31 Jul 2025 12:53:57 +0200 Subject: [PATCH] Add patch webhook endpoint --- crates/meilisearch/src/routes/webhooks.rs | 53 ++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/crates/meilisearch/src/routes/webhooks.rs b/crates/meilisearch/src/routes/webhooks.rs index 15b3145d0..4b925c325 100644 --- a/crates/meilisearch/src/routes/webhooks.rs +++ b/crates/meilisearch/src/routes/webhooks.rs @@ -23,7 +23,7 @@ use crate::extractors::sequential_extractor::SeqHandler; #[derive(OpenApi)] #[openapi( - paths(get_webhooks, patch_webhooks, get_webhook, post_webhook, delete_webhook), + paths(get_webhooks, patch_webhooks, get_webhook, post_webhook, patch_webhook, delete_webhook), tags(( name = "Webhooks", description = "The `/webhooks` route allows you to register endpoints to be called once tasks are processed.", @@ -42,6 +42,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { .service( web::resource("/{uuid}") .route(web::get().to(get_webhook)) + .route(web::patch().to(SeqHandler(patch_webhook))) .route(web::delete().to(SeqHandler(delete_webhook))), ); } @@ -142,6 +143,7 @@ async fn get_webhooks( #[derive(Serialize, Default)] pub struct PatchWebhooksAnalytics { patch_webhooks_count: usize, + patch_webhook_count: usize, post_webhook_count: usize, delete_webhook_count: usize, } @@ -151,6 +153,10 @@ impl PatchWebhooksAnalytics { PatchWebhooksAnalytics { patch_webhooks_count: 1, ..Default::default() } } + pub fn patch_webhook() -> Self { + PatchWebhooksAnalytics { patch_webhook_count: 1, ..Default::default() } + } + pub fn post_webhook() -> Self { PatchWebhooksAnalytics { post_webhook_count: 1, ..Default::default() } } @@ -168,6 +174,7 @@ impl Aggregate for PatchWebhooksAnalytics { fn aggregate(self: Box, new: Box) -> Box { Box::new(PatchWebhooksAnalytics { patch_webhooks_count: self.patch_webhooks_count + new.patch_webhooks_count, + patch_webhook_count: self.patch_webhook_count + new.patch_webhook_count, post_webhook_count: self.post_webhook_count + new.post_webhook_count, delete_webhook_count: self.delete_webhook_count + new.delete_webhook_count, }) @@ -409,6 +416,50 @@ async fn post_webhook( Ok(HttpResponse::Created().json(WebhookWithMetadata { uuid, is_editable: true, webhook })) } +#[utoipa::path( + patch, + path = "/{uuid}", + tag = "Webhooks", + request_body = WebhookSettings, + security(("Bearer" = ["webhooks.update", "*"])), + responses( + (status = 200, description = "Webhook updated successfully", body = WebhookWithMetadata, content_type = "application/json", example = json!({ + "uuid": "550e8400-e29b-41d4-a716-446655440000", + "url": "https://your.site/on-tasks-completed", + "headers": { + "Authorization": "Bearer a-secret-token" + }, + "isEditable": true + })), + (status = 401, description = "The authorization header is missing", body = ResponseError, content_type = "application/json"), + (status = 400, description = "Bad request", body = ResponseError, content_type = "application/json"), + ), + params( + ("uuid" = Uuid, Path, description = "The universally unique identifier of the webhook") + ) +)] +async fn patch_webhook( + index_scheduler: GuardedData, Data>, + uuid: Path, + webhook_settings: AwebJson, + req: HttpRequest, + analytics: Data, +) -> Result { + let uuid = uuid.into_inner(); + + let webhooks = patch_webhooks_inner( + &index_scheduler, + WebhooksSettings { + webhooks: Setting::Set(BTreeMap::from([(uuid, Setting::Set(webhook_settings.0))])), + }, + )?; + let webhook = webhooks.webhooks.get(&uuid).ok_or(WebhooksError::WebhookNotFound(uuid))?.clone(); + + analytics.publish(PatchWebhooksAnalytics::patch_webhook(), &req); + + Ok(HttpResponse::Ok().json(WebhookWithMetadata { uuid, is_editable: uuid != Uuid::nil(), webhook })) +} + #[utoipa::path( delete, path = "/{uuid}",