Skip to content
Clone
b453d5d
241 lines 9.5 KB Rust
use axum::extract::{Json, Path, Query, State};
use export::rest::{AppResponseData, NoData};
use jwt::Session;
use jwt::share::session::require_uid;
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<WebhookSecretDto>),
(status = 429, description = "creation quota exceeded", body = AppResponseData<NoData>),
(status = 403, description = "forbidden", body = AppResponseData<NoData>),
(status = 400, description = "request failed validation", body = AppResponseData<NoData>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn create_webhook(
State(service): State<ChatService>,
session: Session,
Path(room_id): Path<Uuid>,
Json(cmd): Json<CreateWebhookCmd>,
) -> Result<AppResponseData<WebhookSecretDto>, ApiError> {
let uid = require_uid(&session)?;
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"), export::pagination::PageQuery),
responses(
(status = 200, description = "webhook list", body = AppResponseData<export::pagination::Page<WebhookDto>>),
(status = 403, description = "forbidden", body = AppResponseData<NoData>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn list_webhooks(
State(service): State<ChatService>,
session: Session,
Path(room_id): Path<Uuid>,
Query(page): Query<export::pagination::PageQuery>,
) -> Result<AppResponseData<export::pagination::Page<WebhookDto>>, ApiError> {
let uid = require_uid(&session)?;
let rows = service.list_webhooks(uid, room_id).await?;
Ok(AppResponseData::ok(export::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<NoData>),
(status = 404, description = "not found", body = AppResponseData<NoData>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn delete_webhook(
State(service): State<ChatService>,
session: Session,
Path((room_id, webhook_id)): Path<(Uuid, Uuid)>,
) -> Result<AppResponseData<NoData>, ApiError> {
let uid = require_uid(&session)?;
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<MessageDto>),
(status = 401, description = "invalid token", body = AppResponseData<NoData>),
(status = 400, description = "request failed validation", body = AppResponseData<NoData>)
)
)]
pub async fn post_via_webhook(
State(service): State<ChatService>,
Path(token): Path<String>,
Json(cmd): Json<WebhookPostCmd>,
) -> Result<AppResponseData<MessageDto>, 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<WebhookDto>),
(status = 404, description = "not found", body = AppResponseData<NoData>),
(status = 400, description = "request failed validation", body = AppResponseData<NoData>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn update_webhook(
State(service): State<ChatService>,
session: Session,
Path((room_id, webhook_id)): Path<(Uuid, Uuid)>,
Json(cmd): Json<UpdateWebhookCmd>,
) -> Result<AppResponseData<WebhookDto>, ApiError> {
let uid = require_uid(&session)?;
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<OutboundWebhookSecretDto>),
(status = 403, description = "forbidden", body = AppResponseData<NoData>),
(status = 400, description = "request failed validation", body = AppResponseData<NoData>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn create_outbound_webhook(
State(service): State<ChatService>,
session: Session,
Path(room_id): Path<Uuid>,
Json(cmd): Json<CreateOutboundWebhookCmd>,
) -> Result<AppResponseData<OutboundWebhookSecretDto>, ApiError> {
let uid = require_uid(&session)?;
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<Vec<OutboundWebhookDto>>),
(status = 403, description = "forbidden", body = AppResponseData<NoData>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn list_outbound_webhooks(
State(service): State<ChatService>,
session: Session,
Path(room_id): Path<Uuid>,
) -> Result<AppResponseData<Vec<OutboundWebhookDto>>, ApiError> {
let uid = require_uid(&session)?;
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<OutboundWebhookDto>),
(status = 404, description = "not found", body = AppResponseData<NoData>),
(status = 400, description = "request failed validation", body = AppResponseData<NoData>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn update_outbound_webhook(
State(service): State<ChatService>,
session: Session,
Path((room_id, webhook_id)): Path<(Uuid, Uuid)>,
Json(cmd): Json<UpdateOutboundWebhookCmd>,
) -> Result<AppResponseData<OutboundWebhookDto>, ApiError> {
let uid = require_uid(&session)?;
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<NoData>),
(status = 404, description = "not found", body = AppResponseData<NoData>),
(status = 401, description = "authentication required", body = AppResponseData<NoData>)
)
)]
pub async fn delete_outbound_webhook(
State(service): State<ChatService>,
session: Session,
Path((room_id, webhook_id)): Path<(Uuid, Uuid)>,
) -> Result<AppResponseData<NoData>, ApiError> {
let uid = require_uid(&session)?;
service
.delete_outbound_webhook(uid, room_id, webhook_id)
.await?;
Ok(AppResponseData::empty())
}