144 lines
4.1 KiB
Go
144 lines
4.1 KiB
Go
package projects
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/kandev/kandev/internal/office/models"
|
|
)
|
|
|
|
// Handler provides HTTP handlers for project routes.
|
|
type Handler struct {
|
|
svc *ProjectService
|
|
}
|
|
|
|
// NewHandler creates a new Handler backed by the given ProjectService.
|
|
func NewHandler(svc *ProjectService) *Handler {
|
|
return &Handler{svc: svc}
|
|
}
|
|
|
|
// RegisterRoutes registers project HTTP routes on the given router group.
|
|
func RegisterRoutes(api *gin.RouterGroup, h *Handler) {
|
|
api.GET("/workspaces/:wsId/projects", h.listProjects)
|
|
api.POST("/workspaces/:wsId/projects", h.createProject)
|
|
api.GET("/projects/:id", h.getProject)
|
|
api.PATCH("/projects/:id", h.updateProject)
|
|
api.DELETE("/projects/:id", h.deleteProject)
|
|
}
|
|
|
|
func (h *Handler) listProjects(c *gin.Context) {
|
|
projects, err := h.svc.ListProjectsWithCountsFromConfig(c.Request.Context(), c.Param("wsId"))
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, ProjectListResponse{Projects: projects})
|
|
}
|
|
|
|
func (h *Handler) createProject(c *gin.Context) {
|
|
wsID := c.Param("wsId")
|
|
var req CreateProjectRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
reposJSON, err := models.EncodeRepositories(req.Repositories)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
project := &Project{
|
|
WorkspaceID: wsID,
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
Status: ProjectStatusActive,
|
|
LeadAgentProfileID: req.LeadAgentProfileID,
|
|
Color: req.Color,
|
|
BudgetCents: req.BudgetCents,
|
|
Repositories: reposJSON,
|
|
ExecutorConfig: req.ExecutorConfig,
|
|
}
|
|
if err := h.svc.CreateProject(c.Request.Context(), project); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, ProjectResponse{Project: project})
|
|
}
|
|
|
|
func (h *Handler) getProject(c *gin.Context) {
|
|
project, err := h.svc.GetProjectFromConfig(c.Request.Context(), c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, ProjectResponse{Project: project})
|
|
}
|
|
|
|
func (h *Handler) updateProject(c *gin.Context) {
|
|
project, statusCode, err := h.doUpdateProject(c)
|
|
if err != nil {
|
|
c.JSON(statusCode, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, ProjectResponse{Project: project})
|
|
}
|
|
|
|
func (h *Handler) doUpdateProject(c *gin.Context) (*Project, int, error) {
|
|
ctx := c.Request.Context()
|
|
project, err := h.svc.GetProjectFromConfig(ctx, c.Param("id"))
|
|
if err != nil {
|
|
return nil, http.StatusNotFound, err
|
|
}
|
|
var req UpdateProjectRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
return nil, http.StatusBadRequest, err
|
|
}
|
|
if err := applyProjectUpdates(project, &req); err != nil {
|
|
return nil, http.StatusBadRequest, err
|
|
}
|
|
if err := h.svc.UpdateProject(ctx, project); err != nil {
|
|
return nil, http.StatusInternalServerError, err
|
|
}
|
|
return project, http.StatusOK, nil
|
|
}
|
|
|
|
func (h *Handler) deleteProject(c *gin.Context) {
|
|
if err := h.svc.DeleteProject(c.Request.Context(), c.Param("id")); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"ok": true})
|
|
}
|
|
|
|
func applyProjectUpdates(project *Project, req *UpdateProjectRequest) error {
|
|
if req.Name != nil {
|
|
project.Name = *req.Name
|
|
}
|
|
if req.Description != nil {
|
|
project.Description = *req.Description
|
|
}
|
|
if req.Status != nil {
|
|
project.Status = ProjectStatus(*req.Status)
|
|
}
|
|
if req.LeadAgentProfileID != nil {
|
|
project.LeadAgentProfileID = *req.LeadAgentProfileID
|
|
}
|
|
if req.Color != nil {
|
|
project.Color = *req.Color
|
|
}
|
|
if req.BudgetCents != nil {
|
|
project.BudgetCents = *req.BudgetCents
|
|
}
|
|
if req.Repositories != nil {
|
|
encoded, err := models.EncodeRepositories(*req.Repositories)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
project.Repositories = encoded
|
|
}
|
|
if req.ExecutorConfig != nil {
|
|
project.ExecutorConfig = *req.ExecutorConfig
|
|
}
|
|
return nil
|
|
}
|