From 2ffda7cad86a5ae23c1a357a6828009817d8f776 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Mon, 9 Sep 2019 15:30:17 +0200 Subject: [PATCH] - revise naming of some common functions - improve returning of error codes by using common functions - use a separate file for authentication endpoint to improve clarity of code --- common/database.go | 182 ++------------ common/database_test.go | 2 +- common/http_errors.go | 69 ++++++ common/test_utilities.go | 109 +++++++++ routes/dashboard/dashboard_endpoints.go | 48 +--- routes/dashboard/dashboard_middleware.go | 16 +- routes/dashboard/dashboard_test.go | 10 +- routes/file/file_endpoints.go | 57 +---- routes/file/file_middleware.go | 11 +- routes/file/file_test.go | 10 +- routes/scenario/scenario_endpoints.go | 54 +---- routes/scenario/scenario_middleware.go | 26 +- routes/scenario/scenario_test.go | 18 +- routes/signal/signal_endpoints.go | 51 +--- routes/signal/signal_middleware.go | 11 +- routes/signal/signal_test.go | 10 +- .../simulationmodel_endpoints.go | 46 +--- .../simulationmodel_middleware.go | 17 +- .../simulationmodel/simulationmodel_test.go | 10 +- routes/simulator/simulator_endpoints.go | 61 +---- routes/simulator/simulator_middleware.go | 11 +- routes/simulator/simulator_test.go | 18 +- routes/user/authenticate_endpoint.go | 95 ++++++++ routes/user/user_endpoints.go | 225 ++---------------- routes/user/user_middleware.go | 16 +- routes/user/user_test.go | 16 +- routes/widget/widget_endpoints.go | 46 +--- routes/widget/widget_middleware.go | 12 +- routes/widget/widget_test.go | 10 +- start.go | 7 +- 30 files changed, 472 insertions(+), 802 deletions(-) create mode 100644 common/http_errors.go create mode 100644 routes/user/authenticate_endpoint.go diff --git a/common/database.go b/common/database.go index 35718cd..8053efb 100644 --- a/common/database.go +++ b/common/database.go @@ -3,43 +3,48 @@ package common import ( "flag" "fmt" - "github.com/gin-gonic/gin" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/postgres" "log" - "net/http" ) -var DB_HOST string -var DB_NAME string -var DB_DUMMY string -var DB_SSLMODE string -var WITH_AMQP bool +var DB_HOST string // host of the database system +var DB_NAME string // name of the production database +var DB_TEST string // name of the test database +var DB_SSLMODE string // set to enable if database uses SSL +var WITH_AMQP bool // set to true if backend shall be used with AMQP client -var DBpool *gorm.DB +var DBpool *gorm.DB // database used by backend // Initialize input command line flags func init() { flag.StringVar(&DB_HOST, "dbhost", "/var/run/postgresql", "Host of the PostgreSQL database (default is /var/run/postgresql for localhost DB on Ubuntu systems)") flag.StringVar(&DB_NAME, "dbname", "villasdb", "Name of the database to use (default is villasdb)") - flag.StringVar(&DB_DUMMY, "dbdummy", "testvillasdb", "Name of the test database to use (default is testvillasdb)") + flag.StringVar(&DB_TEST, "dbdummy", "testvillasdb", "Name of the test database to use (default is testvillasdb)") flag.StringVar(&DB_SSLMODE, "dbsslmode", "disable", "SSL mode of DB (default is disable)") // TODO: change default for production flag.BoolVar(&WITH_AMQP, "amqp", false, "If AMQP client for simulators shall be enabled, set this option to true (default is false)") flag.Parse() fmt.Println("DB_HOST has value ", DB_HOST) fmt.Println("DB_NAME has value ", DB_NAME) - fmt.Println("DB_DUMMY has value ", DB_DUMMY) + fmt.Println("DB_TEST has value ", DB_TEST) fmt.Println("DB_SSLMODE has value ", DB_SSLMODE) fmt.Println("WITH_AMQP has value ", WITH_AMQP) } // Initialize connection to the database -func InitDB() *gorm.DB { +func InitDB(dbname string) *gorm.DB { dbinfo := fmt.Sprintf("host=%s sslmode=%s dbname=%s", - DB_HOST, DB_SSLMODE, DB_NAME) + DB_HOST, DB_SSLMODE, dbname) db, err := gorm.Open("postgres", dbinfo) checkErr(err) DBpool = db + + if dbname == DB_TEST { + // if we are using the test DB + // drop tables from previous tests + DropTables(db) + } + return db } @@ -48,11 +53,6 @@ func GetDB() *gorm.DB { return DBpool } -// Verify that the database connection is alive -func VerifyConnection(db *gorm.DB) error { - return db.DB().Ping() -} - // Drop all the tables of the database // TODO: Remove that function from the codebase and substitute the body // to the Dummy*() where it is called @@ -65,6 +65,7 @@ func DropTables(db *gorm.DB) { db.DropTableIfExists(&User{}) db.DropTableIfExists(&Dashboard{}) db.DropTableIfExists(&Widget{}) + // The following statement deletes the many to many relationship between users and scenarios db.DropTableIfExists("user_scenarios") } @@ -80,133 +81,6 @@ func MigrateModels(db *gorm.DB) { db.AutoMigrate(&Widget{}) } -// Start a dummy database for testing -func DummyInitDB() *gorm.DB { - - dbinfo := fmt.Sprintf("host=%s sslmode=%s dbname=%s", - DB_HOST, DB_SSLMODE, DB_DUMMY) - test_db, err := gorm.Open("postgres", dbinfo) - checkErr(err) - DBpool = test_db - // drop tables from previous tests - DropTables(test_db) - - return test_db -} - -func DummyAddOnlyUserTableWithAdminDB(db *gorm.DB) { - db.AutoMigrate(&User{}) - - //create a copy of global test data - user0 := User0 - // add admin user to DB - checkErr(db.Create(&user0).Error) -} - -func DummyAddOnlyUserTableWithAdminAndUsersDB(db *gorm.DB) { - db.AutoMigrate(&User{}) - - //create a copy of global test data - user0 := User0 - userA := UserA - userB := UserB - // add admin user to DB - checkErr(db.Create(&user0).Error) - // add normal users to DB - checkErr(db.Create(&userA).Error) - checkErr(db.Create(&userB).Error) -} - -// Migrates models and populates them with data -func DummyPopulateDB(test_db *gorm.DB) { - - MigrateModels(test_db) - - // Create entries of each model (data defined in testdata.go) - - // Users - checkErr(test_db.Create(&User0).Error) // Admin - checkErr(test_db.Create(&UserA).Error) // Normal User - checkErr(test_db.Create(&UserB).Error) // Normal User - - // Simulators - checkErr(test_db.Create(&SimulatorA).Error) - checkErr(test_db.Create(&SimulatorB).Error) - - // Scenarios - checkErr(test_db.Create(&ScenarioA).Error) - checkErr(test_db.Create(&ScenarioB).Error) - - // Signals - checkErr(test_db.Create(&OutSignalA).Error) - checkErr(test_db.Create(&OutSignalB).Error) - checkErr(test_db.Create(&InSignalA).Error) - checkErr(test_db.Create(&InSignalB).Error) - - // Simulation Models - checkErr(test_db.Create(&SimulationModelA).Error) - checkErr(test_db.Create(&SimulationModelB).Error) - - // Dashboards - checkErr(test_db.Create(&DashboardA).Error) - checkErr(test_db.Create(&DashboardB).Error) - - // Files - checkErr(test_db.Create(&FileA).Error) - checkErr(test_db.Create(&FileB).Error) - checkErr(test_db.Create(&FileC).Error) - checkErr(test_db.Create(&FileD).Error) - - // Widgets - checkErr(test_db.Create(&WidgetA).Error) - checkErr(test_db.Create(&WidgetB).Error) - - // Associations between models - // For `belongs to` use the model with id=1 - // For `has many` use the models with id=1 and id=2 - - // User HM Scenarios, Scenario HM Users (Many-to-Many) - checkErr(test_db.Model(&ScenarioA).Association("Users").Append(&UserA).Error) - checkErr(test_db.Model(&ScenarioA).Association("Users").Append(&UserB).Error) - checkErr(test_db.Model(&ScenarioB).Association("Users").Append(&UserA).Error) - checkErr(test_db.Model(&ScenarioB).Association("Users").Append(&UserB).Error) - - // Scenario HM SimulationModels - checkErr(test_db.Model(&ScenarioA).Association("SimulationModels").Append(&SimulationModelA).Error) - checkErr(test_db.Model(&ScenarioA).Association("SimulationModels").Append(&SimulationModelB).Error) - - // Scenario HM Dashboards - checkErr(test_db.Model(&ScenarioA).Association("Dashboards").Append(&DashboardA).Error) - checkErr(test_db.Model(&ScenarioA).Association("Dashboards").Append(&DashboardB).Error) - - // Dashboard HM Widget - checkErr(test_db.Model(&DashboardA).Association("Widgets").Append(&WidgetA).Error) - checkErr(test_db.Model(&DashboardA).Association("Widgets").Append(&WidgetB).Error) - - // SimulationModel HM Signals - checkErr(test_db.Model(&SimulationModelA).Association("InputMapping").Append(&InSignalA).Error) - checkErr(test_db.Model(&SimulationModelA).Association("InputMapping").Append(&InSignalB).Error) - checkErr(test_db.Model(&SimulationModelA).Association("OutputMapping").Append(&OutSignalA).Error) - checkErr(test_db.Model(&SimulationModelA).Association("OutputMapping").Append(&OutSignalB).Error) - - // SimulationModel HM Files - checkErr(test_db.Model(&SimulationModelA).Association("Files").Append(&FileC).Error) - checkErr(test_db.Model(&SimulationModelA).Association("Files").Append(&FileD).Error) - - // Simulator HM SimulationModels - checkErr(test_db.Model(&SimulatorA).Association("SimulationModels").Append(&SimulationModelA).Error) - checkErr(test_db.Model(&SimulatorA).Association("SimulationModels").Append(&SimulationModelB).Error) - - // Widget HM Files - checkErr(test_db.Model(&WidgetA).Association("Files").Append(&FileA).Error) - checkErr(test_db.Model(&WidgetA).Association("Files").Append(&FileB).Error) -} - -// Erase tables and glose the testdb -func DummyCloseDB(test_db *gorm.DB) { - test_db.Close() -} - // Quick error check // NOTE: maybe this is not a good idea func checkErr(err error) { @@ -214,23 +88,3 @@ func checkErr(err error) { log.Fatal(err) } } - -func DBError(c *gin.Context, err error) bool { - if err != nil { - if err == gorm.ErrRecordNotFound { - errormsg := "Record not Found in DB: " + err.Error() - c.JSON(http.StatusNotFound, gin.H{ - "success": false, - "message": errormsg, - }) - } else { - errormsg := "Error on DB Query or transaction: " + err.Error() - c.JSON(http.StatusInternalServerError, gin.H{ - "success": false, - "message": errormsg, - }) - } - return true // Error - } - return false // No error -} diff --git a/common/database_test.go b/common/database_test.go index a7f7a5f..921981d 100644 --- a/common/database_test.go +++ b/common/database_test.go @@ -12,7 +12,7 @@ import ( var db *gorm.DB func TestMain(m *testing.M) { - db = DummyInitDB() + db = InitDB(DB_TEST) // Verify that you can connect to the database err := db.DB().Ping() diff --git a/common/http_errors.go b/common/http_errors.go new file mode 100644 index 0000000..c7bd817 --- /dev/null +++ b/common/http_errors.go @@ -0,0 +1,69 @@ +package common + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/jinzhu/gorm" + "net/http" +) + +func DBError(c *gin.Context, err error) bool { + if err != nil { + if err == gorm.ErrRecordNotFound { + NotFoundError(c, "Record not Found in DB: "+err.Error()) + } else { + InternalServerError(c, "Error on DB Query or transaction: "+err.Error()) + } + return true // Error + } + return false // No error +} + +func BadRequestError(c *gin.Context, err string) { + c.JSON(http.StatusBadRequest, gin.H{ + "success": false, + "message": fmt.Sprintf("%v", err), + }) +} + +func UnprocessableEntityError(c *gin.Context, err string) { + c.JSON(http.StatusUnprocessableEntity, gin.H{ + "success": false, + "message": fmt.Sprintf("%v", err), + }) +} + +func InternalServerError(c *gin.Context, err string) { + c.JSON(http.StatusInternalServerError, gin.H{ + "success": false, + "message": fmt.Sprintf("%v", err), + }) +} + +func UnauthorizedError(c *gin.Context, err string) { + c.JSON(http.StatusUnauthorized, gin.H{ + "success": false, + "message": fmt.Sprintf("%v", err), + }) +} + +func UnauthorizedAbort(c *gin.Context, err string) { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ + "succes": false, + "message": fmt.Sprintf("%v", err), + }) +} + +func NotFoundError(c *gin.Context, err string) { + c.JSON(http.StatusNotFound, gin.H{ + "success": false, + "message": fmt.Sprintf("%v", err), + }) +} + +func ForbiddenError(c *gin.Context, err string) { + c.JSON(http.StatusForbidden, gin.H{ + "success": false, + "message": fmt.Sprintf("%v", err), + }) +} diff --git a/common/test_utilities.go b/common/test_utilities.go index 87786af..7da1bf3 100644 --- a/common/test_utilities.go +++ b/common/test_utilities.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "github.com/gin-gonic/gin" + "github.com/jinzhu/gorm" "github.com/jinzhu/gorm/dialects/postgres" "github.com/nsf/jsondiff" "golang.org/x/crypto/bcrypt" @@ -404,3 +405,111 @@ func AuthenticateForTest(router *gin.Engine, url string, // Return the token and nil error return token, nil } + +func DBAddAdminUser(db *gorm.DB) { + db.AutoMigrate(&User{}) + + //create a copy of global test data + user0 := User0 + // add admin user to DB + checkErr(db.Create(&user0).Error) +} + +func DBAddAdminAndUser(db *gorm.DB) { + db.AutoMigrate(&User{}) + + //create a copy of global test data + user0 := User0 + userA := UserA + userB := UserB + // add admin user to DB + checkErr(db.Create(&user0).Error) + // add normal users to DB + checkErr(db.Create(&userA).Error) + checkErr(db.Create(&userB).Error) +} + +// Migrates models and populates them with data +func AddTestData(test_db *gorm.DB) { + + MigrateModels(test_db) + + // Create entries of each model (data defined in testdata.go) + + // Users + checkErr(test_db.Create(&User0).Error) // Admin + checkErr(test_db.Create(&UserA).Error) // Normal User + checkErr(test_db.Create(&UserB).Error) // Normal User + + // Simulators + checkErr(test_db.Create(&SimulatorA).Error) + checkErr(test_db.Create(&SimulatorB).Error) + + // Scenarios + checkErr(test_db.Create(&ScenarioA).Error) + checkErr(test_db.Create(&ScenarioB).Error) + + // Signals + checkErr(test_db.Create(&OutSignalA).Error) + checkErr(test_db.Create(&OutSignalB).Error) + checkErr(test_db.Create(&InSignalA).Error) + checkErr(test_db.Create(&InSignalB).Error) + + // Simulation Models + checkErr(test_db.Create(&SimulationModelA).Error) + checkErr(test_db.Create(&SimulationModelB).Error) + + // Dashboards + checkErr(test_db.Create(&DashboardA).Error) + checkErr(test_db.Create(&DashboardB).Error) + + // Files + checkErr(test_db.Create(&FileA).Error) + checkErr(test_db.Create(&FileB).Error) + checkErr(test_db.Create(&FileC).Error) + checkErr(test_db.Create(&FileD).Error) + + // Widgets + checkErr(test_db.Create(&WidgetA).Error) + checkErr(test_db.Create(&WidgetB).Error) + + // Associations between models + // For `belongs to` use the model with id=1 + // For `has many` use the models with id=1 and id=2 + + // User HM Scenarios, Scenario HM Users (Many-to-Many) + checkErr(test_db.Model(&ScenarioA).Association("Users").Append(&UserA).Error) + checkErr(test_db.Model(&ScenarioA).Association("Users").Append(&UserB).Error) + checkErr(test_db.Model(&ScenarioB).Association("Users").Append(&UserA).Error) + checkErr(test_db.Model(&ScenarioB).Association("Users").Append(&UserB).Error) + + // Scenario HM SimulationModels + checkErr(test_db.Model(&ScenarioA).Association("SimulationModels").Append(&SimulationModelA).Error) + checkErr(test_db.Model(&ScenarioA).Association("SimulationModels").Append(&SimulationModelB).Error) + + // Scenario HM Dashboards + checkErr(test_db.Model(&ScenarioA).Association("Dashboards").Append(&DashboardA).Error) + checkErr(test_db.Model(&ScenarioA).Association("Dashboards").Append(&DashboardB).Error) + + // Dashboard HM Widget + checkErr(test_db.Model(&DashboardA).Association("Widgets").Append(&WidgetA).Error) + checkErr(test_db.Model(&DashboardA).Association("Widgets").Append(&WidgetB).Error) + + // SimulationModel HM Signals + checkErr(test_db.Model(&SimulationModelA).Association("InputMapping").Append(&InSignalA).Error) + checkErr(test_db.Model(&SimulationModelA).Association("InputMapping").Append(&InSignalB).Error) + checkErr(test_db.Model(&SimulationModelA).Association("OutputMapping").Append(&OutSignalA).Error) + checkErr(test_db.Model(&SimulationModelA).Association("OutputMapping").Append(&OutSignalB).Error) + + // SimulationModel HM Files + checkErr(test_db.Model(&SimulationModelA).Association("Files").Append(&FileC).Error) + checkErr(test_db.Model(&SimulationModelA).Association("Files").Append(&FileD).Error) + + // Simulator HM SimulationModels + checkErr(test_db.Model(&SimulatorA).Association("SimulationModels").Append(&SimulationModelA).Error) + checkErr(test_db.Model(&SimulatorA).Association("SimulationModels").Append(&SimulationModelB).Error) + + // Widget HM Files + checkErr(test_db.Model(&WidgetA).Association("Files").Append(&FileA).Error) + checkErr(test_db.Model(&WidgetA).Association("Files").Append(&FileB).Error) +} diff --git a/routes/dashboard/dashboard_endpoints.go b/routes/dashboard/dashboard_endpoints.go index 24c079f..54883de 100644 --- a/routes/dashboard/dashboard_endpoints.go +++ b/routes/dashboard/dashboard_endpoints.go @@ -1,7 +1,6 @@ package dashboard import ( - "fmt" "net/http" "github.com/gin-gonic/gin" @@ -44,9 +43,7 @@ func getDashboards(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "dashboards": dab, - }) + c.JSON(http.StatusOK, gin.H{"dashboards": dab}) } // addDashboard godoc @@ -67,19 +64,13 @@ func addDashboard(c *gin.Context) { // bind request to JSON var req addDashboardRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Validate the request if err := req.validate(); err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } @@ -99,10 +90,7 @@ func addDashboard(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "dashboard": newDashboard.Dashboard, - }) - + c.JSON(http.StatusOK, gin.H{"dashboard": newDashboard.Dashboard}) } // updateDashboard godoc @@ -128,28 +116,19 @@ func updateDashboard(c *gin.Context) { var req updateDashboardRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Validate the request if err := req.validate(); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Create the updatedDashboard from oldDashboard updatedDashboard, err := req.updatedDashboard(oldDashboard) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } @@ -160,10 +139,7 @@ func updateDashboard(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "dashboard": updatedDashboard.Dashboard, - }) - + c.JSON(http.StatusOK, gin.H{"dashboard": updatedDashboard.Dashboard}) } // getDashboard godoc @@ -185,9 +161,7 @@ func getDashboard(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "dashboard": dab.Dashboard, - }) + c.JSON(http.StatusOK, gin.H{"dashboard": dab.Dashboard}) } // deleteDashboard godoc @@ -213,7 +187,5 @@ func deleteDashboard(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "dashboard": dab.Dashboard, - }) + c.JSON(http.StatusOK, gin.H{"dashboard": dab.Dashboard}) } diff --git a/routes/dashboard/dashboard_middleware.go b/routes/dashboard/dashboard_middleware.go index 6534fd8..72008bf 100644 --- a/routes/dashboard/dashboard_middleware.go +++ b/routes/dashboard/dashboard_middleware.go @@ -3,7 +3,6 @@ package dashboard import ( "fmt" "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/scenario" - "net/http" "strconv" "github.com/gin-gonic/gin" @@ -17,10 +16,7 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, dabIDSource string, err := common.ValidateRole(c, common.ModelDashboard, operation) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("Access denied (role validation failed): %v", err), - }) + common.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation failed): %v", err.Error())) return false, dab } @@ -28,19 +24,13 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, dabIDSource string, if dabIDSource == "path" { dabID, err = strconv.Atoi(c.Param("dashboardID")) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. No or incorrect format of dashboardID path parameter"), - }) + common.BadRequestError(c, fmt.Sprintf("No or incorrect format of dashboardID path parameter")) return false, dab } } else if dabIDSource == "query" { dabID, err = strconv.Atoi(c.Request.URL.Query().Get("dashboardID")) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. No or incorrect format of dashboardID query parameter"), - }) + common.BadRequestError(c, fmt.Sprintf("No or incorrect format of dashboardID query parameter")) return false, dab } } else if dabIDSource == "body" { diff --git a/routes/dashboard/dashboard_test.go b/routes/dashboard/dashboard_test.go index 7471f2c..a343259 100644 --- a/routes/dashboard/dashboard_test.go +++ b/routes/dashboard/dashboard_test.go @@ -47,7 +47,7 @@ func addScenario(token string) (scenarioID uint) { func TestMain(m *testing.M) { - db = common.DummyInitDB() + db = common.InitDB(common.DB_TEST) defer db.Close() router = gin.Default() @@ -66,7 +66,7 @@ func TestMain(m *testing.M) { func TestAddDashboard(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -120,7 +120,7 @@ func TestAddDashboard(t *testing.T) { func TestUpdateDashboard(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -179,7 +179,7 @@ func TestUpdateDashboard(t *testing.T) { func TestDeleteDashboard(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -231,7 +231,7 @@ func TestDeleteDashboard(t *testing.T) { func TestGetAllDashboardsOfScenario(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, diff --git a/routes/file/file_endpoints.go b/routes/file/file_endpoints.go index dd3ba9a..449d27a 100644 --- a/routes/file/file_endpoints.go +++ b/routes/file/file_endpoints.go @@ -36,19 +36,13 @@ func getFiles(c *gin.Context) { objectType := c.Request.URL.Query().Get("objectType") if objectType != "model" && objectType != "widget" { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. Object type not supported for files: %s", objectType), - }) + common.BadRequestError(c, fmt.Sprintf("Object type not supported for files: %s", objectType)) return } objectID_s := c.Request.URL.Query().Get("objectID") objectID, err := strconv.Atoi(objectID_s) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. Error on ID conversion: %s", err.Error()), - }) + common.BadRequestError(c, fmt.Sprintf("Error on ID conversion: %s", err.Error())) return } @@ -84,10 +78,7 @@ func getFiles(c *gin.Context) { } } - c.JSON(http.StatusOK, gin.H{ - "files": files, - }) - + c.JSON(http.StatusOK, gin.H{"files": files}) } // addFile godoc @@ -114,19 +105,13 @@ func addFile(c *gin.Context) { objectType := c.Request.URL.Query().Get("objectType") if objectType != "model" && objectType != "widget" { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. Object type not supported for files: %s", objectType), - }) + common.BadRequestError(c, fmt.Sprintf("Object type not supported for files: %s", objectType)) return } objectID_s := c.Request.URL.Query().Get("objectID") objectID, err := strconv.Atoi(objectID_s) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. Error on ID conversion: %s", err.Error()), - }) + common.BadRequestError(c, fmt.Sprintf("Error on ID conversion: %s", err.Error())) return } @@ -147,10 +132,7 @@ func addFile(c *gin.Context) { // Extract file from POST request form file_header, err := c.FormFile("file") if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. Get form error: %s", err.Error()), - }) + common.BadRequestError(c, fmt.Sprintf("Get form error: %s", err.Error())) return } @@ -161,9 +143,7 @@ func addFile(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "file": newFile.File, - }) + c.JSON(http.StatusOK, gin.H{"file": newFile.File}) } // getFile godoc @@ -197,10 +177,7 @@ func getFile(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "file": f.File, - }) - + c.JSON(http.StatusOK, gin.H{"file": f.File}) } // updateFile godoc @@ -233,19 +210,13 @@ func updateFile(c *gin.Context) { // Extract file from PUT request form err := c.Request.ParseForm() if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. Get form error: %s", err.Error()), - }) + common.BadRequestError(c, fmt.Sprintf("Get form error: %s", err.Error())) return } file_header, err := c.FormFile("file") if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "error": fmt.Sprintf("Bad request. Get form error: %s", err.Error()), - }) + common.BadRequestError(c, fmt.Sprintf("Get form error: %s", err.Error())) return } @@ -255,9 +226,7 @@ func updateFile(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "file": f.File, - }) + c.JSON(http.StatusOK, gin.H{"file": f.File}) } // deleteFile godoc @@ -286,7 +255,5 @@ func deleteFile(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "file": f.File, - }) + c.JSON(http.StatusOK, gin.H{"file": f.File}) } diff --git a/routes/file/file_middleware.go b/routes/file/file_middleware.go index c509a20..91aa251 100644 --- a/routes/file/file_middleware.go +++ b/routes/file/file_middleware.go @@ -6,7 +6,6 @@ import ( "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/routes/widget" "github.com/gin-gonic/gin" - "net/http" "strconv" ) @@ -16,19 +15,13 @@ func checkPermissions(c *gin.Context, operation common.CRUD) (bool, File) { err := common.ValidateRole(c, common.ModelFile, operation) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("Access denied (role validation failed): %v", err), - }) + common.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation failed): %v", err.Error())) return false, f } fileID, err := strconv.Atoi(c.Param("fileID")) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "error": fmt.Sprintf("Bad request. No or incorrect format of fileID path parameter"), - }) + common.BadRequestError(c, fmt.Sprintf("No or incorrect format of fileID path parameter")) return false, f } diff --git a/routes/file/file_test.go b/routes/file/file_test.go index ce4dba4..a584410 100644 --- a/routes/file/file_test.go +++ b/routes/file/file_test.go @@ -99,7 +99,7 @@ func addScenarioAndSimulatorAndSimulationModel() (scenarioID uint, simulatorID u func TestMain(m *testing.M) { - db = common.DummyInitDB() + db = common.InitDB(common.DB_TEST) defer db.Close() router = gin.Default() @@ -124,7 +124,7 @@ func TestMain(m *testing.M) { func TestAddFile(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB @@ -187,7 +187,7 @@ func TestUpdateFile(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB @@ -288,7 +288,7 @@ func TestUpdateFile(t *testing.T) { func TestDeleteFile(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB @@ -362,7 +362,7 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB diff --git a/routes/scenario/scenario_endpoints.go b/routes/scenario/scenario_endpoints.go index 5b902cf..4a726f7 100644 --- a/routes/scenario/scenario_endpoints.go +++ b/routes/scenario/scenario_endpoints.go @@ -1,7 +1,6 @@ package scenario import ( - "fmt" "net/http" "github.com/gin-gonic/gin" @@ -64,9 +63,7 @@ func getScenarios(c *gin.Context) { } } // TODO return list of simulationModelIDs, dashboardIDs and userIDs per scenario - c.JSON(http.StatusOK, gin.H{ - "scenarios": scenarios, - }) + c.JSON(http.StatusOK, gin.H{"scenarios": scenarios}) } // addScenario godoc @@ -99,19 +96,13 @@ func addScenario(c *gin.Context) { var req addScenarioRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Validate the request if err = req.validate(); err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } @@ -132,9 +123,7 @@ func addScenario(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "scenario": newScenario.Scenario, - }) + c.JSON(http.StatusOK, gin.H{"scenario": newScenario.Scenario}) } // updateScenario godoc @@ -161,29 +150,20 @@ func updateScenario(c *gin.Context) { // Bind the (context) with the updateScenarioRequest struct var req updateScenarioRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Validate the request based on struct updateScenarioRequest json tags if err := req.validate(); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Create the updatedScenario from oldScenario updatedScenario, err := req.updatedScenario(oldScenario) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } @@ -194,9 +174,7 @@ func updateScenario(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "scenario": updatedScenario.Scenario, - }) + c.JSON(http.StatusOK, gin.H{"scenario": updatedScenario.Scenario}) } // getScenario godoc @@ -218,9 +196,7 @@ func getScenario(c *gin.Context) { } // TODO return list of simulationModelIDs, dashboardIDs and userIDs per scenario - c.JSON(http.StatusOK, gin.H{ - "scenario": so.Scenario, - }) + c.JSON(http.StatusOK, gin.H{"scenario": so.Scenario}) } // deleteScenario godoc @@ -247,9 +223,7 @@ func deleteScenario(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "scenario": so.Scenario, - }) + c.JSON(http.StatusOK, gin.H{"scenario": so.Scenario}) } // getUsersOfScenario godoc @@ -311,9 +285,7 @@ func addUserToScenario(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "user": u.User, - }) + c.JSON(http.StatusOK, gin.H{"user": u.User}) } // deleteUserFromScenario godoc @@ -348,7 +320,5 @@ func deleteUserFromScenario(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "user": u.User, - }) + c.JSON(http.StatusOK, gin.H{"user": u.User}) } diff --git a/routes/scenario/scenario_middleware.go b/routes/scenario/scenario_middleware.go index 110d0e6..3b70982 100644 --- a/routes/scenario/scenario_middleware.go +++ b/routes/scenario/scenario_middleware.go @@ -2,7 +2,6 @@ package scenario import ( "fmt" - "net/http" "strconv" "github.com/gin-gonic/gin" @@ -16,10 +15,7 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, screnarioIDSource s err := common.ValidateRole(c, common.ModelScenario, operation) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("Access denied (role validation failed): %v", err), - }) + common.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation failed): %v", err)) return false, so } @@ -31,29 +27,20 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, screnarioIDSource s if screnarioIDSource == "path" { scenarioID, err = strconv.Atoi(c.Param("scenarioID")) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. No or incorrect format of scenarioID path parameter"), - }) + common.BadRequestError(c, fmt.Sprintf("No or incorrect format of scenarioID path parameter")) return false, so } } else if screnarioIDSource == "query" { scenarioID, err = strconv.Atoi(c.Request.URL.Query().Get("scenarioID")) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. No or incorrect format of scenarioID query parameter"), - }) + common.BadRequestError(c, fmt.Sprintf("No or incorrect format of scenarioID query parameter")) return false, so } } else if screnarioIDSource == "body" { scenarioID = screnarioIDBody } else { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. The following source of your scenario ID is not valid: %s", screnarioIDSource), - }) + common.BadRequestError(c, fmt.Sprintf("The following source of scenario ID is not valid: %s", screnarioIDSource)) return false, so } @@ -66,10 +53,7 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, screnarioIDSource s } if so.checkAccess(userID.(uint), userRole.(string)) == false { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": "Access denied (for scenario ID).", - }) + common.UnprocessableEntityError(c, "Access denied (for scenario ID).") return false, so } diff --git a/routes/scenario/scenario_test.go b/routes/scenario/scenario_test.go index a27e447..c2fe37d 100644 --- a/routes/scenario/scenario_test.go +++ b/routes/scenario/scenario_test.go @@ -24,7 +24,7 @@ type ScenarioRequest struct { func TestMain(m *testing.M) { - db = common.DummyInitDB() + db = common.InitDB(common.DB_TEST) defer db.Close() router = gin.Default() @@ -41,7 +41,7 @@ func TestAddScenario(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -93,7 +93,7 @@ func TestUpdateScenario(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -156,7 +156,7 @@ func TestGetAllScenariosAsAdmin(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -217,7 +217,7 @@ func TestGetAllScenariosAsUser(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal userB token, err := common.AuthenticateForTest(router, @@ -274,7 +274,7 @@ func TestDeleteScenario(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -323,7 +323,7 @@ func TestAddUserToScenario(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -378,7 +378,7 @@ func TestGetAllUsersOfScenario(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -423,7 +423,7 @@ func TestRemoveUserFromScenario(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, diff --git a/routes/signal/signal_endpoints.go b/routes/signal/signal_endpoints.go index e7a4a88..e25eb35 100644 --- a/routes/signal/signal_endpoints.go +++ b/routes/signal/signal_endpoints.go @@ -1,7 +1,6 @@ package signal import ( - "fmt" "net/http" "github.com/gin-gonic/gin" @@ -44,10 +43,7 @@ func getSignals(c *gin.Context) { } else if direction == "out" { mapping = "OutputMapping" } else { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "error": "Bad request. Direction has to be in or out", - }) + common.BadRequestError(c, "Bad request. Direction has to be in or out") return } @@ -58,9 +54,7 @@ func getSignals(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "signals": sigs, - }) + c.JSON(http.StatusOK, gin.H{"signals": sigs}) } // AddSignal godoc @@ -80,19 +74,13 @@ func addSignal(c *gin.Context) { var req addSignalRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Validate the request if err := req.validate(); err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } @@ -111,9 +99,7 @@ func addSignal(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "signal": newSignal.Signal, - }) + c.JSON(http.StatusOK, gin.H{"signal": newSignal.Signal}) } // updateSignal godoc @@ -137,29 +123,20 @@ func updateSignal(c *gin.Context) { var req updateSignalRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Validate the request if err := req.validate(); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Create the updatedSignal from oldDashboard updatedSignal, err := req.updatedSignal(oldSignal) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } @@ -170,9 +147,7 @@ func updateSignal(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "signal": updatedSignal.Signal, - }) + c.JSON(http.StatusOK, gin.H{"signal": updatedSignal.Signal}) } // getSignal godoc @@ -193,9 +168,7 @@ func getSignal(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "signal": sig.Signal, - }) + c.JSON(http.StatusOK, gin.H{"signal": sig.Signal}) } // deleteSignal godoc @@ -223,7 +196,5 @@ func deleteSignal(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "signal": sig.Signal, - }) + c.JSON(http.StatusOK, gin.H{"signal": sig.Signal}) } diff --git a/routes/signal/signal_middleware.go b/routes/signal/signal_middleware.go index a625e78..88fad8b 100644 --- a/routes/signal/signal_middleware.go +++ b/routes/signal/signal_middleware.go @@ -2,7 +2,6 @@ package signal import ( "fmt" - "net/http" "strconv" "github.com/gin-gonic/gin" @@ -17,19 +16,13 @@ func checkPermissions(c *gin.Context, operation common.CRUD) (bool, Signal) { err := common.ValidateRole(c, common.ModelSignal, operation) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("Access denied (role validation failed): %v", err), - }) + common.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation failed): %v", err.Error())) return false, sig } signalID, err := strconv.Atoi(c.Param("signalID")) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "error": fmt.Sprintf("Bad request. No or incorrect format of signalID path parameter"), - }) + common.BadRequestError(c, fmt.Sprintf("No or incorrect format of signalID path parameter")) return false, sig } diff --git a/routes/signal/signal_test.go b/routes/signal/signal_test.go index 9b39574..21532f4 100644 --- a/routes/signal/signal_test.go +++ b/routes/signal/signal_test.go @@ -101,7 +101,7 @@ func addScenarioAndSimulatorAndSimulationModel() (scenarioID uint, simulatorID u func TestMain(m *testing.M) { - db = common.DummyInitDB() + db = common.InitDB(common.DB_TEST) defer db.Close() router = gin.Default() @@ -126,7 +126,7 @@ func TestMain(m *testing.M) { func TestAddSignal(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB @@ -184,7 +184,7 @@ func TestAddSignal(t *testing.T) { func TestUpdateSignal(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB @@ -248,7 +248,7 @@ func TestUpdateSignal(t *testing.T) { func TestDeleteSignal(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB @@ -316,7 +316,7 @@ func TestDeleteSignal(t *testing.T) { func TestGetAllInputSignalsOfSimulationModel(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB diff --git a/routes/simulationmodel/simulationmodel_endpoints.go b/routes/simulationmodel/simulationmodel_endpoints.go index 05921b6..15e56c4 100644 --- a/routes/simulationmodel/simulationmodel_endpoints.go +++ b/routes/simulationmodel/simulationmodel_endpoints.go @@ -1,7 +1,6 @@ package simulationmodel import ( - "fmt" "net/http" "github.com/gin-gonic/gin" @@ -43,9 +42,7 @@ func getSimulationModels(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "models": models, - }) + c.JSON(http.StatusOK, gin.H{"models": models}) } // addSimulationModel godoc @@ -67,19 +64,13 @@ func addSimulationModel(c *gin.Context) { var req addSimulationModelRequest err := c.ShouldBindJSON(&req) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": "Bad request. Error binding form data to JSON: " + err.Error(), - }) + common.BadRequestError(c, "Bad request. Error binding form data to JSON: "+err.Error()) return } // validate the request if err = req.validate(); err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } @@ -99,9 +90,7 @@ func addSimulationModel(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "model": newSimulationModel.SimulationModel, - }) + c.JSON(http.StatusOK, gin.H{"model": newSimulationModel.SimulationModel}) } // updateSimulationModel godoc @@ -128,29 +117,20 @@ func updateSimulationModel(c *gin.Context) { var req updateSimulationModelRequest err := c.BindJSON(&req) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": "Bad request. Error binding form data to JSON: " + err.Error(), - }) + common.BadRequestError(c, "Error binding form data to JSON: "+err.Error()) return } // Validate the request if err := req.validate(); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Create the updatedSimulationModel from oldSimulationModel updatedSimulationModel, err := req.updatedSimulationModel(oldSimulationModel) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } @@ -161,9 +141,7 @@ func updateSimulationModel(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "model": updatedSimulationModel.SimulationModel, - }) + c.JSON(http.StatusOK, gin.H{"model": updatedSimulationModel.SimulationModel}) } @@ -186,9 +164,7 @@ func getSimulationModel(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "model": m.SimulationModel, - }) + c.JSON(http.StatusOK, gin.H{"model": m.SimulationModel}) } // deleteSimulationModel godoc @@ -215,7 +191,5 @@ func deleteSimulationModel(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "model": m.SimulationModel, - }) + c.JSON(http.StatusOK, gin.H{"model": m.SimulationModel}) } diff --git a/routes/simulationmodel/simulationmodel_middleware.go b/routes/simulationmodel/simulationmodel_middleware.go index d943eb1..aafd028 100644 --- a/routes/simulationmodel/simulationmodel_middleware.go +++ b/routes/simulationmodel/simulationmodel_middleware.go @@ -2,7 +2,6 @@ package simulationmodel import ( "fmt" - "net/http" "strconv" "github.com/gin-gonic/gin" @@ -17,10 +16,7 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, modelIDSource strin err := common.ValidateRole(c, common.ModelSimulationModel, operation) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("Access denied (role validation failed): %v", err), - }) + common.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation failed): %v", err.Error())) return false, m } @@ -28,20 +24,13 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, modelIDSource strin if modelIDSource == "path" { modelID, err = strconv.Atoi(c.Param("modelID")) if err != nil { - errormsg := fmt.Sprintf("Bad request. No or incorrect format of modelID path parameter") - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": errormsg, - }) + common.BadRequestError(c, fmt.Sprintf("No or incorrect format of modelID path parameter")) return false, m } } else if modelIDSource == "query" { modelID, err = strconv.Atoi(c.Request.URL.Query().Get("modelID")) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. No or incorrect format of modelID query parameter"), - }) + common.BadRequestError(c, fmt.Sprintf("No or incorrect format of modelID query parameter")) return false, m } } else if modelIDSource == "body" { diff --git a/routes/simulationmodel/simulationmodel_test.go b/routes/simulationmodel/simulationmodel_test.go index e0fa3df..f1fd9c6 100644 --- a/routes/simulationmodel/simulationmodel_test.go +++ b/routes/simulationmodel/simulationmodel_test.go @@ -79,7 +79,7 @@ func addScenarioAndSimulator() (scenarioID uint, simulatorID uint) { func TestMain(m *testing.M) { - db = common.DummyInitDB() + db = common.InitDB(common.DB_TEST) defer db.Close() router = gin.Default() @@ -101,7 +101,7 @@ func TestMain(m *testing.M) { func TestAddSimulationModel(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB @@ -160,7 +160,7 @@ func TestUpdateSimulationModel(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB @@ -222,7 +222,7 @@ func TestUpdateSimulationModel(t *testing.T) { func TestDeleteSimulationModel(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB @@ -276,7 +276,7 @@ func TestDeleteSimulationModel(t *testing.T) { func TestGetAllSimulationModelsOfScenario(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // prepare the content of the DB for testing // by adding a scenario and a simulator to the DB diff --git a/routes/simulator/simulator_endpoints.go b/routes/simulator/simulator_endpoints.go index 3d61edb..7501ef3 100644 --- a/routes/simulator/simulator_endpoints.go +++ b/routes/simulator/simulator_endpoints.go @@ -1,7 +1,6 @@ package simulator import ( - "fmt" "net/http" "time" @@ -47,9 +46,7 @@ func getSimulators(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "simulators": simulators, - }) + c.JSON(http.StatusOK, gin.H{"simulators": simulators}) } // addSimulator godoc @@ -75,20 +72,13 @@ func addSimulator(c *gin.Context) { var req addSimulatorRequest err := c.BindJSON(&req) if err != nil { - errormsg := "Bad request. Error binding form data to JSON: " + err.Error() - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": errormsg, - }) + common.BadRequestError(c, "Error binding form data to JSON: "+err.Error()) return } // Validate the request if err = req.validate(); err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } @@ -102,9 +92,7 @@ func addSimulator(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "simulator": newSimulator.Simulator, - }) + c.JSON(http.StatusOK, gin.H{"simulator": newSimulator.Simulator}) } // updateSimulator godoc @@ -131,29 +119,20 @@ func updateSimulator(c *gin.Context) { var req updateSimulatorRequest err := c.BindJSON(&req) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": "Bad request. Error binding form data to JSON: " + err.Error(), - }) + common.BadRequestError(c, "Error binding form data to JSON: "+err.Error()) return } // Validate the request if err = req.validate(); err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } // Create the updatedSimulator from oldSimulator updatedSimulator, err := req.updatedSimulator(oldSimulator) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } @@ -164,9 +143,7 @@ func updateSimulator(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "simulator": updatedSimulator.Simulator, - }) + c.JSON(http.StatusOK, gin.H{"simulator": updatedSimulator.Simulator}) } @@ -189,9 +166,7 @@ func getSimulator(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "simulator": s.Simulator, - }) + c.JSON(http.StatusOK, gin.H{"simulator": s.Simulator}) } // deleteSimulator godoc @@ -219,9 +194,7 @@ func deleteSimulator(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "simulator": s.Simulator, - }) + c.JSON(http.StatusOK, gin.H{"simulator": s.Simulator}) } // getModelsOfSimulator godoc @@ -249,9 +222,7 @@ func getModelsOfSimulator(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "models": allModels, - }) + c.JSON(http.StatusOK, gin.H{"models": allModels}) } // sendActionToSimulator godoc @@ -277,10 +248,7 @@ func sendActionToSimulator(c *gin.Context) { var actions []common.Action err := c.BindJSON(&actions) if err != nil { - errormsg := "Bad request. Error binding form data to JSON: " + err.Error() - c.JSON(http.StatusBadRequest, gin.H{ - "error": errormsg, - }) + common.BadRequestError(c, "Error binding form data to JSON: "+err.Error()) return } @@ -293,10 +261,7 @@ func sendActionToSimulator(c *gin.Context) { err = common.SendActionAMQP(action, s.UUID) if err != nil { - errormsg := "Internal Server Error. Unable to send actions to simulator: " + err.Error() - c.JSON(http.StatusInternalServerError, gin.H{ - "error": errormsg, - }) + common.InternalServerError(c, "Unable to send actions to simulator: "+err.Error()) return } } diff --git a/routes/simulator/simulator_middleware.go b/routes/simulator/simulator_middleware.go index 7c6e1a5..8968c2b 100644 --- a/routes/simulator/simulator_middleware.go +++ b/routes/simulator/simulator_middleware.go @@ -4,7 +4,6 @@ import ( "fmt" "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common" "github.com/gin-gonic/gin" - "net/http" "strconv" ) @@ -14,10 +13,7 @@ func checkPermissions(c *gin.Context, modeltype common.ModelName, operation comm err := common.ValidateRole(c, modeltype, operation) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return false, s } @@ -25,10 +21,7 @@ func checkPermissions(c *gin.Context, modeltype common.ModelName, operation comm // Get the ID of the simulator from the context simulatorID, err := strconv.Atoi(c.Param("simulatorID")) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Could not get simulator's ID from context"), - }) + common.BadRequestError(c, fmt.Sprintf("Could not get simulator's ID from context")) return false, s } diff --git a/routes/simulator/simulator_test.go b/routes/simulator/simulator_test.go index 77d449a..5d4c9ed 100644 --- a/routes/simulator/simulator_test.go +++ b/routes/simulator/simulator_test.go @@ -27,7 +27,7 @@ type SimulatorRequest struct { func TestMain(m *testing.M) { - db = common.DummyInitDB() + db = common.InitDB(common.DB_TEST) defer db.Close() router = gin.Default() @@ -43,7 +43,7 @@ func TestMain(m *testing.M) { func TestAddSimulatorAsAdmin(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -86,7 +86,7 @@ func TestAddSimulatorAsAdmin(t *testing.T) { func TestAddSimulatorAsUser(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as user token, err := common.AuthenticateForTest(router, @@ -113,7 +113,7 @@ func TestAddSimulatorAsUser(t *testing.T) { func TestUpdateSimulatorAsAdmin(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -168,7 +168,7 @@ func TestUpdateSimulatorAsAdmin(t *testing.T) { func TestUpdateSimulatorAsUser(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -210,7 +210,7 @@ func TestUpdateSimulatorAsUser(t *testing.T) { func TestDeleteSimulatorAsAdmin(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -260,7 +260,7 @@ func TestDeleteSimulatorAsAdmin(t *testing.T) { func TestDeleteSimulatorAsUser(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -301,7 +301,7 @@ func TestDeleteSimulatorAsUser(t *testing.T) { func TestGetAllSimulators(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -362,7 +362,7 @@ func TestGetAllSimulators(t *testing.T) { func TestGetSimulationModelsOfSimulator(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, diff --git a/routes/user/authenticate_endpoint.go b/routes/user/authenticate_endpoint.go new file mode 100644 index 0000000..4bdf59e --- /dev/null +++ b/routes/user/authenticate_endpoint.go @@ -0,0 +1,95 @@ +package user + +import ( + "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common" + "github.com/dgrijalva/jwt-go" + "github.com/gin-gonic/gin" + "net/http" + "time" +) + +type tokenClaims struct { + UserID uint `json:"id"` + Role string `json:"role"` + jwt.StandardClaims +} + +func RegisterAuthenticate(r *gin.RouterGroup) { + r.POST("", authenticate) +} + +// authenticate godoc +// @Summary Authentication for user +// @ID authenticate +// @Accept json +// @Produce json +// @Tags authentication +// @Param inputUser body user.loginRequest true "loginRequest of user" +// @Success 200 {object} docs.ResponseAuthenticate "JSON web token, success status, message and authenticated user object" +// @Failure 400 {object} docs.ResponseError "Bad request" +// @Failure 401 {object} docs.ResponseError "Unauthorized" +// @Failure 404 {object} docs.ResponseError "Not found" +// @Failure 422 {object} docs.ResponseError "Unprocessable entity." +// @Router /authenticate [post] +func authenticate(c *gin.Context) { + + // Bind the response (context) with the loginRequest struct + var credentials loginRequest + if err := c.ShouldBindJSON(&credentials); err != nil { + common.UnprocessableEntityError(c, err.Error()) + return + } + + // Validate the login request + if errs := credentials.validate(); errs != nil { + common.BadRequestError(c, errs.Error()) + return + } + + // Check if the Username or Password are empty + if credentials.Username == "" || credentials.Password == "" { + common.UnauthorizedError(c, "Invalid credentials") + return + } + + // Find the username in the database + var user User + err := user.ByUsername(credentials.Username) + if err != nil { + common.NotFoundError(c, "User not found") + return + } + + // Validate the password + err = user.validatePassword(credentials.Password) + if err != nil { + common.UnauthorizedError(c, "Invalid password") + return + } + + // create authentication token + claims := tokenClaims{ + user.ID, + user.Role, + jwt.StandardClaims{ + ExpiresAt: time.Now().Add(weekHours).Unix(), + IssuedAt: time.Now().Unix(), + Issuer: "http://web.villas.fein-aachen.org/", + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + tokenString, err := token.SignedString([]byte(jwtSigningSecret)) + if err != nil { + common.UnprocessableEntityError(c, err.Error()) + return + } + + c.JSON(http.StatusOK, gin.H{ + "success": true, + "message": "Authenticated", + "token": tokenString, + "user": user.User, + }) +} diff --git a/routes/user/user_endpoints.go b/routes/user/user_endpoints.go index 66738c8..941cb06 100644 --- a/routes/user/user_endpoints.go +++ b/routes/user/user_endpoints.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common" @@ -18,16 +17,6 @@ import ( const jwtSigningSecret = "This should NOT be here!!@33$8&" const weekHours = time.Hour * 24 * 7 -type tokenClaims struct { - UserID uint `json:"id"` - Role string `json:"role"` - jwt.StandardClaims -} - -func RegisterAuthenticate(r *gin.RouterGroup) { - r.POST("", authenticate) -} - func RegisterUserEndpoints(r *gin.RouterGroup) { r.POST("", addUser) r.PUT("/:userID", updateUser) @@ -36,100 +25,6 @@ func RegisterUserEndpoints(r *gin.RouterGroup) { r.DELETE("/:userID", deleteUser) } -// authenticate godoc -// @Summary Authentication for user -// @ID authenticate -// @Accept json -// @Produce json -// @Tags users -// @Param inputUser body user.loginRequest true "loginRequest of user" -// @Success 200 {object} docs.ResponseAuthenticate "JSON web token, success status, message and authenticated user object" -// @Failure 400 {object} docs.ResponseError "Bad request" -// @Failure 401 {object} docs.ResponseError "Unauthorized" -// @Failure 404 {object} docs.ResponseError "Not found" -// @Failure 422 {object} docs.ResponseError "Unprocessable entity." -// @Router /authenticate [post] -func authenticate(c *gin.Context) { - - // Bind the response (context) with the loginRequest struct - var credentials loginRequest - if err := c.ShouldBindJSON(&credentials); err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) - return - } - - // Validate the login request - if errs := credentials.validate(); errs != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", errs), - }) - return - } - - // Check if the Username or Password are empty - if credentials.Username == "" || credentials.Password == "" { - c.JSON(http.StatusUnauthorized, gin.H{ - "success": false, - "message": "Invalid credentials", - }) - return - } - - // Find the username in the database - var user User - err := user.ByUsername(credentials.Username) - if err != nil { - c.JSON(http.StatusNotFound, gin.H{ - "success": false, - "message": "User not found", - }) - return - } - - // Validate the password - err = user.validatePassword(credentials.Password) - if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{ - "success": false, - "message": "Invalid password", - }) - return - } - - // create authentication token - claims := tokenClaims{ - user.ID, - user.Role, - jwt.StandardClaims{ - ExpiresAt: time.Now().Add(weekHours).Unix(), - IssuedAt: time.Now().Unix(), - Issuer: "http://web.villas.fein-aachen.org/", - }, - } - - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - tokenString, err := token.SignedString([]byte(jwtSigningSecret)) - if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) - return - } - - c.JSON(http.StatusOK, gin.H{ - "success": true, - "message": "Authenticated", - "token": tokenString, - "user": user.User, - }) -} - // GetUsers godoc // @Summary Get all users // @ID GetUsers @@ -144,10 +39,7 @@ func getUsers(c *gin.Context) { err := common.ValidateRole(c, common.ModelUsers, common.Read) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } @@ -158,9 +50,7 @@ func getUsers(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "users": users, - }) + c.JSON(http.StatusOK, gin.H{"users": users}) } // AddUser godoc @@ -179,29 +69,20 @@ func addUser(c *gin.Context) { err := common.ValidateRole(c, common.ModelUser, common.Create) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } // Bind the request var req addUserRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Validate the request if err = req.validate(); err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } @@ -211,20 +92,14 @@ func addUser(c *gin.Context) { // Check that the username is NOT taken err = newUser.ByUsername(newUser.Username) if err == nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": "Username is already taken", - }) + common.UnprocessableEntityError(c, "Username is already taken") return } // Hash the password before saving it to the DB err = newUser.setPassword(newUser.Password) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": "Unable to encrypt the password", - }) + common.UnprocessableEntityError(c, "Unable to encrypt the password") return } @@ -235,9 +110,7 @@ func addUser(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "user": newUser.User, - }) + c.JSON(http.StatusOK, gin.H{"user": newUser.User}) } // UpdateUser godoc @@ -259,10 +132,7 @@ func updateUser(c *gin.Context) { err := common.ValidateRole(c, common.ModelUser, common.Update) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } @@ -270,10 +140,7 @@ func updateUser(c *gin.Context) { var oldUser User toBeUpdatedID, err := strconv.Atoi(c.Param("userID")) if err != nil { - c.JSON(http.StatusNotFound, gin.H{ - "success": false, - "message": fmt.Sprintf("Could not get user's ID from context"), - }) + common.NotFoundError(c, fmt.Sprintf("Could not get user's ID from context")) return } @@ -296,47 +163,32 @@ func updateUser(c *gin.Context) { // Get caller's ID from context callerID, exists := c.Get(common.UserIDCtx) if !exists { - c.JSON(http.StatusNotFound, gin.H{ - "success": false, - "message": fmt.Sprintf("Could not get caller's ID from context"), - }) + common.NotFoundError(c, fmt.Sprintf("Could not get caller's ID from context")) return } // Get caller's Role from context callerRole, exists := c.Get(common.UserRoleCtx) if !exists { - c.JSON(http.StatusNotFound, gin.H{ - "success": false, - "message": fmt.Sprintf("Could not get caller's Role from context"), - }) + common.NotFoundError(c, fmt.Sprintf("Could not get caller's Role from context")) return } if uint(toBeUpdatedID) != callerID && callerRole != "Admin" { - c.JSON(http.StatusForbidden, gin.H{ - "success": false, - "message": "Invalid authorization", - }) + common.ForbiddenError(c, "Invalid authorization") return } // Bind the (context) with the updateUserRequest struct var req updateUserRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, fmt.Sprintf("%v", err)) return } // Validate the request based on struct updateUserRequest json tags if err = req.validate(); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } @@ -345,16 +197,10 @@ func updateUser(c *gin.Context) { updatedUser, err := req.updatedUser(callerRole, oldUser) if err != nil { if strings.Contains(err.Error(), "Admin") { - c.JSON(http.StatusForbidden, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.ForbiddenError(c, err.Error()) } else if strings.Contains(err.Error(), "Username") || strings.Contains(err.Error(), "password") { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) } return } @@ -366,9 +212,7 @@ func updateUser(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "user": updatedUser.User, - }) + c.JSON(http.StatusOK, gin.H{"user": updatedUser.User}) } // GetUser godoc @@ -387,19 +231,13 @@ func getUser(c *gin.Context) { err := common.ValidateRole(c, common.ModelUser, common.Read) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } id, err := strconv.Atoi(c.Param("userID")) if err != nil { - c.JSON(http.StatusNotFound, gin.H{ - "success": false, - "message": fmt.Sprintf("Could not get user's ID from context"), - }) + common.NotFoundError(c, fmt.Sprintf("Could not get user's ID from context")) return } @@ -407,10 +245,7 @@ func getUser(c *gin.Context) { reqUserRole, _ := c.Get(common.UserRoleCtx) if id != reqUserID && reqUserRole != "Admin" { - c.JSON(http.StatusForbidden, gin.H{ - "success": false, - "message": "Invalid authorization", - }) + common.ForbiddenError(c, "Invalid authorization") return } @@ -421,9 +256,7 @@ func getUser(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "user": user.User, - }) + c.JSON(http.StatusOK, gin.H{"user": user.User}) } // DeleteUser godoc @@ -441,20 +274,14 @@ func deleteUser(c *gin.Context) { err := common.ValidateRole(c, common.ModelUser, common.Delete) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } var user User id, err := strconv.Atoi(c.Param("userID")) if err != nil { - c.JSON(http.StatusNotFound, gin.H{ - "success": false, - "message": fmt.Sprintf("Could not get user's ID from context"), - }) + common.NotFoundError(c, fmt.Sprintf("Could not get user's ID from context")) return } @@ -472,7 +299,5 @@ func deleteUser(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "user": user.User, - }) + c.JSON(http.StatusOK, gin.H{"user": user.User}) } diff --git a/routes/user/user_middleware.go b/routes/user/user_middleware.go index 674b496..a645867 100644 --- a/routes/user/user_middleware.go +++ b/routes/user/user_middleware.go @@ -6,7 +6,6 @@ import ( "github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go/request" "github.com/gin-gonic/gin" - "net/http" ) func userToContext(ctx *gin.Context, user_id uint) { @@ -15,10 +14,7 @@ func userToContext(ctx *gin.Context, user_id uint) { err := user.ByID(user_id) if err != nil { - ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ - "succes": false, - "message": "Authentication failed (user not found)", - }) + common.UnauthorizedAbort(ctx, "Authentication failed (user not found)") return } @@ -52,10 +48,7 @@ func Authentication(unauthorized bool) gin.HandlerFunc { // If the authentication extraction fails return HTTP CODE 401 if err != nil { if unauthorized { - ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ - "succes": false, - "message": "Authentication failed (claims extraction)", - }) + common.UnauthorizedAbort(ctx, "Authentication failed (claims extraction)") } return } @@ -66,10 +59,7 @@ func Authentication(unauthorized bool) gin.HandlerFunc { user_id, ok := claims["id"].(float64) if !ok { - ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{ - "succes": false, - "message": "Authentication failed (claims casting)", - }) + common.UnauthorizedAbort(ctx, "Authentication failed (claims casting)") return } diff --git a/routes/user/user_test.go b/routes/user/user_test.go index 09850aa..b5304c9 100644 --- a/routes/user/user_test.go +++ b/routes/user/user_test.go @@ -24,7 +24,7 @@ type UserRequest struct { func TestMain(m *testing.M) { - db = common.DummyInitDB() + db = common.InitDB(common.DB_TEST) defer db.Close() router = gin.Default() @@ -41,7 +41,7 @@ func TestAddGetUser(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminDB(db) + common.DBAddAdminUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -89,7 +89,7 @@ func TestUsersNotAllowedActions(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminDB(db) + common.DBAddAdminUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -149,7 +149,7 @@ func TestGetAllUsers(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminDB(db) + common.DBAddAdminUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -185,7 +185,7 @@ func TestModifyAddedUserAsUser(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminDB(db) + common.DBAddAdminUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -296,7 +296,7 @@ func TestInvalidUserUpdate(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminDB(db) + common.DBAddAdminUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -347,7 +347,7 @@ func TestModifyAddedUserAsAdmin(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminDB(db) + common.DBAddAdminUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, @@ -429,7 +429,7 @@ func TestDeleteUser(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminDB(db) + common.DBAddAdminUser(db) // authenticate as admin token, err := common.AuthenticateForTest(router, diff --git a/routes/widget/widget_endpoints.go b/routes/widget/widget_endpoints.go index 08abe09..4e27e53 100644 --- a/routes/widget/widget_endpoints.go +++ b/routes/widget/widget_endpoints.go @@ -1,7 +1,6 @@ package widget import ( - "fmt" "net/http" "github.com/gin-gonic/gin" @@ -43,9 +42,7 @@ func getWidgets(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "widgets": widgets, - }) + c.JSON(http.StatusOK, gin.H{"widgets": widgets}) } // addWidget godoc @@ -65,19 +62,13 @@ func addWidget(c *gin.Context) { var req addWidgetRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Validate the request if err := req.validate(); err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.UnprocessableEntityError(c, err.Error()) return } @@ -96,9 +87,7 @@ func addWidget(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "widget": newWidget.Widget, - }) + c.JSON(http.StatusOK, gin.H{"widget": newWidget.Widget}) } // updateWidget godoc @@ -124,29 +113,20 @@ func updateWidget(c *gin.Context) { var req updateWidgetRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) return } // Validate the request if err := req.validate(); err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("%v", err), - }) + common.BadRequestError(c, err.Error()) 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), - }) + common.BadRequestError(c, err.Error()) return } @@ -157,9 +137,7 @@ func updateWidget(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "widget": updatedWidget.Widget, - }) + c.JSON(http.StatusOK, gin.H{"widget": updatedWidget.Widget}) } @@ -182,9 +160,7 @@ func getWidget(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "widget": w.Widget, - }) + c.JSON(http.StatusOK, gin.H{"widget": w.Widget}) } // deleteWidget godoc @@ -211,7 +187,5 @@ func deleteWidget(c *gin.Context) { return } - c.JSON(http.StatusOK, gin.H{ - "widget": w.Widget, - }) + c.JSON(http.StatusOK, gin.H{"widget": w.Widget}) } diff --git a/routes/widget/widget_middleware.go b/routes/widget/widget_middleware.go index a573be9..d168909 100644 --- a/routes/widget/widget_middleware.go +++ b/routes/widget/widget_middleware.go @@ -2,7 +2,6 @@ package widget import ( "fmt" - "net/http" "strconv" "github.com/gin-gonic/gin" @@ -17,10 +16,7 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, widgetIDBody int) ( err := common.ValidateRole(c, common.ModelWidget, operation) if err != nil { - c.JSON(http.StatusUnprocessableEntity, gin.H{ - "success": false, - "message": fmt.Sprintf("Access denied (role validation failed): %v", err), - }) + common.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation failed): %v", err.Error())) return false, w } @@ -28,11 +24,7 @@ func CheckPermissions(c *gin.Context, operation common.CRUD, widgetIDBody int) ( if widgetIDBody < 0 { widgetID, err = strconv.Atoi(c.Param("widgetID")) if err != nil { - - c.JSON(http.StatusBadRequest, gin.H{ - "success": false, - "message": fmt.Sprintf("Bad request. No or incorrect format of widgetID path parameter"), - }) + common.BadRequestError(c, fmt.Sprintf("No or incorrect format of widgetID path parameter")) return false, w } } else { diff --git a/routes/widget/widget_test.go b/routes/widget/widget_test.go index aa89b0b..c826423 100644 --- a/routes/widget/widget_test.go +++ b/routes/widget/widget_test.go @@ -75,7 +75,7 @@ func addScenarioAndDashboard(token string) (scenarioID uint, dashboardID uint) { func TestMain(m *testing.M) { - db = common.DummyInitDB() + db = common.InitDB(common.DB_TEST) defer db.Close() router = gin.Default() @@ -97,7 +97,7 @@ func TestMain(m *testing.M) { func TestAddWidget(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -159,7 +159,7 @@ func TestAddWidget(t *testing.T) { func TestUpdateWidget(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -232,7 +232,7 @@ func TestUpdateWidget(t *testing.T) { func TestDeleteWidget(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, @@ -291,7 +291,7 @@ func TestDeleteWidget(t *testing.T) { func TestGetAllWidgetsOfDashboard(t *testing.T) { common.DropTables(db) common.MigrateModels(db) - common.DummyAddOnlyUserTableWithAdminAndUsersDB(db) + common.DBAddAdminAndUser(db) // authenticate as normal user token, err := common.AuthenticateForTest(router, diff --git a/start.go b/start.go index 792a85a..7827f7f 100644 --- a/start.go +++ b/start.go @@ -37,12 +37,13 @@ import ( // @host localhost:4000 // @BasePath /api/v2 func main() { - // Testing - db := common.DummyInitDB() + // TODO DB_TEST is used for testing, should be DB_NAME in production + db := common.InitDB(common.DB_TEST) common.MigrateModels(db) defer db.Close() - common.DummyPopulateDB(db) + // TODO the following line should be removed in production, it adds test data to the DB + common.AddTestData(db) r := gin.Default()