use ::session::AuthedUser; use api::http::{Json, Path, Query, State}; use api::rest::{AppResponseData, NoData}; use uuid::Uuid; use crate::errors::ApiError; use crate::services::messages::MessageDto; use crate::services::service::ChatService; use crate::services::webhooks::{ CreateWebhookCmd, UpdateWebhookCmd, WebhookDto, WebhookPostCmd, WebhookSecretDto, }; #[utoipa::path( post, path = "/chat/rooms/{room_id}/webhooks", tag = "chat", description = "空间管理员为房间创建 Webhook,并一次性返回调用令牌。", params(("room_id" = Uuid, Path, description = "room id")), request_body = CreateWebhookCmd, responses( (status = 200, description = "webhook created", body = AppResponseData), (status = 429, description = "creation quota exceeded", body = AppResponseData), (status = 403, description = "forbidden", body = AppResponseData), (status = 400, description = "request failed validation", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn create_webhook( State(service): State, AuthedUser(uid): AuthedUser, Path(room_id): Path, Json(cmd): Json, ) -> Result, ApiError> { let dto = service.create_webhook(uid, room_id, cmd).await?; Ok(AppResponseData::ok(dto)) } #[utoipa::path( get, path = "/chat/rooms/{room_id}/webhooks", tag = "chat", description = "列出房间 Webhook 的元数据,但不返回令牌。", params(("room_id" = Uuid, Path, description = "room id"), api::pagination::PageQuery), responses( (status = 200, description = "webhook list", body = AppResponseData>), (status = 403, description = "forbidden", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn list_webhooks( State(service): State, AuthedUser(uid): AuthedUser, Path(room_id): Path, Query(page): Query, ) -> Result>, ApiError> { let rows = service.list_webhooks(uid, room_id).await?; Ok(AppResponseData::ok(api::pagination::paginate(rows, &page)?)) } #[utoipa::path( delete, path = "/chat/rooms/{room_id}/webhooks/{webhook_id}", tag = "chat", description = "删除房间下的指定 Webhook。", params( ("room_id" = Uuid, Path, description = "room id"), ("webhook_id" = Uuid, Path, description = "webhook id") ), responses( (status = 200, description = "webhook deleted", body = AppResponseData), (status = 404, description = "not found", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn delete_webhook( State(service): State, AuthedUser(uid): AuthedUser, Path((room_id, webhook_id)): Path<(Uuid, Uuid)>, ) -> Result, ApiError> { service.delete_webhook(uid, room_id, webhook_id).await?; Ok(AppResponseData::empty()) } #[utoipa::path( post, path = "/chat/hooks/{token}", tag = "chat", description = "凭路径中的 Webhook 令牌以创建者身份向房间发送消息。", params(("token" = String, Path, description = "webhook token")), request_body = WebhookPostCmd, responses( (status = 200, description = "message posted", body = AppResponseData), (status = 401, description = "invalid token", body = AppResponseData), (status = 400, description = "request failed validation", body = AppResponseData) ) )] pub async fn post_via_webhook( State(service): State, Path(token): Path, Json(cmd): Json, ) -> Result, ApiError> { let value = service.post_via_webhook(&token, cmd).await?; let dto: MessageDto = serde_json::from_value(value)?; Ok(AppResponseData::ok(dto)) } #[utoipa::path( patch, path = "/chat/rooms/{room_id}/webhooks/{webhook_id}", tag = "chat", description = "更新 Webhook 名称或启用状态。", params(("room_id" = Uuid, Path), ("webhook_id" = Uuid, Path)), request_body = UpdateWebhookCmd, responses( (status = 200, description = "webhook updated", body = AppResponseData), (status = 404, description = "not found", body = AppResponseData), (status = 400, description = "request failed validation", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn update_webhook( State(service): State, AuthedUser(uid): AuthedUser, Path((room_id, webhook_id)): Path<(Uuid, Uuid)>, Json(cmd): Json, ) -> Result, ApiError> { let dto = service .update_webhook(uid, room_id, webhook_id, cmd) .await?; Ok(AppResponseData::ok(dto)) } use crate::services::outbound::{ CreateOutboundWebhookCmd, OutboundWebhookDto, OutboundWebhookSecretDto, UpdateOutboundWebhookCmd, }; #[utoipa::path( post, path = "/chat/rooms/{room_id}/outbound-webhooks", tag = "chat", description = "创建出站 Webhook(房间消息事件回调),一次性返回签名密钥。", params(("room_id" = Uuid, Path, description = "room id")), request_body = CreateOutboundWebhookCmd, responses( (status = 200, description = "outbound webhook created", body = AppResponseData), (status = 403, description = "forbidden", body = AppResponseData), (status = 400, description = "request failed validation", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn create_outbound_webhook( State(service): State, AuthedUser(uid): AuthedUser, Path(room_id): Path, Json(cmd): Json, ) -> Result, ApiError> { let dto = service.create_outbound_webhook(uid, room_id, cmd).await?; Ok(AppResponseData::ok(dto)) } #[utoipa::path( get, path = "/chat/rooms/{room_id}/outbound-webhooks", tag = "chat", description = "列出房间的出站 Webhook(不返回密钥)。", params(("room_id" = Uuid, Path, description = "room id")), responses( (status = 200, description = "outbound webhook list", body = AppResponseData>), (status = 403, description = "forbidden", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn list_outbound_webhooks( State(service): State, AuthedUser(uid): AuthedUser, Path(room_id): Path, ) -> Result>, ApiError> { let rows = service.list_outbound_webhooks(uid, room_id).await?; Ok(AppResponseData::ok(rows)) } #[utoipa::path( patch, path = "/chat/rooms/{room_id}/outbound-webhooks/{webhook_id}", tag = "chat", description = "更新出站 Webhook 的名称、地址或启用状态。", params(("room_id" = Uuid, Path), ("webhook_id" = Uuid, Path)), request_body = UpdateOutboundWebhookCmd, responses( (status = 200, description = "outbound webhook updated", body = AppResponseData), (status = 404, description = "not found", body = AppResponseData), (status = 400, description = "request failed validation", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn update_outbound_webhook( State(service): State, AuthedUser(uid): AuthedUser, Path((room_id, webhook_id)): Path<(Uuid, Uuid)>, Json(cmd): Json, ) -> Result, ApiError> { let dto = service .update_outbound_webhook(uid, room_id, webhook_id, cmd) .await?; Ok(AppResponseData::ok(dto)) } #[utoipa::path( delete, path = "/chat/rooms/{room_id}/outbound-webhooks/{webhook_id}", tag = "chat", description = "删除出站 Webhook 并清理待投递事件。", params(("room_id" = Uuid, Path), ("webhook_id" = Uuid, Path)), responses( (status = 200, description = "outbound webhook deleted", body = AppResponseData), (status = 404, description = "not found", body = AppResponseData), (status = 401, description = "authentication required", body = AppResponseData) ) )] pub async fn delete_outbound_webhook( State(service): State, AuthedUser(uid): AuthedUser, Path((room_id, webhook_id)): Path<(Uuid, Uuid)>, ) -> Result, ApiError> { service .delete_outbound_webhook(uid, room_id, webhook_id) .await?; Ok(AppResponseData::empty()) }