gitdataai/lib/api/src/channel/rest_room.rs
2026-05-30 01:38:40 +08:00

322 lines
8.7 KiB
Rust

use actix_web::{HttpRequest, HttpResponse, web};
use channel::ChannelBus;
use channel::http::{WsHandler, WsInMessage};
use serde::Deserialize;
use uuid::Uuid;
use super::rest::{channel_err, created_json, extract_user, ok_json};
use crate::error::ApiError;
#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct RoomCreateRequest {
pub workspace: Uuid,
pub room_name: String,
pub public: bool,
pub category: Option<Uuid>,
}
#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct RoomUpdateRequest {
pub room_name: Option<String>,
pub public: Option<bool>,
pub category: Option<Uuid>,
}
#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct AccessRequest {
pub user: Uuid,
}
#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct CategoryCreateRequest {
pub name: String,
pub position: Option<i32>,
}
#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct CategoryUpdateRequest {
pub name: Option<String>,
pub position: Option<i32>,
}
#[utoipa::path(
get,
path = "/api/v1/ws/rooms",
responses((status = 200, description = "List of rooms")),
tag = "channel",
)]
pub async fn list_rooms(
req: HttpRequest,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let rooms = bus.list_user_rooms(user_id)
.await
.map_err(channel_err)?;
let categories = bus.list_user_categories(user_id)
.await
.map_err(channel_err)?;
let workspace_id = if let Some(r) = rooms.first() {
Some(r.workspace_id)
} else {
bus.first_workspace_id(user_id).await.unwrap_or(None)
};
Ok(HttpResponse::Ok().json(serde_json::json!({
"rooms": rooms,
"categories": categories,
"workspace_id": workspace_id,
})))
}
#[utoipa::path(
post,
path = "/api/v1/ws/rooms/{room_id}/subscribe",
responses((status = 204, description = "Subscribed, user room cache refreshed")),
tag = "channel",
)]
pub async fn subscribe(
req: HttpRequest,
room_id: web::Path<Uuid>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let msg = WsInMessage::Subscribe {
room: room_id.into_inner(),
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(ok_json(result))
}
#[utoipa::path(
delete,
path = "/api/v1/ws/rooms/{room_id}/subscribe",
responses((status = 204, description = "Unsubscribed")),
tag = "channel",
)]
pub async fn unsubscribe(
req: HttpRequest,
room_id: web::Path<Uuid>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let msg = WsInMessage::Unsubscribe {
room: room_id.into_inner(),
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(ok_json(result))
}
#[utoipa::path(
get,
path = "/api/v1/ws/rooms/{room_id}",
responses((status = 200, description = "Room info")),
tag = "channel",
)]
pub async fn room_get(
req: HttpRequest,
room_id: web::Path<Uuid>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let msg = WsInMessage::RoomGet {
room: room_id.into_inner(),
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(ok_json(result))
}
#[utoipa::path(
post,
path = "/api/v1/ws/rooms",
request_body = RoomCreateRequest,
responses((status = 201, description = "Room created")),
tag = "channel",
)]
pub async fn room_create(
req: HttpRequest,
body: web::Json<RoomCreateRequest>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let msg = WsInMessage::RoomCreate {
workspace: body.workspace,
room_name: body.room_name.clone(),
public: body.public,
category: body.category,
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(created_json(result))
}
#[utoipa::path(
patch,
path = "/api/v1/ws/rooms/{room_id}",
request_body = RoomUpdateRequest,
responses((status = 200, description = "Room updated")),
tag = "channel",
)]
pub async fn room_update(
req: HttpRequest,
room_id: web::Path<Uuid>,
body: web::Json<RoomUpdateRequest>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let msg = WsInMessage::RoomUpdate {
room: room_id.into_inner(),
room_name: body.room_name.clone(),
public: body.public,
category: body.category,
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(ok_json(result))
}
#[utoipa::path(
delete,
path = "/api/v1/ws/rooms/{room_id}",
responses((status = 204, description = "Room deleted")),
tag = "channel",
)]
pub async fn room_delete(
req: HttpRequest,
room_id: web::Path<Uuid>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let msg = WsInMessage::RoomDelete {
room: room_id.into_inner(),
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(ok_json(result))
}
#[utoipa::path(
post,
path = "/api/v1/ws/rooms/{room_id}/members",
request_body = AccessRequest,
responses((status = 204, description = "Access granted")),
tag = "channel",
)]
pub async fn access_grant(
req: HttpRequest,
room_id: web::Path<Uuid>,
body: web::Json<AccessRequest>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let msg = WsInMessage::AccessGrant {
room: room_id.into_inner(),
user: body.user,
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(ok_json(result))
}
#[utoipa::path(
delete,
path = "/api/v1/ws/rooms/{room_id}/members/{user_id}",
responses((status = 204, description = "Access revoked")),
tag = "channel",
)]
pub async fn access_revoke(
req: HttpRequest,
path: web::Path<(Uuid, Uuid)>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let (room, target_user) = path.into_inner();
let msg = WsInMessage::AccessRevoke {
room,
user: target_user,
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(ok_json(result))
}
#[utoipa::path(
post,
path = "/api/v1/ws/workspaces/{workspace_id}/categories",
request_body = CategoryCreateRequest,
responses((status = 201, description = "Category created")),
tag = "channel",
)]
pub async fn category_create(
req: HttpRequest,
workspace_id: web::Path<Uuid>,
body: web::Json<CategoryCreateRequest>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let msg = WsInMessage::CategoryCreate {
workspace: workspace_id.into_inner(),
name: body.name.clone(),
position: body.position,
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(created_json(result))
}
#[utoipa::path(
patch,
path = "/api/v1/ws/categories/{category_id}",
request_body = CategoryUpdateRequest,
responses((status = 200, description = "Category updated")),
tag = "channel",
)]
pub async fn category_update(
req: HttpRequest,
category_id: web::Path<Uuid>,
body: web::Json<CategoryUpdateRequest>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let msg = WsInMessage::CategoryUpdate {
id: category_id.into_inner(),
name: body.name.clone(),
position: body.position,
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(ok_json(result))
}
#[utoipa::path(
delete,
path = "/api/v1/ws/categories/{category_id}",
responses((status = 204, description = "Category deleted")),
tag = "channel",
)]
pub async fn category_delete(
req: HttpRequest,
category_id: web::Path<Uuid>,
bus: web::Data<ChannelBus>,
) -> Result<HttpResponse, ApiError> {
let user_id = extract_user(&req)?;
let msg = WsInMessage::CategoryDelete {
id: category_id.into_inner(),
};
let result = WsHandler::handle(&bus, user_id, msg)
.await
.map_err(channel_err)?;
Ok(ok_json(result))
}