You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
4.8 KiB
165 lines
4.8 KiB
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 Items(g *gin.RouterGroup, db database.Database) {
|
|
g.Use(scopeIDMiddleware(db))
|
|
|
|
g.GET("/", handler("items", func(c *gin.Context) (res interface{}, err error) {
|
|
mode := c.Query("mode")
|
|
|
|
var fromTime, toTime time.Time
|
|
var fromDate, toDate models.Date
|
|
if mode != "scheduled" {
|
|
if c.Query("to") == "" {
|
|
toTime = time.Now()
|
|
} else {
|
|
toTime, err = time.Parse(time.RFC3339Nano, c.Query("to"))
|
|
if err != nil {
|
|
return nil, slerrors.BadRequest("Invalid value for to")
|
|
}
|
|
}
|
|
if c.Query("from") == "" {
|
|
fromTime = time.Now().Add(-time.Hour * 24 * 30)
|
|
} else {
|
|
fromTime, err = time.Parse(time.RFC3339Nano, c.Query("from"))
|
|
if err != nil {
|
|
return nil, slerrors.BadRequest("Invalid value for from")
|
|
}
|
|
}
|
|
if toTime.After(toTime) {
|
|
return nil, slerrors.BadRequest("the flow of time itself is convoluted, but not so for the database")
|
|
}
|
|
} else {
|
|
if c.Query("to") == "" {
|
|
toDate, _ = models.ParseDate(time.Now().Add(time.Hour * 24 * 7).Format("2006-01-02"))
|
|
} else {
|
|
toDate, err = models.ParseDate(c.Query("to"))
|
|
if err != nil {
|
|
return nil, slerrors.BadRequest("Invalid value for to")
|
|
}
|
|
}
|
|
if c.Query("from") == "" {
|
|
fromDate, _ = models.ParseDate(time.Now().Format("2006-01-02"))
|
|
} else {
|
|
fromDate, err = models.ParseDate(c.Query("from"))
|
|
if err != nil {
|
|
return nil, slerrors.BadRequest("Invalid value for from")
|
|
}
|
|
}
|
|
}
|
|
|
|
switch mode {
|
|
case "", "created":
|
|
return db.Items(getScope(c).ID).ListCreated(c.Request.Context(), fromTime, toTime)
|
|
case "acquired":
|
|
return db.Items(getScope(c).ID).ListAcquired(c.Request.Context(), fromTime, toTime)
|
|
case "loose":
|
|
return db.Items(getScope(c).ID).ListLoose(c.Request.Context(), fromTime, toTime)
|
|
case "scheduled":
|
|
return db.Items(getScope(c).ID).ListScheduled(c.Request.Context(), fromDate, toDate)
|
|
default:
|
|
return nil, slerrors.BadRequest("unknown mode")
|
|
}
|
|
}))
|
|
|
|
g.GET("/:id", handler("item", func(c *gin.Context) (interface{}, error) {
|
|
id, err := reqInt(c, "id")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return db.Items(getScope(c).ID).Find(c.Request.Context(), id)
|
|
}))
|
|
|
|
g.POST("/", handler("item", func(c *gin.Context) (interface{}, error) {
|
|
item := &models.Item{}
|
|
err := c.BindJSON(item)
|
|
if err != nil {
|
|
return nil, slerrors.BadRequest("Invalid JSON input: " + err.Error())
|
|
}
|
|
|
|
item.CreatedTime = time.Now()
|
|
|
|
if item.Name == "" {
|
|
return nil, slerrors.BadRequest("Blank item name not allowed")
|
|
}
|
|
if item.OwnerID == "" {
|
|
item.OwnerID = auth.UserID(c)
|
|
} else if getScope(c).HasMember(item.OwnerID) {
|
|
return nil, slerrors.Forbidden("Owner is not part of scope.")
|
|
}
|
|
for _, stat := range item.Stats {
|
|
if getScope(c).Stat(stat.ID) == nil {
|
|
return nil, slerrors.Forbidden("One or more stats are not part of scope.")
|
|
}
|
|
if stat.Acquired == 0 && stat.Required == 0 {
|
|
return nil, slerrors.BadRequest("0/0 stats are not allowed when creating items.")
|
|
}
|
|
}
|
|
|
|
return db.Items(getScope(c).ID).Create(c.Request.Context(), *item)
|
|
}))
|
|
|
|
g.PUT("/:id", handler("item", func(c *gin.Context) (interface{}, error) {
|
|
id, err := reqInt(c, "id")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
update := &models.ItemUpdate{}
|
|
err = c.BindJSON(update)
|
|
if err != nil {
|
|
return nil, slerrors.BadRequest("Invalid JSON input: " + err.Error())
|
|
}
|
|
|
|
item, err := db.Items(getScope(c).ID).Find(c.Request.Context(), id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if update.Name != nil && *update.Name == "" {
|
|
return nil, slerrors.BadRequest("Blank item name not allowed")
|
|
}
|
|
if update.OwnerID != nil || !getScope(c).HasMember(item.OwnerID) {
|
|
return nil, slerrors.Forbidden("New item is not part of scope.")
|
|
}
|
|
for _, stat := range update.Stats {
|
|
statRef := getScope(c).Stat(stat.ID)
|
|
if stat.Required != 0 && stat.Acquired != 0 && statRef == nil {
|
|
return nil, slerrors.Forbidden("One or more stats are not part of the scope.")
|
|
}
|
|
if !statRef.AllowsAmount(stat.Required) {
|
|
return nil, slerrors.Forbidden("One or more stats have a disallowed required amount.")
|
|
}
|
|
}
|
|
|
|
return db.Items(getScope(c).ID).Update(c.Request.Context(), *item, *update)
|
|
}))
|
|
|
|
g.DELETE("/:id", handler("item", func(c *gin.Context) (interface{}, error) {
|
|
id, err := reqInt(c, "id")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
item, err := db.Items(getScope(c).ID).Find(c.Request.Context(), id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = db.Items(getScope(c).ID).Delete(c.Request.Context(), *item)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return item, nil
|
|
}))
|
|
}
|