Add new frontend pages for the multi-tenant OCDP platform: - Charts page (/charts): Browse Harbor OCI registries to list Helm chart repositories and versions, with deploy modal to launch charts on selected clusters - Monitoring page (/monitoring): Display cluster metrics (CPU/Memory/GPU usage) and per-node details with resource utilization bars - Chart References page (/chart-references): CRUD for chart metadata references - Values Templates page (/templates): CRUD for Helm values templates with version history and rollback support - Sidebar: Add Charts navigation, update Storage and Templates links - api.ts: Add all API client functions (clusterApi, registryApi, instanceApi, monitoringApi, storageApi, chartReferenceApi, valuesTemplateApi, workspaceApi, userApi) with full TypeScript types Note: deploy flow and values template rollback not yet end-to-end tested.
332 lines
9.2 KiB
Go
332 lines
9.2 KiB
Go
package rest
|
||
|
||
import (
|
||
"encoding/json"
|
||
"net/http"
|
||
|
||
"github.com/gorilla/mux"
|
||
"github.com/ocdp/cluster-service/internal/adapter/input/http/dto"
|
||
"github.com/ocdp/cluster-service/internal/domain/entity"
|
||
"github.com/ocdp/cluster-service/internal/domain/service"
|
||
)
|
||
|
||
// UserManagementHandler 用户管理 HTTP 处理程序
|
||
type UserManagementHandler struct {
|
||
userManagementService *service.UserManagementService
|
||
authService *service.AuthService
|
||
workspaceService *service.WorkspaceService
|
||
}
|
||
|
||
// NewUserManagementHandler 创建用户管理处理程序
|
||
func NewUserManagementHandler(
|
||
userManagementService *service.UserManagementService,
|
||
authService *service.AuthService,
|
||
workspaceService *service.WorkspaceService,
|
||
) *UserManagementHandler {
|
||
return &UserManagementHandler{
|
||
userManagementService: userManagementService,
|
||
authService: authService,
|
||
workspaceService: workspaceService,
|
||
}
|
||
}
|
||
|
||
// CreateUser 创建用户(Admin 操作)
|
||
// @Summary 创建用户
|
||
// @Description 创建新用户(Admin 专用)
|
||
// @Tags admin
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param request body dto.CreateUserRequest true "创建用户请求"
|
||
// @Success 200 {object} dto.UserResponseWithDTO
|
||
// @Router /admin/users [post]
|
||
func (h *UserManagementHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
|
||
// 检查权限(Admin)
|
||
if !h.requireAdmin(w, r) {
|
||
return
|
||
}
|
||
|
||
var req dto.CreateUserRequest
|
||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||
respondError(w, http.StatusBadRequest, "Invalid request body", "")
|
||
return
|
||
}
|
||
|
||
user, err := h.userManagementService.CreateUser(r.Context(), req.Username, req.Password, req.Email, req.Role, req.WorkspaceID)
|
||
if err != nil {
|
||
respondError(w, http.StatusBadRequest, err.Error(), "")
|
||
return
|
||
}
|
||
|
||
// 获取 workspace 名称
|
||
workspaceName := ""
|
||
if user.WorkspaceID != "" {
|
||
ws, _ := h.workspaceService.GetByID(r.Context(), user.WorkspaceID)
|
||
if ws != nil {
|
||
workspaceName = ws.Name
|
||
}
|
||
}
|
||
|
||
respondSuccess(w, "", dto.UserResponseWithDTO{User: dto.UserDTOFromEntity(user, workspaceName)})
|
||
}
|
||
|
||
// GetUser 获取用户
|
||
// @Summary 获取用户
|
||
// @Description 获取指定用户信息(Admin 专用)
|
||
// @Tags admin
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path string true "用户 ID"
|
||
// @Success 200 {object} dto.UserResponseWithDTO
|
||
// @Router /admin/users/{user_id} [get]
|
||
func (h *UserManagementHandler) GetUser(w http.ResponseWriter, r *http.Request) {
|
||
// 检查权限(Admin)
|
||
if !h.requireAdmin(w, r) {
|
||
return
|
||
}
|
||
|
||
vars := mux.Vars(r)
|
||
userID := vars["user_id"]
|
||
|
||
user, err := h.userManagementService.GetUser(r.Context(), userID)
|
||
if err != nil {
|
||
respondError(w, http.StatusNotFound, "User not found", "")
|
||
return
|
||
}
|
||
|
||
// 获取 workspace 名称
|
||
workspaceName := ""
|
||
if user.WorkspaceID != "" {
|
||
ws, _ := h.workspaceService.GetByID(r.Context(), user.WorkspaceID)
|
||
if ws != nil {
|
||
workspaceName = ws.Name
|
||
}
|
||
}
|
||
|
||
respondSuccess(w, "", dto.UserResponseWithDTO{User: dto.UserDTOFromEntity(user, workspaceName)})
|
||
}
|
||
|
||
// ListUsers 列出用户
|
||
// @Summary 列出用户
|
||
// @Description 获取所有用户列表(Admin 专用),可按 workspace_id 筛选
|
||
// @Tags admin
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param workspace_id query string false "工作空间 ID"
|
||
// @Success 200 {object} dto.UserListResponse
|
||
// @Router /admin/users [get]
|
||
func (h *UserManagementHandler) ListUsers(w http.ResponseWriter, r *http.Request) {
|
||
// 检查权限(Admin)
|
||
if !h.requireAdmin(w, r) {
|
||
return
|
||
}
|
||
|
||
workspaceID := r.URL.Query().Get("workspace_id")
|
||
|
||
users, err := h.userManagementService.ListUsers(r.Context(), workspaceID)
|
||
if err != nil {
|
||
respondError(w, http.StatusInternalServerError, err.Error(), "")
|
||
return
|
||
}
|
||
|
||
// 获取所有 workspace 名称
|
||
workspaceNames := make(map[string]string)
|
||
workspaces, _ := h.workspaceService.List(r.Context())
|
||
for _, ws := range workspaces {
|
||
workspaceNames[ws.ID] = ws.Name
|
||
}
|
||
|
||
respondSuccess(w, "", dto.UserListResponse{
|
||
Users: dto.UserDTOsFromEntities(users, workspaceNames),
|
||
Total: len(users),
|
||
})
|
||
}
|
||
|
||
// UpdateUser 更新用户
|
||
// @Summary 更新用户
|
||
// @Description 更新用户信息(Admin 专用)
|
||
// @Tags admin
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path string true "用户 ID"
|
||
// @Param request body dto.UpdateUserRequest true "更新用户请求"
|
||
// @Success 200 {object} dto.UserResponseWithDTO
|
||
// @Router /admin/users/{user_id} [put]
|
||
func (h *UserManagementHandler) UpdateUser(w http.ResponseWriter, r *http.Request) {
|
||
// 检查权限(Admin)
|
||
if !h.requireAdmin(w, r) {
|
||
return
|
||
}
|
||
|
||
vars := mux.Vars(r)
|
||
userID := vars["user_id"]
|
||
|
||
user, err := h.userManagementService.GetUser(r.Context(), userID)
|
||
if err != nil {
|
||
respondError(w, http.StatusNotFound, "User not found", "")
|
||
return
|
||
}
|
||
|
||
var req dto.UpdateUserRequest
|
||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||
respondError(w, http.StatusBadRequest, "Invalid request body", "")
|
||
return
|
||
}
|
||
|
||
if req.Email != "" {
|
||
user.Email = req.Email
|
||
}
|
||
if req.IsActive != nil {
|
||
user.IsActive = *req.IsActive
|
||
}
|
||
|
||
if err := h.userManagementService.UpdateUser(r.Context(), user); err != nil {
|
||
respondError(w, http.StatusBadRequest, err.Error(), "")
|
||
return
|
||
}
|
||
|
||
// 获取 workspace 名称
|
||
workspaceName := ""
|
||
if user.WorkspaceID != "" {
|
||
ws, _ := h.workspaceService.GetByID(r.Context(), user.WorkspaceID)
|
||
if ws != nil {
|
||
workspaceName = ws.Name
|
||
}
|
||
}
|
||
|
||
respondSuccess(w, "", dto.UserResponseWithDTO{User: dto.UserDTOFromEntity(user, workspaceName)})
|
||
}
|
||
|
||
// SetUserActive 启用/禁用用户
|
||
// @Summary 启用/禁用用户
|
||
// @Description 设置用户是否启用(Admin 专用)
|
||
// @Tags admin
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path string true "用户 ID"
|
||
// @Param request body dto.SetUserActiveRequest true "启用状态"
|
||
// @Success 200
|
||
// @Router /admin/users/{user_id}/active [put]
|
||
func (h *UserManagementHandler) SetUserActive(w http.ResponseWriter, r *http.Request) {
|
||
// 检查权限(Admin)
|
||
if !h.requireAdmin(w, r) {
|
||
return
|
||
}
|
||
|
||
vars := mux.Vars(r)
|
||
userID := vars["user_id"]
|
||
|
||
var req dto.SetUserActiveRequest
|
||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||
respondError(w, http.StatusBadRequest, "Invalid request body", "")
|
||
return
|
||
}
|
||
|
||
if err := h.userManagementService.SetUserActive(r.Context(), userID, req.IsActive); err != nil {
|
||
respondError(w, http.StatusBadRequest, err.Error(), "")
|
||
return
|
||
}
|
||
|
||
respondSuccess(w, "", nil)
|
||
}
|
||
|
||
// ChangeUserWorkspace 分配用户到 Workspace
|
||
// @Summary 分配用户到工作空间
|
||
// @Description 将用户分配到指定工作空间(Admin 专用)
|
||
// @Tags admin
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path string true "用户 ID"
|
||
// @Param request body dto.ChangeUserWorkspaceRequest true "工作空间分配请求"
|
||
// @Success 200
|
||
// @Router /admin/users/{user_id}/workspace [put]
|
||
func (h *UserManagementHandler) ChangeUserWorkspace(w http.ResponseWriter, r *http.Request) {
|
||
// 检查权限(Admin)
|
||
if !h.requireAdmin(w, r) {
|
||
return
|
||
}
|
||
|
||
vars := mux.Vars(r)
|
||
userID := vars["user_id"]
|
||
|
||
var req dto.ChangeUserWorkspaceRequest
|
||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||
respondError(w, http.StatusBadRequest, "Invalid request body", "")
|
||
return
|
||
}
|
||
|
||
if err := h.userManagementService.ChangeUserWorkspace(r.Context(), userID, req.WorkspaceID); err != nil {
|
||
respondError(w, http.StatusBadRequest, err.Error(), "")
|
||
return
|
||
}
|
||
|
||
respondSuccess(w, "", nil)
|
||
}
|
||
|
||
// ResetPassword 重置用户密码(Admin 操作)
|
||
// @Summary 重置用户密码
|
||
// @Description 重置指定用户的密码(Admin 专用)
|
||
// @Tags admin
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path string true "用户 ID"
|
||
// @Param request body dto.ResetPasswordRequest true "重置密码请求"
|
||
// @Success 200
|
||
// @Router /admin/users/{user_id}/password [put]
|
||
func (h *UserManagementHandler) ResetPassword(w http.ResponseWriter, r *http.Request) {
|
||
// 检查权限(Admin)
|
||
if !h.requireAdmin(w, r) {
|
||
return
|
||
}
|
||
|
||
vars := mux.Vars(r)
|
||
userID := vars["user_id"]
|
||
|
||
var req dto.ResetPasswordRequest
|
||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||
respondError(w, http.StatusBadRequest, "Invalid request body", "")
|
||
return
|
||
}
|
||
|
||
if err := h.userManagementService.ResetPassword(r.Context(), userID, req.NewPassword); err != nil {
|
||
respondError(w, http.StatusBadRequest, err.Error(), "")
|
||
return
|
||
}
|
||
|
||
respondSuccess(w, "", nil)
|
||
}
|
||
|
||
// DeleteUser 删除用户
|
||
// @Summary 删除用户
|
||
// @Description 删除指定用户(Admin 专用)
|
||
// @Tags admin
|
||
// @Accept json
|
||
// @Produce json
|
||
// @Param user_id path string true "用户 ID"
|
||
// @Success 200
|
||
// @Router /admin/users/{user_id} [delete]
|
||
func (h *UserManagementHandler) DeleteUser(w http.ResponseWriter, r *http.Request) {
|
||
// 检查权限(Admin)
|
||
if !h.requireAdmin(w, r) {
|
||
return
|
||
}
|
||
|
||
vars := mux.Vars(r)
|
||
userID := vars["user_id"]
|
||
|
||
if err := h.userManagementService.DeleteUser(r.Context(), userID); err != nil {
|
||
respondError(w, http.StatusBadRequest, err.Error(), "")
|
||
return
|
||
}
|
||
|
||
respondSuccess(w, "", nil)
|
||
}
|
||
|
||
// requireAdmin 检查是否为 Admin
|
||
func (h *UserManagementHandler) requireAdmin(w http.ResponseWriter, r *http.Request) bool {
|
||
userRole := r.Header.Get("X-User-Role")
|
||
if userRole != string(entity.RoleAdmin) {
|
||
respondError(w, http.StatusForbidden, "Admin access required", "")
|
||
return false
|
||
}
|
||
return true
|
||
} |