Files
ocdp-go/backend/internal/adapter/input/http/rest/user_management_handler.go
Ivan087 29d0310f03 feat(frontend): add Helm chart browser, monitoring, chart-references and values templates pages
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.
2026-04-15 16:59:31 +08:00

332 lines
9.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}