mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-30 00:00:12 +01:00
- revise testing of widget enpoints
- add validators for widgets - revise implementation of widget endpoints - clean up testdata, serializers and response - improve documentation for swaggo
This commit is contained in:
parent
7c7488ee00
commit
e3651e34f0
9 changed files with 594 additions and 254 deletions
|
@ -1,23 +1,5 @@
|
|||
package common
|
||||
|
||||
import "github.com/jinzhu/gorm/dialects/postgres"
|
||||
|
||||
type WidgetResponse struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Width uint `json:"width"`
|
||||
Height uint `json:"height"`
|
||||
MinWidth uint `json:"minWidth"`
|
||||
MinHeight uint `json:"minHeight"`
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
Z int `json:"z"`
|
||||
DashboardID uint `json:"dashboardID"`
|
||||
IsLocked bool `json:"isLocked"`
|
||||
CustomProperties postgres.Jsonb `json:"customProperties"`
|
||||
}
|
||||
|
||||
type FileResponse struct {
|
||||
Name string `json:"name"`
|
||||
ID uint `json:"id"`
|
||||
|
@ -52,14 +34,6 @@ type ResponseMsgSignal struct {
|
|||
Signal SignalResponse `json:"signal"`
|
||||
}
|
||||
|
||||
type ResponseMsgWidgets struct {
|
||||
Widgets []WidgetResponse `json:"widgets"`
|
||||
}
|
||||
|
||||
type ResponseMsgWidget struct {
|
||||
Widget WidgetResponse `json:"widget"`
|
||||
}
|
||||
|
||||
type ResponseMsgFiles struct {
|
||||
Files []FileResponse `json:"files"`
|
||||
}
|
||||
|
|
|
@ -4,47 +4,6 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Widget/s Serializers
|
||||
|
||||
type WidgetsSerializer struct {
|
||||
Ctx *gin.Context
|
||||
Widgets []Widget
|
||||
}
|
||||
|
||||
func (self *WidgetsSerializer) Response() []WidgetResponse {
|
||||
response := []WidgetResponse{}
|
||||
for _, widget := range self.Widgets {
|
||||
serializer := WidgetSerializer{self.Ctx, widget}
|
||||
response = append(response, serializer.Response())
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
type WidgetSerializer struct {
|
||||
Ctx *gin.Context
|
||||
Widget
|
||||
}
|
||||
|
||||
func (self *WidgetSerializer) Response() WidgetResponse {
|
||||
|
||||
response := WidgetResponse{
|
||||
ID: self.ID,
|
||||
Name: self.Name,
|
||||
Type: self.Type,
|
||||
Width: self.Width,
|
||||
Height: self.Height,
|
||||
MinWidth: self.MinWidth,
|
||||
MinHeight: self.MinHeight,
|
||||
X: self.X,
|
||||
Y: self.Y,
|
||||
Z: self.Z,
|
||||
DashboardID: self.DashboardID,
|
||||
IsLocked: self.IsLocked,
|
||||
CustomProperties: self.CustomProperties,
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
// File/s Serializers
|
||||
|
||||
type FilesSerializerNoAssoc struct {
|
||||
|
|
|
@ -265,7 +265,6 @@ var FileD = File{
|
|||
// Widgets
|
||||
var customPropertiesA = json.RawMessage(`{"property1" : "testValue1A", "property2" : "testValue2A", "property3" : 42}`)
|
||||
var customPropertiesB = json.RawMessage(`{"property1" : "testValue1B", "property2" : "testValue2B", "property3" : 43}`)
|
||||
var customPropertiesC = json.RawMessage(`{"property1" : "testValue1C", "property2" : "testValue2C", "property3" : 44}`)
|
||||
|
||||
var WidgetA = Widget{
|
||||
Name: "Widget_A",
|
||||
|
@ -281,21 +280,6 @@ var WidgetA = Widget{
|
|||
CustomProperties: postgres.Jsonb{customPropertiesA},
|
||||
}
|
||||
|
||||
var WidgetA_response = WidgetResponse{
|
||||
ID: 1,
|
||||
Name: WidgetA.Name,
|
||||
Type: WidgetA.Type,
|
||||
Width: WidgetA.Width,
|
||||
Height: WidgetA.Height,
|
||||
MinWidth: WidgetA.MinWidth,
|
||||
MinHeight: WidgetA.MinHeight,
|
||||
X: WidgetA.X,
|
||||
Y: WidgetA.Y,
|
||||
Z: WidgetA.Z,
|
||||
IsLocked: WidgetA.IsLocked,
|
||||
CustomProperties: WidgetA.CustomProperties,
|
||||
}
|
||||
|
||||
var WidgetB = Widget{
|
||||
Name: "Widget_B",
|
||||
Type: "slider",
|
||||
|
@ -305,66 +289,7 @@ var WidgetB = Widget{
|
|||
MinWidth: 50,
|
||||
X: 100,
|
||||
Y: -40,
|
||||
Z: 0,
|
||||
Z: -1,
|
||||
IsLocked: false,
|
||||
CustomProperties: postgres.Jsonb{customPropertiesB},
|
||||
}
|
||||
|
||||
var WidgetB_response = WidgetResponse{
|
||||
ID: 2,
|
||||
Name: WidgetB.Name,
|
||||
Type: WidgetB.Type,
|
||||
Width: WidgetB.Width,
|
||||
Height: WidgetB.Height,
|
||||
MinWidth: WidgetB.MinWidth,
|
||||
MinHeight: WidgetB.MinHeight,
|
||||
X: WidgetB.X,
|
||||
Y: WidgetB.Y,
|
||||
Z: WidgetB.Z,
|
||||
IsLocked: WidgetB.IsLocked,
|
||||
CustomProperties: WidgetB.CustomProperties,
|
||||
}
|
||||
|
||||
var WidgetC = Widget{
|
||||
Name: "Widget_C",
|
||||
Type: "bargraph",
|
||||
Height: 30,
|
||||
Width: 100,
|
||||
MinHeight: 20,
|
||||
MinWidth: 50,
|
||||
X: 11,
|
||||
Y: 12,
|
||||
Z: 13,
|
||||
IsLocked: false,
|
||||
CustomProperties: postgres.Jsonb{customPropertiesC},
|
||||
}
|
||||
|
||||
var WidgetC_response = WidgetResponse{
|
||||
ID: 3,
|
||||
Name: WidgetC.Name,
|
||||
Type: WidgetC.Type,
|
||||
Width: WidgetC.Width,
|
||||
Height: WidgetC.Height,
|
||||
MinWidth: WidgetC.MinWidth,
|
||||
MinHeight: WidgetC.MinHeight,
|
||||
X: WidgetC.X,
|
||||
Y: WidgetC.Y,
|
||||
Z: WidgetC.Z,
|
||||
IsLocked: WidgetC.IsLocked,
|
||||
CustomProperties: WidgetC.CustomProperties,
|
||||
}
|
||||
|
||||
var WidgetCUpdated_response = WidgetResponse{
|
||||
ID: 3,
|
||||
Name: "Widget_CUpdated",
|
||||
Type: WidgetC.Type,
|
||||
Height: 35,
|
||||
Width: 110,
|
||||
MinHeight: WidgetC.MinHeight,
|
||||
MinWidth: WidgetC.MinWidth,
|
||||
X: WidgetC.X,
|
||||
Y: WidgetC.Y,
|
||||
Z: WidgetC.Z,
|
||||
IsLocked: WidgetC.IsLocked,
|
||||
CustomProperties: WidgetC.CustomProperties,
|
||||
}
|
||||
|
|
|
@ -56,3 +56,11 @@ type ResponseDashboards struct {
|
|||
type ResponseDashboard struct {
|
||||
dashboard common.Dashboard
|
||||
}
|
||||
|
||||
type ResponseWidgets struct {
|
||||
widgets []common.Widget
|
||||
}
|
||||
|
||||
type ResponseWidget struct {
|
||||
widget common.Widget
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package widget
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -22,11 +23,10 @@ func RegisterWidgetEndpoints(r *gin.RouterGroup) {
|
|||
// @ID getWidgets
|
||||
// @Produce json
|
||||
// @Tags widgets
|
||||
// @Success 200 {array} common.WidgetResponse "Array of widgets to which belong to dashboard"
|
||||
// @Failure 401 "Unauthorized Access"
|
||||
// @Failure 403 "Access forbidden."
|
||||
// @Failure 404 "Not found"
|
||||
// @Failure 500 "Internal server error"
|
||||
// @Success 200 {object} docs.ResponseWidgets "Widgets to which belong to dashboard"
|
||||
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||
// @Param dashboardID query int true "Dashboard ID"
|
||||
// @Router /widgets [get]
|
||||
func getWidgets(c *gin.Context) {
|
||||
|
@ -43,9 +43,8 @@ func getWidgets(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
serializer := common.WidgetsSerializer{c, widgets}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"widgets": serializer.Response(),
|
||||
"widgets": widgets,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -55,51 +54,51 @@ func getWidgets(c *gin.Context) {
|
|||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags widgets
|
||||
// @Param inputWidget body common.ResponseMsgWidget true "Widget to be added incl. ID of dashboard"
|
||||
// @Success 200 "OK."
|
||||
// @Failure 401 "Unauthorized Access"
|
||||
// @Failure 403 "Access forbidden."
|
||||
// @Failure 404 "Not found"
|
||||
// @Failure 500 "Internal server error"
|
||||
// @Param inputWidget body widget.validNewWidget true "Widget to be added incl. ID of dashboard"
|
||||
// @Success 200 {object} docs.ResponseWidget "Widget that was added"
|
||||
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||
// @Router /widgets [post]
|
||||
func addWidget(c *gin.Context) {
|
||||
|
||||
var newWidgetData common.ResponseMsgWidget
|
||||
err := c.BindJSON(&newWidgetData)
|
||||
if err != nil {
|
||||
errormsg := "Bad request. Error binding form data to JSON: " + err.Error()
|
||||
var req addWidgetRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": errormsg,
|
||||
"success": false,
|
||||
"message": fmt.Sprintf("%v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var newWidget Widget
|
||||
newWidget.Name = newWidgetData.Widget.Name
|
||||
newWidget.Type = newWidgetData.Widget.Type
|
||||
newWidget.Height = newWidgetData.Widget.Height
|
||||
newWidget.Width = newWidgetData.Widget.Width
|
||||
newWidget.MinHeight = newWidgetData.Widget.MinHeight
|
||||
newWidget.MinWidth = newWidgetData.Widget.MinWidth
|
||||
newWidget.X = newWidgetData.Widget.X
|
||||
newWidget.Y = newWidgetData.Widget.Y
|
||||
newWidget.Z = newWidgetData.Widget.Z
|
||||
newWidget.CustomProperties = newWidgetData.Widget.CustomProperties
|
||||
newWidget.IsLocked = newWidgetData.Widget.IsLocked
|
||||
newWidget.DashboardID = newWidgetData.Widget.DashboardID
|
||||
// Validate the request
|
||||
if err := req.validate(); err != nil {
|
||||
c.JSON(http.StatusUnprocessableEntity, gin.H{
|
||||
"success": false,
|
||||
"message": fmt.Sprintf("%v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Create the new widget from the request
|
||||
newWidget := req.createWidget()
|
||||
|
||||
// Check if user is allowed to modify selected dashboard (scenario)
|
||||
ok, _ := dashboard.CheckPermissions(c, common.Create, "body", int(newWidget.DashboardID))
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
err = newWidget.addToDashboard()
|
||||
|
||||
if common.ProvideErrorResponse(c, err) == false {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "OK.",
|
||||
})
|
||||
err := newWidget.addToDashboard()
|
||||
if err != nil {
|
||||
common.ProvideErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"widget": newWidget.Widget,
|
||||
})
|
||||
}
|
||||
|
||||
// updateWidget godoc
|
||||
|
@ -108,37 +107,60 @@ func addWidget(c *gin.Context) {
|
|||
// @Tags widgets
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param inputWidget body common.ResponseMsgWidget true "Widget to be updated"
|
||||
// @Success 200 "OK."
|
||||
// @Failure 401 "Unauthorized Access"
|
||||
// @Failure 403 "Access forbidden."
|
||||
// @Failure 404 "Not found"
|
||||
// @Failure 500 "Internal server error"
|
||||
// @Param inputWidget body widget.validUpdatedWidget true "Widget to be updated"
|
||||
// @Success 200 {object} docs.ResponseWidget "Widget that was updated"
|
||||
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||
// @Param widgetID path int true "Widget ID"
|
||||
// @Router /widgets/{widgetID} [put]
|
||||
func updateWidget(c *gin.Context) {
|
||||
|
||||
ok, w := CheckPermissions(c, common.Update, -1)
|
||||
ok, oldWidget := CheckPermissions(c, common.Update, -1)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var modifiedWidget common.ResponseMsgWidget
|
||||
err := c.BindJSON(&modifiedWidget)
|
||||
if err != nil {
|
||||
errormsg := "Bad request. Error binding form data to JSON: " + err.Error()
|
||||
var req updateWidgetRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": errormsg,
|
||||
"success": false,
|
||||
"message": fmt.Sprintf("%v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err = w.update(modifiedWidget.Widget)
|
||||
if common.ProvideErrorResponse(c, err) == false {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "OK.",
|
||||
// Validate the request
|
||||
if err := req.validate(); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"success": false,
|
||||
"message": fmt.Sprintf("%v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Create the updatedScenario from oldScenario
|
||||
updatedWidget, err := req.updatedWidget(oldWidget)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"success": false,
|
||||
"message": fmt.Sprintf("%v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Update the widget in the DB
|
||||
err = oldWidget.update(updatedWidget)
|
||||
if err != nil {
|
||||
common.ProvideErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"widget": updatedWidget.Widget,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// getWidget godoc
|
||||
|
@ -146,11 +168,11 @@ func updateWidget(c *gin.Context) {
|
|||
// @ID getWidget
|
||||
// @Tags widgets
|
||||
// @Produce json
|
||||
// @Success 200 {object} common.WidgetResponse "Requested widget."
|
||||
// @Failure 401 "Unauthorized Access"
|
||||
// @Failure 403 "Access forbidden."
|
||||
// @Failure 404 "Not found"
|
||||
// @Failure 500 "Internal server error"
|
||||
// @Success 200 {object} docs.ResponseWidget "Widget that was requested"
|
||||
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||
// @Param widgetID path int true "Widget ID"
|
||||
// @Router /widgets/{widgetID} [get]
|
||||
func getWidget(c *gin.Context) {
|
||||
|
@ -160,9 +182,8 @@ func getWidget(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
serializer := common.WidgetSerializer{c, w.Widget}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"widget": serializer.Response(),
|
||||
"widget": w.Widget,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -171,11 +192,11 @@ func getWidget(c *gin.Context) {
|
|||
// @ID deleteWidget
|
||||
// @Tags widgets
|
||||
// @Produce json
|
||||
// @Success 200 "OK."
|
||||
// @Failure 401 "Unauthorized Access"
|
||||
// @Failure 403 "Access forbidden."
|
||||
// @Failure 404 "Not found"
|
||||
// @Failure 500 "Internal server error"
|
||||
// @Success 200 {object} docs.ResponseWidget "Widget that was deleted"
|
||||
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||
// @Param widgetID path int true "Widget ID"
|
||||
// @Router /widgets/{widgetID} [delete]
|
||||
func deleteWidget(c *gin.Context) {
|
||||
|
@ -191,6 +212,6 @@ func deleteWidget(c *gin.Context) {
|
|||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "OK.",
|
||||
"widget": w.Widget,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package widget
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/dashboard"
|
||||
)
|
||||
|
@ -21,7 +19,7 @@ func (w *Widget) ByID(id uint) error {
|
|||
db := common.GetDB()
|
||||
err := db.Find(w, id).Error
|
||||
if err != nil {
|
||||
return fmt.Errorf("Widget with id=%v does not exist", id)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -46,7 +44,7 @@ func (w *Widget) addToDashboard() error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (w *Widget) update(modifiedWidget common.WidgetResponse) error {
|
||||
func (w *Widget) update(modifiedWidget Widget) error {
|
||||
|
||||
db := common.GetDB()
|
||||
err := db.Model(w).Updates(map[string]interface{}{
|
||||
|
|
|
@ -17,7 +17,10 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, widgetIDBody int) (
|
|||
|
||||
err := common.ValidateRole(c, common.ModelWidget, operation)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnprocessableEntity, "Access denied (role validation failed).")
|
||||
c.JSON(http.StatusUnprocessableEntity, gin.H{
|
||||
"success": false,
|
||||
"message": fmt.Sprintf("Access denied (role validation failed): %v", err),
|
||||
})
|
||||
return false, w
|
||||
}
|
||||
|
||||
|
@ -25,9 +28,10 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, widgetIDBody int) (
|
|||
if widgetIDBody < 0 {
|
||||
widgetID, err = strconv.Atoi(c.Param("widgetID"))
|
||||
if err != nil {
|
||||
errormsg := fmt.Sprintf("Bad request. No or incorrect format of widgetID path parameter")
|
||||
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": errormsg,
|
||||
"success": false,
|
||||
"message": fmt.Sprintf("Bad request. No or incorrect format of widgetID path parameter"),
|
||||
})
|
||||
return false, w
|
||||
}
|
||||
|
|
|
@ -1,65 +1,407 @@
|
|||
package widget
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"fmt"
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common"
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/dashboard"
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/scenario"
|
||||
"git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/user"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/jinzhu/gorm/dialects/postgres"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Test /widgets endpoints
|
||||
func TestWidgetEndpoints(t *testing.T) {
|
||||
var router *gin.Engine
|
||||
var db *gorm.DB
|
||||
|
||||
var token string
|
||||
type WidgetRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Width uint `json:"width,omitempty"`
|
||||
Height uint `json:"height,omitempty"`
|
||||
MinWidth uint `json:"minWidth,omitempty"`
|
||||
MinHeight uint `json:"minHeight,omitempty"`
|
||||
X int `json:"x,omitempty"`
|
||||
Y int `json:"y,omitempty"`
|
||||
Z int `json:"z,omitempty"`
|
||||
DashboardID uint `json:"dashboardID,omitempty"`
|
||||
IsLocked bool `json:"isLocked,omitempty"`
|
||||
CustomProperties postgres.Jsonb `json:"customProperties,omitempty"`
|
||||
}
|
||||
|
||||
var myWidgets = []common.WidgetResponse{common.WidgetA_response, common.WidgetB_response}
|
||||
var msgWidgets = common.ResponseMsgWidgets{Widgets: myWidgets}
|
||||
var msgWdg = common.ResponseMsgWidget{Widget: common.WidgetC_response}
|
||||
var msgWdgupdated = common.ResponseMsgWidget{Widget: common.WidgetCUpdated_response}
|
||||
type DashboardRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Grid int `json:"grid,omitempty"`
|
||||
ScenarioID uint `json:"scenarioID,omitempty"`
|
||||
}
|
||||
|
||||
db := common.DummyInitDB()
|
||||
type ScenarioRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Running bool `json:"running,omitempty"`
|
||||
StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
|
||||
}
|
||||
|
||||
func addScenarioAndDashboard(token string) (scenarioID uint, dashboardID uint) {
|
||||
|
||||
// POST $newScenario
|
||||
newScenario := ScenarioRequest{
|
||||
Name: common.ScenarioA.Name,
|
||||
Running: common.ScenarioA.Running,
|
||||
StartParameters: common.ScenarioA.StartParameters,
|
||||
}
|
||||
_, resp, _ := common.NewTestEndpoint(router, token,
|
||||
"/api/scenarios", "POST", common.KeyModels{"scenario": newScenario})
|
||||
|
||||
// Read newScenario's ID from the response
|
||||
newScenarioID, _ := common.GetResponseID(resp)
|
||||
|
||||
// test POST dashboards/ $newDashboard
|
||||
newDashboard := DashboardRequest{
|
||||
Name: common.DashboardA.Name,
|
||||
Grid: common.DashboardA.Grid,
|
||||
ScenarioID: uint(newScenarioID),
|
||||
}
|
||||
_, resp, _ = common.NewTestEndpoint(router, token,
|
||||
"/api/dashboards", "POST", common.KeyModels{"dashboard": newDashboard})
|
||||
|
||||
// Read newDashboard's ID from the response
|
||||
newDashboardID, _ := common.GetResponseID(resp)
|
||||
|
||||
return uint(newScenarioID), uint(newDashboardID)
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
db = common.DummyInitDB()
|
||||
defer db.Close()
|
||||
common.DummyPopulateDB(db)
|
||||
|
||||
router := gin.Default()
|
||||
router = gin.Default()
|
||||
api := router.Group("/api")
|
||||
|
||||
// All endpoints require authentication except when someone wants to
|
||||
// login (POST /authenticate)
|
||||
user.RegisterAuthenticate(api.Group("/authenticate"))
|
||||
|
||||
api.Use(user.Authentication(true))
|
||||
|
||||
RegisterWidgetEndpoints(api.Group("/widgets"))
|
||||
// scenario endpoints required here to first add a scenario to the DB
|
||||
// that can be associated with a new dashboard
|
||||
scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
|
||||
// dashboard endpoints required here to first add a dashboard to the DB
|
||||
// that can be associated with a new widget
|
||||
dashboard.RegisterDashboardEndpoints(api.Group("/dashboards"))
|
||||
|
||||
credjson, _ := json.Marshal(common.CredUser)
|
||||
msgOKjson, _ := json.Marshal(common.MsgOK)
|
||||
msgWidgetsjson, _ := json.Marshal(msgWidgets)
|
||||
msgWdgjson, _ := json.Marshal(msgWdg)
|
||||
msgWdgupdatedjson, _ := json.Marshal(msgWdgupdated)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
token = common.AuthenticateForTest(t, router, "/api/authenticate", "POST", credjson, 200)
|
||||
func TestAddWidget(t *testing.T) {
|
||||
common.DropTables(db)
|
||||
common.MigrateModels(db)
|
||||
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||
|
||||
// test GET widgets
|
||||
common.TestEndpoint(t, router, token, "/api/widgets?dashboardID=1", "GET", nil, 200, msgWidgetsjson)
|
||||
// authenticate as normal user
|
||||
token, err := common.NewAuthenticateForTest(router,
|
||||
"/api/authenticate", "POST", common.UserACredentials)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// test POST widgets
|
||||
common.TestEndpoint(t, router, token, "/api/widgets", "POST", msgWdgjson, 200, msgOKjson)
|
||||
_, dashboardID := addScenarioAndDashboard(token)
|
||||
|
||||
// test GET widgets/:widgetID to check if previous POST worked correctly
|
||||
common.TestEndpoint(t, router, token, "/api/widgets/3", "GET", nil, 200, msgWdgjson)
|
||||
// test POST widgets/ $newWidget
|
||||
newWidget := WidgetRequest{
|
||||
Name: common.WidgetA.Name,
|
||||
Type: common.WidgetA.Type,
|
||||
Width: common.WidgetA.Width,
|
||||
Height: common.WidgetA.Height,
|
||||
MinWidth: common.WidgetA.MinWidth,
|
||||
MinHeight: common.WidgetA.MinHeight,
|
||||
X: common.WidgetA.X,
|
||||
Y: common.WidgetA.Y,
|
||||
Z: common.WidgetA.Z,
|
||||
IsLocked: common.WidgetA.IsLocked,
|
||||
CustomProperties: common.WidgetA.CustomProperties,
|
||||
DashboardID: dashboardID,
|
||||
}
|
||||
code, resp, err := common.NewTestEndpoint(router, token,
|
||||
"/api/widgets", "POST", common.KeyModels{"widget": newWidget})
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// test PUT widgets/:widgetID
|
||||
common.TestEndpoint(t, router, token, "/api/widgets/3", "PUT", msgWdgupdatedjson, 200, msgOKjson)
|
||||
common.TestEndpoint(t, router, token, "/api/widgets/3", "GET", nil, 200, msgWdgupdatedjson)
|
||||
// Compare POST's response with the newWidget
|
||||
err = common.CompareResponse(resp, common.KeyModels{"widget": newWidget})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// test DELETE widgets/:widgetID
|
||||
common.TestEndpoint(t, router, token, "/api/widgets/3", "DELETE", nil, 200, msgOKjson)
|
||||
common.TestEndpoint(t, router, token, "/api/widgets?dashboardID=1", "GET", nil, 200, msgWidgetsjson)
|
||||
// Read newWidget's ID from the response
|
||||
newWidgetID, err := common.GetResponseID(resp)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// TODO add testing for other return codes
|
||||
// Get the newWidget
|
||||
code, resp, err = common.NewTestEndpoint(router, token,
|
||||
fmt.Sprintf("/api/widgets/%v", newWidgetID), "GET", nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// Compare GET's response with the newWidget
|
||||
err = common.CompareResponse(resp, common.KeyModels{"widget": newWidget})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// try to POST a malformed widget
|
||||
// Required fields are missing
|
||||
malformedNewWidget := WidgetRequest{
|
||||
Name: "ThisIsAMalformedDashboard",
|
||||
}
|
||||
// this should NOT work and return a unprocessable entity 442 status code
|
||||
code, resp, err = common.NewTestEndpoint(router, token,
|
||||
"/api/widgets", "POST", common.KeyModels{"widget": malformedNewWidget})
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
|
||||
}
|
||||
|
||||
func TestUpdateWidget(t *testing.T) {
|
||||
common.DropTables(db)
|
||||
common.MigrateModels(db)
|
||||
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||
|
||||
// authenticate as normal user
|
||||
token, err := common.NewAuthenticateForTest(router,
|
||||
"/api/authenticate", "POST", common.UserACredentials)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, dashboardID := addScenarioAndDashboard(token)
|
||||
|
||||
// test POST widgets/ $newWidget
|
||||
newWidget := WidgetRequest{
|
||||
Name: common.WidgetA.Name,
|
||||
Type: common.WidgetA.Type,
|
||||
Width: common.WidgetA.Width,
|
||||
Height: common.WidgetA.Height,
|
||||
MinWidth: common.WidgetA.MinWidth,
|
||||
MinHeight: common.WidgetA.MinHeight,
|
||||
X: common.WidgetA.X,
|
||||
Y: common.WidgetA.Y,
|
||||
Z: common.WidgetA.Z,
|
||||
IsLocked: common.WidgetA.IsLocked,
|
||||
CustomProperties: common.WidgetA.CustomProperties,
|
||||
DashboardID: dashboardID,
|
||||
}
|
||||
code, resp, err := common.NewTestEndpoint(router, token,
|
||||
"/api/widgets", "POST", common.KeyModels{"widget": newWidget})
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// Read newWidget's ID from the response
|
||||
newWidgetID, err := common.GetResponseID(resp)
|
||||
assert.NoError(t, err)
|
||||
|
||||
updatedWidget := WidgetRequest{
|
||||
Name: common.WidgetB.Name,
|
||||
Type: common.WidgetB.Type,
|
||||
Width: common.WidgetB.Width,
|
||||
Height: common.WidgetB.Height,
|
||||
MinWidth: common.WidgetB.MinWidth,
|
||||
MinHeight: common.WidgetB.MinHeight,
|
||||
CustomProperties: common.WidgetA.CustomProperties,
|
||||
}
|
||||
|
||||
code, resp, err = common.NewTestEndpoint(router, token,
|
||||
fmt.Sprintf("/api/widgets/%v", newWidgetID), "PUT", common.KeyModels{"widget": updatedWidget})
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// Compare PUT's response with the updatedWidget
|
||||
err = common.CompareResponse(resp, common.KeyModels{"widget": updatedWidget})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get the updatedWidget
|
||||
code, resp, err = common.NewTestEndpoint(router, token,
|
||||
fmt.Sprintf("/api/widgets/%v", newWidgetID), "GET", nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// Compare GET's response with the updatedWidget
|
||||
err = common.CompareResponse(resp, common.KeyModels{"widget": updatedWidget})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// try to update a widget that does not exist (should return not found 404 status code)
|
||||
code, resp, err = common.NewTestEndpoint(router, token,
|
||||
fmt.Sprintf("/api/widgets/%v", newWidgetID+1), "PUT", common.KeyModels{"widget": updatedWidget})
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
|
||||
|
||||
}
|
||||
|
||||
func TestDeleteWidget(t *testing.T) {
|
||||
common.DropTables(db)
|
||||
common.MigrateModels(db)
|
||||
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||
|
||||
// authenticate as normal user
|
||||
token, err := common.NewAuthenticateForTest(router,
|
||||
"/api/authenticate", "POST", common.UserACredentials)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, dashboardID := addScenarioAndDashboard(token)
|
||||
|
||||
// test POST widgets/ $newWidget
|
||||
newWidget := WidgetRequest{
|
||||
Name: common.WidgetA.Name,
|
||||
Type: common.WidgetA.Type,
|
||||
Width: common.WidgetA.Width,
|
||||
Height: common.WidgetA.Height,
|
||||
MinWidth: common.WidgetA.MinWidth,
|
||||
MinHeight: common.WidgetA.MinHeight,
|
||||
X: common.WidgetA.X,
|
||||
Y: common.WidgetA.Y,
|
||||
Z: common.WidgetA.Z,
|
||||
IsLocked: common.WidgetA.IsLocked,
|
||||
CustomProperties: common.WidgetA.CustomProperties,
|
||||
DashboardID: dashboardID,
|
||||
}
|
||||
code, resp, err := common.NewTestEndpoint(router, token,
|
||||
"/api/widgets", "POST", common.KeyModels{"widget": newWidget})
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// Read newWidget's ID from the response
|
||||
newWidgetID, err := common.GetResponseID(resp)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Count the number of all the widgets returned for dashboard
|
||||
initialNumber, err := common.LengthOfResponse(router, token,
|
||||
fmt.Sprintf("/api/widgets?dashboardID=%v", dashboardID), "GET", nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Delete the added newWidget
|
||||
code, resp, err = common.NewTestEndpoint(router, token,
|
||||
fmt.Sprintf("/api/widgets/%v", newWidgetID), "DELETE", nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// Compare DELETE's response with the newWidget
|
||||
err = common.CompareResponse(resp, common.KeyModels{"widget": newWidget})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Again count the number of all the widgets returned for dashboard
|
||||
finalNumber, err := common.LengthOfResponse(router, token,
|
||||
fmt.Sprintf("/api/widgets?dashboardID=%v", dashboardID), "GET", nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, initialNumber-1, finalNumber)
|
||||
}
|
||||
|
||||
func TestGetAllWidgetsOfDashboard(t *testing.T) {
|
||||
common.DropTables(db)
|
||||
common.MigrateModels(db)
|
||||
common.DummyAddOnlyUserTableWithAdminAndUsersDB(db)
|
||||
|
||||
// authenticate as normal user
|
||||
token, err := common.NewAuthenticateForTest(router,
|
||||
"/api/authenticate", "POST", common.UserACredentials)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, dashboardID := addScenarioAndDashboard(token)
|
||||
|
||||
// Count the number of all the widgets returned for dashboard
|
||||
initialNumber, err := common.LengthOfResponse(router, token,
|
||||
fmt.Sprintf("/api/widgets?dashboardID=%v", dashboardID), "GET", nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// test POST widgets/ $newWidget
|
||||
newWidgetA := WidgetRequest{
|
||||
Name: common.WidgetA.Name,
|
||||
Type: common.WidgetA.Type,
|
||||
Width: common.WidgetA.Width,
|
||||
Height: common.WidgetA.Height,
|
||||
MinWidth: common.WidgetA.MinWidth,
|
||||
MinHeight: common.WidgetA.MinHeight,
|
||||
X: common.WidgetA.X,
|
||||
Y: common.WidgetA.Y,
|
||||
Z: common.WidgetA.Z,
|
||||
IsLocked: common.WidgetA.IsLocked,
|
||||
CustomProperties: common.WidgetA.CustomProperties,
|
||||
DashboardID: dashboardID,
|
||||
}
|
||||
code, resp, err := common.NewTestEndpoint(router, token,
|
||||
"/api/widgets", "POST", common.KeyModels{"widget": newWidgetA})
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
||||
newWidgetB := WidgetRequest{
|
||||
Name: common.WidgetB.Name,
|
||||
Type: common.WidgetB.Type,
|
||||
Width: common.WidgetB.Width,
|
||||
Height: common.WidgetB.Height,
|
||||
MinWidth: common.WidgetB.MinWidth,
|
||||
MinHeight: common.WidgetB.MinHeight,
|
||||
X: common.WidgetB.X,
|
||||
Y: common.WidgetB.Y,
|
||||
Z: common.WidgetB.Z,
|
||||
IsLocked: common.WidgetB.IsLocked,
|
||||
CustomProperties: common.WidgetB.CustomProperties,
|
||||
DashboardID: dashboardID,
|
||||
}
|
||||
code, resp, err = common.NewTestEndpoint(router, token,
|
||||
"/api/widgets", "POST", common.KeyModels{"widget": newWidgetB})
|
||||
assert.NoError(t, err)
|
||||
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
|
||||
|
||||
// Again count the number of all the widgets returned for dashboard
|
||||
finalNumber, err := common.LengthOfResponse(router, token,
|
||||
fmt.Sprintf("/api/widgets?dashboardID=%v", dashboardID), "GET", nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, initialNumber+2, finalNumber)
|
||||
}
|
||||
|
||||
//// Test /widgets endpoints
|
||||
//func TestWidgetEndpoints(t *testing.T) {
|
||||
//
|
||||
// var token string
|
||||
//
|
||||
// var myWidgets = []common.WidgetResponse{common.WidgetA_response, common.WidgetB_response}
|
||||
// var msgWidgets = common.ResponseMsgWidgets{Widgets: myWidgets}
|
||||
// var msgWdg = common.ResponseMsgWidget{Widget: common.WidgetC_response}
|
||||
// var msgWdgupdated = common.ResponseMsgWidget{Widget: common.WidgetCUpdated_response}
|
||||
//
|
||||
// db := common.DummyInitDB()
|
||||
// defer db.Close()
|
||||
// common.DummyPopulateDB(db)
|
||||
//
|
||||
// router := gin.Default()
|
||||
// api := router.Group("/api")
|
||||
//
|
||||
// // All endpoints require authentication except when someone wants to
|
||||
// // login (POST /authenticate)
|
||||
// user.RegisterAuthenticate(api.Group("/authenticate"))
|
||||
//
|
||||
// api.Use(user.Authentication(true))
|
||||
//
|
||||
// RegisterWidgetEndpoints(api.Group("/widgets"))
|
||||
//
|
||||
// credjson, _ := json.Marshal(common.CredUser)
|
||||
// msgOKjson, _ := json.Marshal(common.MsgOK)
|
||||
// msgWidgetsjson, _ := json.Marshal(msgWidgets)
|
||||
// msgWdgjson, _ := json.Marshal(msgWdg)
|
||||
// msgWdgupdatedjson, _ := json.Marshal(msgWdgupdated)
|
||||
//
|
||||
// token = common.AuthenticateForTest(t, router, "/api/authenticate", "POST", credjson, 200)
|
||||
//
|
||||
// // test GET widgets
|
||||
// common.TestEndpoint(t, router, token, "/api/widgets?dashboardID=1", "GET", nil, 200, msgWidgetsjson)
|
||||
//
|
||||
// // test POST widgets
|
||||
// common.TestEndpoint(t, router, token, "/api/widgets", "POST", msgWdgjson, 200, msgOKjson)
|
||||
//
|
||||
// // test GET widgets/:widgetID to check if previous POST worked correctly
|
||||
// common.TestEndpoint(t, router, token, "/api/widgets/3", "GET", nil, 200, msgWdgjson)
|
||||
//
|
||||
// // test PUT widgets/:widgetID
|
||||
// common.TestEndpoint(t, router, token, "/api/widgets/3", "PUT", msgWdgupdatedjson, 200, msgOKjson)
|
||||
// common.TestEndpoint(t, router, token, "/api/widgets/3", "GET", nil, 200, msgWdgupdatedjson)
|
||||
//
|
||||
// // test DELETE widgets/:widgetID
|
||||
// common.TestEndpoint(t, router, token, "/api/widgets/3", "DELETE", nil, 200, msgOKjson)
|
||||
// common.TestEndpoint(t, router, token, "/api/widgets?dashboardID=1", "GET", nil, 200, msgWidgetsjson)
|
||||
//
|
||||
// // TODO add testing for other return codes
|
||||
//
|
||||
//}
|
||||
|
|
109
routes/widget/widget_validators.go
Normal file
109
routes/widget/widget_validators.go
Normal file
|
@ -0,0 +1,109 @@
|
|||
package widget
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/jinzhu/gorm/dialects/postgres"
|
||||
"github.com/nsf/jsondiff"
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
)
|
||||
|
||||
var validate *validator.Validate
|
||||
|
||||
type validNewWidget struct {
|
||||
Name string `form:"name" validate:"required"`
|
||||
Type string `form:"type" validate:"required"`
|
||||
Width uint `form:"width" validate:"required"`
|
||||
Height uint `form:"height" validate:"required"`
|
||||
MinWidth uint `form:"minWidth" validate:"omitempty"`
|
||||
MinHeight uint `form:"minHeight" validate:"omitempty"`
|
||||
X int `form:"x" validate:"omitempty"`
|
||||
Y int `form:"y" validate:"omitempty"`
|
||||
Z int `form:"z" validate:"omitempty"`
|
||||
DashboardID uint `form:"dashboardID" validate:"required"`
|
||||
IsLocked bool `form:"isLocked" validate:"omitempty"`
|
||||
CustomProperties postgres.Jsonb `form:"customProperties" validate:"omitempty"`
|
||||
}
|
||||
|
||||
type validUpdatedWidget struct {
|
||||
Name string `form:"name" validate:"omitempty"`
|
||||
Type string `form:"type" validate:"omitempty"`
|
||||
Width uint `form:"width" validate:"omitempty"`
|
||||
Height uint `form:"height" validate:"omitempty"`
|
||||
MinWidth uint `form:"minWidth" validate:"omitempty"`
|
||||
MinHeight uint `form:"minHeight" validate:"omitempty"`
|
||||
X int `form:"x" validate:"omitempty"`
|
||||
Y int `form:"y" validate:"omitempty"`
|
||||
Z int `form:"z" validate:"omitempty"`
|
||||
IsLocked bool `form:"isLocked" validate:"omitempty"`
|
||||
CustomProperties postgres.Jsonb `form:"customProperties" validate:"omitempty"`
|
||||
}
|
||||
|
||||
type addWidgetRequest struct {
|
||||
validNewWidget `json:"widget"`
|
||||
}
|
||||
|
||||
type updateWidgetRequest struct {
|
||||
validUpdatedWidget `json:"widget"`
|
||||
}
|
||||
|
||||
func (r *addWidgetRequest) validate() error {
|
||||
validate = validator.New()
|
||||
errs := validate.Struct(r)
|
||||
return errs
|
||||
}
|
||||
|
||||
func (r *validUpdatedWidget) validate() error {
|
||||
validate = validator.New()
|
||||
errs := validate.Struct(r)
|
||||
return errs
|
||||
}
|
||||
|
||||
func (r *addWidgetRequest) createWidget() Widget {
|
||||
var s Widget
|
||||
|
||||
s.Name = r.Name
|
||||
s.Type = r.Type
|
||||
s.Width = r.Width
|
||||
s.Height = r.Height
|
||||
s.MinWidth = r.MinWidth
|
||||
s.MinHeight = r.MinHeight
|
||||
s.X = r.X
|
||||
s.Y = r.Y
|
||||
s.Z = r.Z
|
||||
s.IsLocked = r.IsLocked
|
||||
s.CustomProperties = r.CustomProperties
|
||||
s.DashboardID = r.DashboardID
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *updateWidgetRequest) updatedWidget(oldWidget Widget) (Widget, error) {
|
||||
// Use the old Widget as a basis for the updated Widget `s`
|
||||
s := oldWidget
|
||||
|
||||
if r.Name != "" {
|
||||
s.Name = r.Name
|
||||
}
|
||||
|
||||
s.Type = r.Type
|
||||
s.Width = r.Width
|
||||
s.Height = r.Height
|
||||
s.MinWidth = r.MinWidth
|
||||
s.MinHeight = r.MinHeight
|
||||
s.X = r.X
|
||||
s.Y = r.Y
|
||||
s.Z = r.Z
|
||||
s.IsLocked = r.IsLocked
|
||||
|
||||
// only update custom props if not empty
|
||||
var emptyJson postgres.Jsonb
|
||||
// Serialize empty json and params
|
||||
emptyJson_ser, _ := json.Marshal(emptyJson)
|
||||
customprops_ser, _ := json.Marshal(r.CustomProperties)
|
||||
opts := jsondiff.DefaultConsoleOptions()
|
||||
diff, _ := jsondiff.Compare(emptyJson_ser, customprops_ser, &opts)
|
||||
if diff.String() != "FullMatch" {
|
||||
s.CustomProperties = r.CustomProperties
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
Loading…
Add table
Reference in a new issue