Loggest thine Stuff
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.
 
 
 
 
 
 

322 lines
8.4 KiB

package httpapi
import (
"encoding/json"
"fmt"
"git.aiterp.net/stufflog3/stufflog3/entities"
"git.aiterp.net/stufflog3/stufflog3/models"
"git.aiterp.net/stufflog3/stufflog3/usecases/items"
"github.com/gin-gonic/gin"
"strconv"
"strings"
"time"
)
func ItemsAllScopes(g *gin.RouterGroup, items *items.Service) {
g.GET("", handler("items", func(c *gin.Context) (interface{}, error) {
filter, err := getItemFilterFromQuery(c)
if err != nil {
return nil, err
}
return items.ListAllScopes(c.Request.Context(), filter)
}))
}
func Items(g *gin.RouterGroup, items *items.Service) {
g.GET("/:item_id", handler("project", func(c *gin.Context) (interface{}, error) {
id, err := reqInt(c, "item_id")
if err != nil {
return nil, err
}
return items.Find(c.Request.Context(), id)
}))
g.GET("", handler("items", func(c *gin.Context) (interface{}, error) {
filter, err := getItemFilterFromQuery(c)
if err != nil {
return nil, err
}
return items.ListScoped(c.Request.Context(), filter)
}))
g.POST("", handler("item", func(c *gin.Context) (interface{}, error) {
input := struct {
entities.Item
Stats []entities.ItemStat `json:"stats"`
}{}
err := c.BindJSON(&input)
if err != nil {
return nil, models.BadInputError{
Object: "Project",
Problem: "Invalid JSON: " + err.Error(),
}
}
return items.Create(c.Request.Context(), input.Item, input.Stats)
}))
g.PUT("/:item_id", handler("item", func(c *gin.Context) (interface{}, error) {
input := struct {
models.ItemUpdate
Stats []entities.ItemStat `json:"stats"`
}{}
err := c.BindJSON(&input)
if err != nil {
return nil, models.BadInputError{
Object: "Project",
Problem: "Invalid JSON: " + err.Error(),
}
}
id, err := reqInt(c, "item_id")
if err != nil {
return nil, err
}
return items.Update(c.Request.Context(), id, input.ItemUpdate, input.Stats)
}))
g.PUT("/:item_id/stats/:stat_id", handler("item", func(c *gin.Context) (interface{}, error) {
input := entities.ItemStat{}
err := c.BindJSON(&input)
if err != nil {
return nil, models.BadInputError{
Object: "Project",
Problem: "Invalid JSON: " + err.Error(),
}
}
itemID, err := reqInt(c, "item_id")
if err != nil {
return nil, err
}
statID, err := reqInt(c, "stat_id")
if err != nil {
return nil, err
}
input.StatID = statID
return items.UpdateStat(c.Request.Context(), itemID, input)
}))
g.DELETE("/:item_id/stats/:stat_id", handler("item", func(c *gin.Context) (interface{}, error) {
itemID, err := reqInt(c, "item_id")
if err != nil {
return nil, err
}
statID, err := reqInt(c, "stat_id")
if err != nil {
return nil, err
}
return items.DeleteStat(c.Request.Context(), itemID, statID)
}))
g.DELETE("/:item_id", handler("item", func(c *gin.Context) (interface{}, error) {
id, err := reqInt(c, "item_id")
if err != nil {
return nil, err
}
return items.Delete(c.Request.Context(), id)
}))
}
func getItemFilterFromQuery(c *gin.Context) (models.ItemFilter, error) {
filter := models.ItemFilter{}
if rawFilter := c.Query("filter"); rawFilter != "" {
err := json.Unmarshal([]byte(rawFilter), &filter)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: "filter",
Problem: "Invalid raw filter: " + err.Error(),
}
}
}
if queryOwnerId := c.Query("ownerId"); queryOwnerId != "" {
filter.OwnerID = &queryOwnerId
}
queryScheduledMin := c.Query("scheduledMin")
queryScheduledMax := c.Query("scheduledMax")
if queryScheduledMin != "" && queryScheduledMax != "" {
min, err := models.ParseDate(queryScheduledMin)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: "scheduledMin",
Problem: "Invalid from date: " + err.Error(),
}
}
max, err := models.ParseDate(queryScheduledMax)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: "scheduledMax",
Problem: "Invalid to date: " + err.Error(),
}
}
filter.ScheduledDate = &models.TimeInterval[models.Date]{Min: min, Max: max}
}
queryCreatedMin := c.Query("createdMin")
queryCreatedMax := c.Query("createdMax")
if queryCreatedMin != "" && queryCreatedMax != "" {
min, err := time.Parse(time.RFC3339, queryCreatedMin)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: "createdMin",
Problem: "Invalid from date: " + err.Error(),
}
}
max, err := time.Parse(time.RFC3339, queryCreatedMax)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: "createdMax",
Problem: "Invalid to date: " + err.Error(),
}
}
filter.CreatedTime = &models.TimeInterval[time.Time]{Min: min, Max: max}
}
queryAcquiredMin := c.Query("acquiredMin")
queryAcquiredMax := c.Query("acquiredMax")
if queryAcquiredMin != "" && queryAcquiredMax != "" {
min, err := time.Parse(time.RFC3339, queryAcquiredMin)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: "acquiredMin",
Problem: "Invalid from date: " + err.Error(),
}
}
max, err := time.Parse(time.RFC3339, queryAcquiredMax)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: "acquiredMax",
Problem: "Invalid to date: " + err.Error(),
}
}
filter.AcquiredTime = &models.TimeInterval[time.Time]{Min: min, Max: max}
}
anyDateMin := c.Query("anyDateMin")
anyDateMax := c.Query("anyDateMax")
if anyDateMin != "" && anyDateMax != "" {
min, err := time.Parse(time.RFC3339, anyDateMin)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: "anyDateMin",
Problem: "Invalid from date: " + err.Error(),
}
}
max, err := time.Parse(time.RFC3339, anyDateMax)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: "anyDateMax",
Problem: "Invalid to date: " + err.Error(),
}
}
minY, minM, minD := min.Date()
maxY, maxM, maxD := max.Date()
filter.AcquiredTime = &models.TimeInterval[time.Time]{Min: min, Max: max}
filter.CreatedTime = &models.TimeInterval[time.Time]{Min: min, Max: max}
filter.ScheduledDate = &models.TimeInterval[models.Date]{
Min: models.Date{minY, int(minM), minD},
Max: models.Date{maxY, int(maxM), maxD},
}
}
if queryProjectID := c.Query("projectId"); queryProjectID != "" {
ids := strings.Split(queryProjectID, ",")
for _, id := range ids {
parsed, err := strconv.Atoi(id)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: fmt.Sprintf("projectId[%d]", len(filter.ProjectIDs)),
Problem: "Invalid number",
}
}
filter.ProjectIDs = append(filter.ProjectIDs, parsed)
}
}
if queryRequirementID := c.Query("requirementId"); queryRequirementID != "" {
if queryRequirementID != "null" {
ids := strings.Split(queryRequirementID, ",")
for _, id := range ids {
parsed, err := strconv.Atoi(id)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: fmt.Sprintf("requirementId[%d]", len(filter.RequirementIDs)),
Problem: "Invalid number",
}
}
filter.RequirementIDs = append(filter.RequirementIDs, parsed)
}
} else {
filter.Loose = true
}
}
if statID := c.Query("statId"); statID != "" {
ids := strings.Split(statID, ",")
for _, id := range ids {
parsed, err := strconv.Atoi(id)
if err != nil {
return models.ItemFilter{}, models.BadInputError{
Object: "Query",
Field: fmt.Sprintf("statId[%d]", len(filter.StatIDs)),
Problem: "Invalid number",
}
}
filter.StatIDs = append(filter.StatIDs, parsed)
}
}
if filter.ScheduledDate != nil && !filter.ScheduledDate.Valid() {
return models.ItemFilter{}, models.BadInputError{
Object: "Filter",
Field: "scheduledDate",
Problem: "Invalid scheduled date range",
}
}
if filter.CreatedTime != nil && !filter.CreatedTime.Valid() {
return models.ItemFilter{}, models.BadInputError{
Object: "Filter",
Field: "createdTime",
Problem: "Invalid created time range",
}
}
if filter.AcquiredTime != nil && !filter.AcquiredTime.Valid() {
return models.ItemFilter{}, models.BadInputError{
Object: "Filter",
Field: "acquiredTime",
Problem: "Invalid created time range",
}
}
return filter, nil
}