use axum::Extension; use axum::extract::{FromRef, Path, Query, State}; use axum::response::Json; use serde::{Deserialize, Serialize}; use utoipa::{IntoParams, ToSchema}; use validator::Validate; use erp_core::error::AppError; use erp_core::types::{ApiResponse, PaginatedResponse, Pagination, TenantContext}; use uuid::Uuid; use crate::auth_state::AuthState; use crate::dto::{CreateUserReq, RoleResp, UpdateUserReq, UserResp}; use crate::service::user_service::UserService; use erp_core::rbac::require_permission; /// Query parameters for user list endpoint. #[derive(Debug, Deserialize, IntoParams)] pub struct UserListParams { pub page: Option, pub page_size: Option, /// Optional search term — filters by username (case-insensitive contains). pub search: Option, } #[utoipa::path( get, path = "/api/v1/users", params(UserListParams), responses( (status = 200, description = "成功", body = ApiResponse>), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "用户管理" )] /// GET /api/v1/users /// /// List users within the current tenant with pagination and optional search. /// Requires the `user.list` permission. pub async fn list_users( State(state): State, Extension(ctx): Extension, Query(params): Query, ) -> Result>>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "user.list")?; let pagination = Pagination { page: params.page, page_size: params.page_size, }; let (users, total) = UserService::list( ctx.tenant_id, &pagination, params.search.as_deref(), &state.db, ) .await?; let page = pagination.page.unwrap_or(1); let page_size = pagination.limit(); let total_pages = total.div_ceil(page_size); Ok(Json(ApiResponse::ok(PaginatedResponse { data: users, total, page, page_size, total_pages, }))) } #[utoipa::path( post, path = "/api/v1/users", request_body = CreateUserReq, responses( (status = 200, description = "创建成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "用户管理" )] /// POST /api/v1/users /// /// Create a new user within the current tenant. /// Requires the `user.create` permission. pub async fn create_user( State(state): State, Extension(ctx): Extension, Json(mut req): Json, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "user.create")?; req.validate() .map_err(|e| AppError::Validation(e.to_string()))?; req.sanitize(); let user = UserService::create( ctx.tenant_id, ctx.user_id, &req, &state.db, &state.event_bus, ) .await?; Ok(Json(ApiResponse::ok(user))) } #[utoipa::path( get, path = "/api/v1/users/{id}", params(("id" = Uuid, Path, description = "用户ID")), responses( (status = 200, description = "成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), (status = 404, description = "用户不存在"), ), security(("bearer_auth" = [])), tag = "用户管理" )] /// GET /api/v1/users/:id /// /// Fetch a single user by ID within the current tenant. /// Requires the `user.read` permission. pub async fn get_user( State(state): State, Extension(ctx): Extension, Path(id): Path, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "user.read")?; let user = UserService::get_by_id(id, ctx.tenant_id, &state.db).await?; Ok(Json(ApiResponse::ok(user))) } #[utoipa::path( put, path = "/api/v1/users/{id}", params(("id" = Uuid, Path, description = "用户ID")), request_body = UpdateUserReq, responses( (status = 200, description = "更新成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), (status = 404, description = "用户不存在"), ), security(("bearer_auth" = [])), tag = "用户管理" )] /// PUT /api/v1/users/:id /// /// Update editable user fields. /// Requires the `user.update` permission. pub async fn update_user( State(state): State, Extension(ctx): Extension, Path(id): Path, Json(mut req): Json, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "user.update")?; req.sanitize(); let user = UserService::update(id, ctx.tenant_id, ctx.user_id, &req, &state.db).await?; Ok(Json(ApiResponse::ok(user))) } #[utoipa::path( delete, path = "/api/v1/users/{id}", params(("id" = Uuid, Path, description = "用户ID")), responses( (status = 200, description = "用户已删除"), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), (status = 404, description = "用户不存在"), ), security(("bearer_auth" = [])), tag = "用户管理" )] /// DELETE /api/v1/users/:id /// /// Soft-delete a user by ID within the current tenant. /// Requires the `user.delete` permission. pub async fn delete_user( State(state): State, Extension(ctx): Extension, Path(id): Path, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "user.delete")?; UserService::delete(id, ctx.tenant_id, ctx.user_id, &state.db, &state.event_bus).await?; Ok(Json(ApiResponse { success: true, data: None, message: Some("用户已删除".to_string()), })) } /// Assign roles request body. #[derive(Debug, Deserialize, ToSchema)] pub struct AssignRolesReq { pub role_ids: Vec, } /// Assign roles response. #[derive(Debug, Serialize, ToSchema)] pub struct AssignRolesResp { pub roles: Vec, } #[utoipa::path( post, path = "/api/v1/users/{id}/roles", params(("id" = Uuid, Path, description = "用户ID")), request_body = AssignRolesReq, responses( (status = 200, description = "角色分配成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), (status = 404, description = "用户不存在"), ), security(("bearer_auth" = [])), tag = "用户管理" )] /// POST /api/v1/users/:id/roles /// /// Replace all role assignments for a user within the current tenant. /// Requires the `user.update` permission. pub async fn assign_roles( State(state): State, Extension(ctx): Extension, Path(id): Path, Json(req): Json, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "user.update")?; let roles = UserService::assign_roles(id, ctx.tenant_id, ctx.user_id, &req.role_ids, &state.db).await?; Ok(Json(ApiResponse::ok(AssignRolesResp { roles }))) }