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
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
|
|
}
|