diff --git a/console/graph.go b/console/graph.go index 1689daa6..0ed58605 100644 --- a/console/graph.go +++ b/console/graph.go @@ -15,11 +15,11 @@ import ( // graphQuery describes the input for the /graph endpoint. type graphQuery struct { Start time.Time `json:"start" binding:"required"` - End time.Time `json:"end" binding:"required"` - Points int `json:"points" binding:"required"` // minimum number of points - Dimensions []queryColumn `json:"dimensions"` // group by ... - Limit int `json:"limit"` // limit product of dimensions - Filter queryFilter `json:"filter"` // where ... + End time.Time `json:"end" binding:"required,gtfield=Start"` + Points int `json:"points" binding:"required,min=5,max=2000"` // minimum number of points + Dimensions []queryColumn `json:"dimensions"` // group by ... + Limit int `json:"limit" binding:"isdefault|min=1,max=50"` // limit product of dimensions + Filter queryFilter `json:"filter"` // where ... } // graphQueryToSQL converts a graph query to an SQL request @@ -96,21 +96,6 @@ func (c *Component) graphHandlerFunc(gc *gin.Context) { gc.JSON(http.StatusBadRequest, gin.H{"message": helpers.Capitalize(err.Error())}) return } - if query.Start.After(query.End) { - gc.JSON(http.StatusBadRequest, gin.H{"message": "Start should not be after end"}) - return - } - if query.Points < 5 || query.Points > 2000 { - gc.JSON(http.StatusBadRequest, gin.H{"message": "Points should be >= 5 and <= 2000"}) - return - } - if query.Limit == 0 { - query.Limit = 10 - } - if query.Limit < 5 || query.Limit > 50 { - gc.JSON(http.StatusBadRequest, gin.H{"message": "Limit should be >= 5 and <= 50"}) - return - } sqlQuery, err := query.toSQL() if err != nil { diff --git a/console/widgets.go b/console/widgets.go index 62f99eee..209f3c79 100644 --- a/console/widgets.go +++ b/console/widgets.go @@ -4,9 +4,10 @@ import ( "fmt" "net/http" "reflect" - "strconv" "time" + "akvorado/common/helpers" + "github.com/gin-gonic/gin" ) @@ -169,19 +170,22 @@ LIMIT 5 gc.JSON(http.StatusOK, gin.H{"top": results}) } +type widgetParameters struct { + Points uint64 `form:"points" binding:"isdefault|min=5,max=1000"` +} + func (c *Component) widgetGraphHandlerFunc(gc *gin.Context) { ctx := c.t.Context(gc.Request.Context()) - points, err := strconv.ParseUint(gc.DefaultQuery("points", "200"), 10, 16) - if err != nil { - gc.JSON(http.StatusBadRequest, gin.H{"message": "Invalid value for points."}) + var params widgetParameters + if err := gc.ShouldBindQuery(¶ms); err != nil { + gc.JSON(http.StatusBadRequest, gin.H{"message": helpers.Capitalize(err.Error())}) return } - if points < 5 || points > 1000 { - gc.JSON(http.StatusBadRequest, gin.H{"message": "Points should be > 5 and < 1000"}) - return + if params.Points == 0 { + params.Points = 200 } - interval := int64((24 * time.Hour).Seconds()) / int64(points) + interval := int64((24 * time.Hour).Seconds()) / int64(params.Points) now := c.d.Clock.Now() query := c.queryFlowsTable(fmt.Sprintf(` WITH @@ -200,7 +204,7 @@ ORDER BY Time`, interval), now.Add(-24*time.Hour), now, time.Duration(interval)* Time time.Time `json:"t"` Gbps float64 `json:"gbps"` }{} - err = c.d.ClickHouseDB.Conn.Select(ctx, &results, query) + err := c.d.ClickHouseDB.Conn.Select(ctx, &results, query) if err != nil { c.r.Err(err).Msg("unable to query database") gc.JSON(http.StatusInternalServerError, gin.H{"message": "Unable to query database."}) diff --git a/inlet/core/http.go b/inlet/core/http.go index 359c542a..3c7139c9 100644 --- a/inlet/core/http.go +++ b/inlet/core/http.go @@ -5,6 +5,8 @@ import ( "sync/atomic" "time" + "akvorado/common/helpers" + "github.com/gin-gonic/gin" ) @@ -17,9 +19,10 @@ type flowsParameters struct { // is intended for debug only. func (c *Component) FlowsHTTPHandler(gc *gin.Context) { var params flowsParameters - var limit, count uint64 - if gc.ShouldBindQuery(¶ms) == nil { - limit = params.Limit + var count uint64 + if err := gc.ShouldBindQuery(¶ms); err != nil { + gc.JSON(http.StatusBadRequest, gin.H{"message": helpers.Capitalize(err.Error())}) + return } atomic.AddUint32(&c.httpFlowClients, 1) @@ -36,14 +39,14 @@ func (c *Component) FlowsHTTPHandler(gc *gin.Context) { case <-gc.Request.Context().Done(): return case msg := <-c.httpFlowChannel: - if limit == 1 { + if params.Limit == 1 { gc.IndentedJSON(http.StatusOK, msg) } else { gc.JSON(http.StatusOK, msg) gc.Writer.Write([]byte("\n")) } count++ - if limit > 0 && count == limit { + if params.Limit > 0 && count == params.Limit { return } case <-tickerChan: