package api import ( "git.aiterp.net/stufflog3/stufflog3-api/internal/auth" "git.aiterp.net/stufflog3/stufflog3-api/internal/database" "git.aiterp.net/stufflog3/stufflog3-api/internal/models" "git.aiterp.net/stufflog3/stufflog3-api/internal/slerrors" "github.com/gin-gonic/gin" "time" ) func Projects(g *gin.RouterGroup, db database.Database) { g.Use(scopeIDMiddleware(db)) g.GET("/", handler("projects", func(c *gin.Context) (interface{}, error) { return db.Projects(getScope(c).ID).List(c.Request.Context()) })) g.GET("/:id", handler("project", func(c *gin.Context) (interface{}, error) { id, err := reqInt(c, "id") if err != nil { return nil, err } return db.Projects(getScope(c).ID).Find(c.Request.Context(), id) })) g.POST("/", handler("project", func(c *gin.Context) (interface{}, error) { project := &models.Project{} err := c.BindJSON(project) if err != nil { return nil, slerrors.BadRequest("Invalid JSON input: " + err.Error()) } if !project.Status.Valid() { return nil, slerrors.BadRequest("Unknown/unsupported project status") } if project.Name == "" { return nil, slerrors.BadRequest("Project name cannot be blank") } if len(project.Requirements) > 0 { return nil, slerrors.BadRequest("You cannot submit requirements this way") } project.OwnerID = auth.UserID(c) project.CreatedTime = time.Now() return db.Projects(getScope(c).ID).Create(c.Request.Context(), *project) })) g.PUT("/:id", handler("project", func(c *gin.Context) (interface{}, error) { id, err := reqInt(c, "id") if err != nil { return nil, err } update := &models.ProjectUpdate{} err = c.BindJSON(update) if err != nil { return nil, slerrors.BadRequest("Invalid JSON input: " + err.Error()) } project, err := db.Projects(getScope(c).ID).Find(c.Request.Context(), id) if err != nil { return nil, err } return db.Projects(getScope(c).ID).Update(c.Request.Context(), *project, *update) })) g.POST("/:id/requirements", handler("project", func(c *gin.Context) (interface{}, error) { id, err := reqInt(c, "id") if err != nil { return nil, err } requirement := &models.ProjectRequirement{} err = c.BindJSON(requirement) if err != nil { return nil, slerrors.BadRequest("Invalid JSON input: " + err.Error()) } if requirement.Name == "" { return nil, slerrors.BadRequest("Requirement name cannot be empty.") } if !requirement.Status.Valid() { return nil, slerrors.BadRequest("Bad requirement status.") } for _, stat := range requirement.Stats { if getScope(c).Stat(stat.ID) == nil { return nil, slerrors.Forbidden("One or more stats are not part of scope.") } if stat.Required < 0 { return nil, slerrors.BadRequest("-1 stats are not allowed when creating project requirements.") } } project, err := db.Projects(getScope(c).ID).Find(c.Request.Context(), id) if err != nil { return nil, err } return db.Projects(getScope(c).ID).AddRequirement(c.Request.Context(), project.ProjectEntry, *requirement) })) g.PUT("/:id/requirements/:rid", handler("project", func(c *gin.Context) (interface{}, error) { id, err := reqInt(c, "id") if err != nil { return nil, err } rid, err := reqInt(c, "rid") if err != nil { return nil, err } update := &models.ProjectRequirementUpdate{} err = c.BindJSON(update) if err != nil { return nil, slerrors.BadRequest("Invalid JSON input: " + err.Error()) } if update.Name != nil && *update.Name == "" { return nil, slerrors.BadRequest("Requirement name cannot be empty.") } if update.Status != nil && !update.Status.Valid() { return nil, slerrors.BadRequest("Bad requirement status.") } for _, stat := range update.Stats { if getScope(c).Stat(stat.ID) == nil { return nil, slerrors.Forbidden("One or more stats are not part of scope.") } } project, err := db.Projects(getScope(c).ID).Find(c.Request.Context(), id) if err != nil { return nil, err } requirement := project.Requirement(rid) if requirement == nil { return nil, slerrors.NotFound("Project requirement") } return db.Projects(getScope(c).ID).UpdateRequirement(c.Request.Context(), project.ProjectEntry, *requirement, *update) })) g.DELETE("/:id/requirements/:rid", handler("project", func(c *gin.Context) (interface{}, error) { deleteItems := c.Query("deleteItems") == "true" id, err := reqInt(c, "id") if err != nil { return nil, err } rid, err := reqInt(c, "rid") if err != nil { return nil, err } project, err := db.Projects(getScope(c).ID).Find(c.Request.Context(), id) if err != nil { return nil, err } requirement := project.Requirement(rid) if requirement == nil { return nil, slerrors.NotFound("Project requirement") } return db.Projects(getScope(c).ID).DeleteRequirement(c.Request.Context(), project.ProjectEntry, *requirement, deleteItems) })) g.DELETE("/:id", handler("project", func(c *gin.Context) (interface{}, error) { deleteItems := c.Query("deleteItems") == "true" id, err := reqInt(c, "id") if err != nil { return nil, err } project, err := db.Projects(getScope(c).ID).Find(c.Request.Context(), id) if err != nil { return nil, err } err = db.Projects(getScope(c).ID).Delete(c.Request.Context(), project.ProjectEntry, deleteItems) if err != nil { return nil, err } return project, nil })) }