package vm import ( "context" "encoding/json" "net/http" "time" "proxui/backend/internal/auth" ) type Repository interface { ListProjectVMs(ctx context.Context, profileID string, projectID string) ([]VM, bool, error) GetVM(ctx context.Context, profileID string, vmID string) (VM, bool, error) } type Handler struct { repository Repository power PowerDependencies } type Option func(*Handler) func WithPower(dependencies PowerDependencies) Option { return func(h *Handler) { h.power = dependencies } } func NewHandler(repository Repository, opts ...Option) Handler { handler := Handler{repository: repository} for _, opt := range opts { opt(&handler) } return handler } func (h Handler) ListProjectVMs(w http.ResponseWriter, r *http.Request) { principal, ok := auth.PrincipalFromRequest(r) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } projectID := r.PathValue("projectID") if projectID == "" { writeError(w, http.StatusBadRequest, "project_id_required") return } vms, found, err := h.repository.ListProjectVMs(r.Context(), principal.Subject, projectID) if err != nil { writeError(w, http.StatusInternalServerError, "vm_list_failed") return } if !found { writeError(w, http.StatusNotFound, "project_not_found") return } writeJSON(w, http.StatusOK, map[string][]VM{"data": vms}) } func (h Handler) GetVM(w http.ResponseWriter, r *http.Request) { principal, ok := auth.PrincipalFromRequest(r) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } vmID := r.PathValue("vmID") if vmID == "" { writeError(w, http.StatusBadRequest, "vm_id_required") return } vm, found, err := h.repository.GetVM(r.Context(), principal.Subject, vmID) if err != nil { writeError(w, http.StatusInternalServerError, "vm_get_failed") return } if !found { writeError(w, http.StatusNotFound, "vm_not_found") return } writeJSON(w, http.StatusOK, vm) } type VM struct { ID string `json:"id"` ProjectID string `json:"project_id"` TenantID string `json:"tenant_id"` ClusterID string `json:"cluster_id"` ProxmoxVMID int `json:"proxmox_vmid"` Node string `json:"node"` Name string `json:"name"` Status string `json:"status"` VCPU int `json:"vcpu"` RAMMB int `json:"ram_mb"` DiskGB int `json:"disk_gb"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` ProjectName string `json:"project_name"` MembershipRole string `json:"membership_role"` } func writeJSON(w http.ResponseWriter, status int, body any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(body) } func writeError(w http.ResponseWriter, status int, message string) { writeJSON(w, status, map[string]string{"error": message}) }