package api import ( "github.com/gin-gonic/gin" "github.com/gissleh/stufflog/database" "github.com/gissleh/stufflog/internal/auth" "github.com/gissleh/stufflog/internal/generate" "github.com/gissleh/stufflog/internal/slerrors" "github.com/gissleh/stufflog/models" "github.com/gissleh/stufflog/services" "strings" "time" ) func Project(g *gin.RouterGroup, db database.Database) { l := services.Loader{DB: db} g.GET("/", handler("projects", func(c *gin.Context) (interface{}, error) { filter := models.ProjectFilter{} if setting := c.Query("active"); setting != "" { active := setting == "true" filter.Active = &active } if setting := c.Query("include-semi-active"); setting != "" { filter.IncludeSemiActive = setting == "true" } if setting := c.Query("expiring"); setting != "" { filter.Expiring = setting == "true" } if setting := c.Query("favorite"); setting != "" { favorite := setting == "true" filter.Favorite = &favorite } if setting := c.Query("ungrouped"); setting != "" { filter.Ungrouped = setting == "true" } if setting := c.Query("groups"); setting != "" { filter.ProjectGroupIDs = strings.Split(setting, ",") } return l.ListProjects(c, filter) })) g.GET("/:id", handler("project", func(c *gin.Context) (interface{}, error) { return l.FindProject(c, c.Param("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") } if project.EndTime != nil && project.EndTime.Before(time.Now()) { return nil, slerrors.BadRequest("Project end time must be later than current time.") } if project.StartTime != nil && (project.EndTime == nil || !project.StartTime.Before(*project.EndTime)) { return nil, slerrors.BadRequest("Project start time must be before end time.") } project.ID = generate.ProjectID() project.UserID = auth.UserID(c) project.CreatedTime = time.Now().UTC() if project.GroupID != nil && *project.GroupID == "" { project.GroupID = nil } err = db.Projects().Insert(c.Request.Context(), project) if err != nil { return nil, err } if project.Active && project.StatusTag != nil { project.StatusTag = nil } if project.SubtractAmount < 0 { project.SubtractAmount = 0 } return &models.ProjectResult{ Project: project, Tasks: []*models.TaskResult{}, }, nil })) g.PUT("/:id", handler("project", func(c *gin.Context) (interface{}, error) { update := models.ProjectUpdate{} err := c.BindJSON(&update) if err != nil { return nil, slerrors.BadRequest("Invalid JSON") } project, err := l.FindProject(c.Request.Context(), c.Param("id")) if err != nil { return nil, err } project.Update(update) if project.StartTime != nil && (project.EndTime == nil || !project.StartTime.Before(*project.EndTime)) { return nil, slerrors.BadRequest("Project start time must be before end time.") } err = db.Projects().Update(c.Request.Context(), project.Project) if err != nil { return nil, err } return project, nil })) g.DELETE("/:id", handler("project", func(c *gin.Context) (interface{}, error) { project, err := l.FindProject(c.Request.Context(), c.Param("id")) if err != nil { return nil, err } if len(project.Tasks) > 0 { return nil, slerrors.Forbidden("cannot delete non-empty projects.") } err = db.Projects().Delete(c.Request.Context(), project.Project) if err != nil { return nil, err } return project, nil })) }