move functions to duplicate scenarios into respective packages, resolve circular dependency problems (move permissions checking to database package), improve error handling of async DuplicateScenarioForUser function

This commit is contained in:
Sonja Happ 2021-10-18 17:20:28 +02:00
parent 93d14300d8
commit 302b1cc470
42 changed files with 1051 additions and 887 deletions

View file

@ -176,3 +176,67 @@ func generatePassword(Len int) string {
return b.String()
}
// add test users defined above
func AddTestUsers() error {
testUsers := []User{User0, UserA, UserB, UserC}
DBpool.AutoMigrate(&User{})
for _, user := range testUsers {
err := DBpool.Create(&user).Error
if err != nil {
return err
}
}
return nil
}
// Credentials
var StrPassword0 = "xyz789"
var StrPasswordA = "abc123"
var StrPasswordB = "bcd234"
var StrPasswordC = "guestpw"
// Hash passwords with bcrypt algorithm
var bcryptCost = 10
var pw0, _ = bcrypt.GenerateFromPassword([]byte(StrPassword0), bcryptCost)
var pwA, _ = bcrypt.GenerateFromPassword([]byte(StrPasswordA), bcryptCost)
var pwB, _ = bcrypt.GenerateFromPassword([]byte(StrPasswordB), bcryptCost)
var pwC, _ = bcrypt.GenerateFromPassword([]byte(StrPasswordC), bcryptCost)
var User0 = User{Username: "User_0", Password: string(pw0),
Role: "Admin", Mail: "User_0@example.com"}
var UserA = User{Username: "User_A", Password: string(pwA),
Role: "User", Mail: "User_A@example.com", Active: true}
var UserB = User{Username: "User_B", Password: string(pwB),
Role: "User", Mail: "User_B@example.com", Active: true}
var UserC = User{Username: "User_C", Password: string(pwC),
Role: "Guest", Mail: "User_C@example.com", Active: true}
type Credentials struct {
Username string `json:"username,required"`
Password string `json:"password,required"`
}
var AdminCredentials = Credentials{
Username: User0.Username,
Password: StrPassword0,
}
var UserACredentials = Credentials{
Username: UserA.Username,
Password: StrPasswordA,
}
var UserBCredentials = Credentials{
Username: UserB.Username,
Password: StrPasswordB,
}
var GuestCredentials = Credentials{
Username: UserC.Username,
Password: StrPasswordC,
}

301
database/permissions.go Normal file
View file

@ -0,0 +1,301 @@
/** Database package, roles.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package database
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"github.com/gin-gonic/gin"
)
func CheckScenarioPermissions(c *gin.Context, operation CRUD, scenarioIDsource string, scenarioIDbody int) (bool, Scenario) {
var so Scenario
err := ValidateRole(c, ModelScenario, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of scenario failed): %v", err))
return false, so
}
if operation == Create || (operation == Read && scenarioIDsource == "none") {
return true, so
}
scenarioID, err := helper.GetIDOfElement(c, "scenarioID", scenarioIDsource, scenarioIDbody)
if err != nil {
return false, so
}
userID, _ := c.Get(UserIDCtx)
db := GetDB()
err = db.Find(&so, uint(scenarioID)).Error
if helper.DBError(c, err) {
return false, so
}
hasAccess := false
u := User{}
err = db.Find(&u, userID.(uint)).Error
if err != nil {
hasAccess = false
}
if u.Role == "Admin" {
hasAccess = true
}
scenarioUser := User{}
err = db.Order("ID asc").Model(&so).Where("ID = ?", userID.(uint)).Related(&scenarioUser, "Users").Error
if err != nil {
hasAccess = false
}
if !scenarioUser.Active {
hasAccess = false
} else if so.IsLocked && operation != Read {
hasAccess = false
} else {
hasAccess = true
}
if hasAccess == false {
helper.UnprocessableEntityError(c, "Access denied (user has no access or scenario is locked).")
return false, so
}
return true, so
}
func CheckComponentConfigPermissions(c *gin.Context, operation CRUD, configIDSource string, configIDBody int) (bool, ComponentConfiguration) {
var m ComponentConfiguration
err := ValidateRole(c, ModelComponentConfiguration, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of Component Configuration failed): %v", err.Error()))
return false, m
}
configID, err := helper.GetIDOfElement(c, "configID", configIDSource, configIDBody)
if err != nil {
return false, m
}
db := GetDB()
err = db.Find(&m, uint(configID)).Error
if helper.DBError(c, err) {
return false, m
}
ok, _ := CheckScenarioPermissions(c, operation, "body", int(m.ScenarioID))
if !ok {
return false, m
}
return true, m
}
func CheckSignalPermissions(c *gin.Context, operation CRUD) (bool, Signal) {
var sig Signal
err := ValidateRole(c, ModelSignal, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of signal failed): %v", err.Error()))
return false, sig
}
signalID, err := helper.GetIDOfElement(c, "signalID", "path", -1)
if err != nil {
return false, sig
}
db := GetDB()
err = db.Find(&sig, uint(signalID)).Error
if helper.DBError(c, err) {
return false, sig
}
ok, _ := CheckComponentConfigPermissions(c, operation, "body", int(sig.ConfigID))
if !ok {
return false, sig
}
return true, sig
}
func CheckDashboardPermissions(c *gin.Context, operation CRUD, dabIDSource string, dabIDBody int) (bool, Dashboard) {
var dab Dashboard
err := ValidateRole(c, ModelDashboard, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation failed): %v", err.Error()))
return false, dab
}
dabID, err := helper.GetIDOfElement(c, "dashboardID", dabIDSource, dabIDBody)
if err != nil {
return false, dab
}
db := GetDB()
err = db.Find(&dab, uint(dabID)).Error
if helper.DBError(c, err) {
return false, dab
}
ok, _ := CheckScenarioPermissions(c, operation, "body", int(dab.ScenarioID))
if !ok {
return false, dab
}
return true, dab
}
func CheckWidgetPermissions(c *gin.Context, operation CRUD, widgetIDBody int) (bool, Widget) {
var w Widget
var err error
err = ValidateRole(c, ModelWidget, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of widget failed): %v", err.Error()))
return false, w
}
var widgetID int
if widgetIDBody < 0 {
widgetID, err = helper.GetIDOfElement(c, "widgetID", "path", -1)
if err != nil {
return false, w
}
} else {
widgetID = widgetIDBody
}
db := GetDB()
err = db.Find(&w, uint(widgetID)).Error
if helper.DBError(c, err) {
return false, w
}
ok, _ := CheckDashboardPermissions(c, operation, "body", int(w.DashboardID))
if !ok {
return false, w
}
return true, w
}
func CheckFilePermissions(c *gin.Context, operation CRUD) (bool, File) {
var f File
err := ValidateRole(c, ModelFile, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of file failed): %v", err.Error()))
return false, f
}
fileID, err := helper.GetIDOfElement(c, "fileID", "path", -1)
if err != nil {
return false, f
}
db := GetDB()
err = db.Find(&f, uint(fileID)).Error
if helper.DBError(c, err) {
return false, f
}
if operation != Read {
// check access to scenario only if operation is not Read (=download) of file
ok, _ := CheckScenarioPermissions(c, operation, "body", int(f.ScenarioID))
if !ok {
return false, f
}
}
return true, f
}
func CheckResultPermissions(c *gin.Context, operation CRUD, resultIDSource string, resultIDBody int) (bool, Result) {
var result Result
err := ValidateRole(c, ModelResult, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation failed): %v", err.Error()))
return false, result
}
resultID, err := helper.GetIDOfElement(c, "resultID", resultIDSource, resultIDBody)
if err != nil {
return false, result
}
db := GetDB()
err = db.Find(&result, uint(resultID)).Error
if helper.DBError(c, err) {
return false, result
}
ok, _ := CheckScenarioPermissions(c, operation, "body", int(result.ScenarioID))
if !ok {
return false, result
}
return true, result
}
func CheckICPermissions(c *gin.Context, modeltype ModelName, operation CRUD, hasID bool) (bool, InfrastructureComponent) {
var s InfrastructureComponent
err := ValidateRole(c, modeltype, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of infrastructure component failed): %v", err.Error()))
return false, s
}
if hasID {
// Get the ID of the infrastructure component from the context
ICID, err := helper.GetIDOfElement(c, "ICID", "path", -1)
if err != nil {
return false, s
}
db := GetDB()
err = db.Find(&s, uint(ICID)).Error
if helper.DBError(c, err) {
return false, s
}
}
return true, s
}

View file

@ -23,7 +23,6 @@ package database
import (
"fmt"
"github.com/gin-gonic/gin"
)

View file

@ -25,10 +25,8 @@ import (
"bytes"
"encoding/json"
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"github.com/gin-gonic/gin"
"github.com/nsf/jsondiff"
"golang.org/x/crypto/bcrypt"
"log"
"net/http"
"net/http/httptest"
@ -41,28 +39,6 @@ type KeyModels map[string]interface{}
// #################### User data used for testing #######################
// #######################################################################
// Credentials
var StrPassword0 = "xyz789"
var StrPasswordA = "abc123"
var StrPasswordB = "bcd234"
var StrPasswordC = "guestpw"
// Hash passwords with bcrypt algorithm
var bcryptCost = 10
var pw0, _ = bcrypt.GenerateFromPassword([]byte(StrPassword0), bcryptCost)
var pwA, _ = bcrypt.GenerateFromPassword([]byte(StrPasswordA), bcryptCost)
var pwB, _ = bcrypt.GenerateFromPassword([]byte(StrPasswordB), bcryptCost)
var pwC, _ = bcrypt.GenerateFromPassword([]byte(StrPasswordC), bcryptCost)
var User0 = database.User{Username: "User_0", Password: string(pw0),
Role: "Admin", Mail: "User_0@example.com"}
var UserA = database.User{Username: "User_A", Password: string(pwA),
Role: "User", Mail: "User_A@example.com", Active: true}
var UserB = database.User{Username: "User_B", Password: string(pwB),
Role: "User", Mail: "User_B@example.com", Active: true}
var UserC = database.User{Username: "User_C", Password: string(pwC),
Role: "Guest", Mail: "User_C@example.com", Active: true}
type UserRequest struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
@ -72,31 +48,6 @@ type UserRequest struct {
Active string `json:"active,omitempty"`
}
type Credentials struct {
Username string `json:"username,required"`
Password string `json:"password,required"`
}
var AdminCredentials = Credentials{
Username: User0.Username,
Password: StrPassword0,
}
var UserACredentials = Credentials{
Username: UserA.Username,
Password: StrPasswordA,
}
var UserBCredentials = Credentials{
Username: UserB.Username,
Password: StrPasswordB,
}
var GuestCredentials = Credentials{
Username: UserC.Username,
Password: StrPasswordC,
}
// ############################################################################
// #################### Functions used for testing ############################
// ############################################################################
@ -314,20 +265,3 @@ func AuthenticateForTest(router *gin.Engine, credentials interface{}) (string, e
// Return the token and nil error
return token, nil
}
// add test users defined above
func AddTestUsers() error {
testUsers := []database.User{User0, UserA, UserB, UserC}
database.DBpool.AutoMigrate(&database.User{})
for _, user := range testUsers {
err := database.DBpool.Create(&user).Error
if err != nil {
return err
}
}
return nil
}

View file

@ -29,7 +29,6 @@ import (
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
)
func RegisterComponentConfigurationEndpoints(r *gin.RouterGroup) {
@ -54,7 +53,7 @@ func RegisterComponentConfigurationEndpoints(r *gin.RouterGroup) {
// @Security Bearer
func getConfigs(c *gin.Context) {
ok, so := scenario.CheckPermissions(c, database.Read, "query", -1)
ok, so := database.CheckScenarioPermissions(c, database.Read, "query", -1)
if !ok {
return
}
@ -102,7 +101,7 @@ func addConfig(c *gin.Context) {
newConfig := req.createConfig()
// check access to the scenario
ok, _ := scenario.CheckPermissions(c, database.Update, "body", int(newConfig.ScenarioID))
ok, _ := database.CheckScenarioPermissions(c, database.Update, "body", int(newConfig.ScenarioID))
if !ok {
return
}
@ -132,11 +131,15 @@ func addConfig(c *gin.Context) {
// @Security Bearer
func updateConfig(c *gin.Context) {
ok, oldConfig := CheckPermissions(c, database.Update, "path", -1)
ok, oldConfig_r := database.CheckComponentConfigPermissions(c, database.Update, "path", -1)
if !ok {
return
}
var oldConfig ComponentConfiguration
oldConfig.ComponentConfiguration = oldConfig_r
var req updateConfigRequest
err := c.BindJSON(&req)
if err != nil {
@ -176,12 +179,12 @@ func updateConfig(c *gin.Context) {
// @Security Bearer
func getConfig(c *gin.Context) {
ok, m := CheckPermissions(c, database.Read, "path", -1)
ok, m := database.CheckComponentConfigPermissions(c, database.Read, "path", -1)
if !ok {
return
}
c.JSON(http.StatusOK, gin.H{"config": m.ComponentConfiguration})
c.JSON(http.StatusOK, gin.H{"config": m})
}
// deleteConfig godoc
@ -199,11 +202,14 @@ func getConfig(c *gin.Context) {
// @Security Bearer
func deleteConfig(c *gin.Context) {
ok, m := CheckPermissions(c, database.Delete, "path", -1)
ok, m_r := database.CheckComponentConfigPermissions(c, database.Delete, "path", -1)
if !ok {
return
}
var m ComponentConfiguration
m.ComponentConfiguration = m_r
err := m.delete()
if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"config": m.ComponentConfiguration})

View file

@ -23,7 +23,7 @@ package component_configuration
import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/signal"
"log"
)
@ -48,8 +48,8 @@ func (m *ComponentConfiguration) ByID(id uint) error {
func (m *ComponentConfiguration) addToScenario() error {
db := database.GetDB()
var so scenario.Scenario
err := so.ByID(m.ScenarioID)
var so database.Scenario
err := db.Find(&so, m.ScenarioID).Error
if err != nil {
return err
}
@ -119,8 +119,8 @@ func (m *ComponentConfiguration) Update(modifiedConfig ComponentConfiguration) e
func (m *ComponentConfiguration) delete() error {
db := database.GetDB()
var so scenario.Scenario
err := so.ByID(m.ScenarioID)
var so database.Scenario
err := db.Find(&so, m.ScenarioID).Error
if err != nil {
return err
}
@ -185,3 +185,53 @@ func (m *ComponentConfiguration) delete() error {
return nil
}
func (m *ComponentConfiguration) Duplicate(scenarioID uint, icIds map[uint]string, signalMap *map[uint]uint) error {
db := database.GetDB()
var dup ComponentConfiguration
dup.Name = m.Name
dup.StartParameters = m.StartParameters
dup.ScenarioID = scenarioID
if icIds[m.ICID] == "" {
dup.ICID = m.ICID
} else {
var duplicatedIC database.InfrastructureComponent
err := db.Find(&duplicatedIC, "UUID = ?", icIds[m.ICID]).Error
if err != nil {
log.Print(err)
return err
}
dup.ICID = duplicatedIC.ID
}
// save duplicate to DB and create associations with IC and scenario
err := dup.addToScenario()
if err != nil {
return err
}
// duplication of signals
var sigs []signal.Signal
err = db.Order("ID asc").Model(&m).Related(&sigs, "OutputMapping").Error
smap := *signalMap
for _, s := range sigs {
var sigDup signal.Signal
sigDup.Direction = s.Direction
sigDup.Index = s.Index
sigDup.Name = s.Name // + ` ` + userName
sigDup.ScalingFactor = s.ScalingFactor
sigDup.Unit = s.Unit
sigDup.ConfigID = dup.ID
err = sigDup.AddToConfig()
if err != nil {
return err
}
smap[s.ID] = sigDup.ID
}
return nil
}

View file

@ -1,59 +0,0 @@
/** component_configuration package, middleware.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package component_configuration
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
)
func CheckPermissions(c *gin.Context, operation database.CRUD, configIDSource string, configIDBody int) (bool, ComponentConfiguration) {
var m ComponentConfiguration
err := database.ValidateRole(c, database.ModelComponentConfiguration, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of Component Configuration failed): %v", err.Error()))
return false, m
}
configID, err := helper.GetIDOfElement(c, "configID", configIDSource, configIDBody)
if err != nil {
return false, m
}
err = m.ByID(uint(configID))
if helper.DBError(c, err) {
return false, m
}
ok, _ := scenario.CheckPermissions(c, operation, "body", int(m.ScenarioID))
if !ok {
return false, m
}
return true, m
}

View file

@ -81,7 +81,7 @@ func newFalse() *bool {
func addScenarioAndIC() (scenarioID uint, ICID uint) {
// authenticate as admin
token, _ := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, _ := helper.AuthenticateForTest(router, database.AdminCredentials)
// POST $newICA
newICA := ICRequest{
@ -114,7 +114,7 @@ func addScenarioAndIC() (scenarioID uint, ICID uint) {
}
// authenticate as normal user
token, _ = helper.AuthenticateForTest(router, helper.UserACredentials)
token, _ = helper.AuthenticateForTest(router, database.UserACredentials)
// POST $newScenario
newScenario := ScenarioRequest{
@ -168,7 +168,7 @@ func TestMain(m *testing.M) {
func TestAddConfig(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
@ -178,7 +178,7 @@ func TestAddConfig(t *testing.T) {
newConfig1.ScenarioID = scenarioID
newConfig1.ICID = ICID
// authenticate as normal userB who has no access to new scenario
token, err := helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err := helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to POST with no access
@ -189,7 +189,7 @@ func TestAddConfig(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to POST non JSON body
@ -199,7 +199,7 @@ func TestAddConfig(t *testing.T) {
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST newConfig
@ -238,7 +238,7 @@ func TestAddConfig(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// Try to GET the newConfig with no access
@ -254,7 +254,7 @@ func TestUpdateConfig(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
@ -262,7 +262,7 @@ func TestUpdateConfig(t *testing.T) {
scenarioID, ICID := addScenarioAndIC()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST newConfig
@ -283,7 +283,7 @@ func TestUpdateConfig(t *testing.T) {
}
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to PUT with no access
@ -294,7 +294,7 @@ func TestUpdateConfig(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as guest user who has access to component config
token, err = helper.AuthenticateForTest(router, helper.GuestCredentials)
token, err = helper.AuthenticateForTest(router, database.GuestCredentials)
assert.NoError(t, err)
// try to PUT as guest
@ -305,7 +305,7 @@ func TestUpdateConfig(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to PUT a non JSON body
@ -357,7 +357,7 @@ func TestUpdateConfig(t *testing.T) {
func TestDeleteConfig(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
@ -367,7 +367,7 @@ func TestDeleteConfig(t *testing.T) {
newConfig1.ICID = ICID
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST newConfig
@ -381,7 +381,7 @@ func TestDeleteConfig(t *testing.T) {
assert.NoError(t, err)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to DELETE with no access
@ -392,7 +392,7 @@ func TestDeleteConfig(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all the component config returned for scenario
@ -421,7 +421,7 @@ func TestDeleteConfig(t *testing.T) {
func TestGetAllConfigsOfScenario(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
@ -431,7 +431,7 @@ func TestGetAllConfigsOfScenario(t *testing.T) {
newConfig1.ICID = ICID
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST newConfig
@ -448,7 +448,7 @@ func TestGetAllConfigsOfScenario(t *testing.T) {
assert.Equal(t, 1, NumberOfConfigs)
// authenticate as normal userB who has no access to scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to get configs without access

View file

@ -29,7 +29,6 @@ import (
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
)
func RegisterDashboardEndpoints(r *gin.RouterGroup) {
@ -55,7 +54,7 @@ func RegisterDashboardEndpoints(r *gin.RouterGroup) {
// @Security Bearer
func getDashboards(c *gin.Context) {
ok, sim := scenario.CheckPermissions(c, database.Read, "query", -1)
ok, sim := database.CheckScenarioPermissions(c, database.Read, "query", -1)
if !ok {
return
}
@ -102,7 +101,7 @@ func addDashboard(c *gin.Context) {
newDashboard := req.createDashboard()
// Check if user is allowed to modify scenario specified in request
ok, _ := scenario.CheckPermissions(c, database.Update, "body", int(newDashboard.ScenarioID))
ok, _ := database.CheckScenarioPermissions(c, database.Update, "body", int(newDashboard.ScenarioID))
if !ok {
return
}
@ -132,11 +131,14 @@ func addDashboard(c *gin.Context) {
// @Security Bearer
func updateDashboard(c *gin.Context) {
ok, oldDashboard := CheckPermissions(c, database.Update, "path", -1)
ok, oldDashboard_r := database.CheckDashboardPermissions(c, database.Update, "path", -1)
if !ok {
return
}
var oldDashboard Dashboard
oldDashboard.Dashboard = oldDashboard_r
var req updateDashboardRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.BadRequestError(c, err.Error())
@ -174,12 +176,12 @@ func updateDashboard(c *gin.Context) {
// @Security Bearer
func getDashboard(c *gin.Context) {
ok, dab := CheckPermissions(c, database.Read, "path", -1)
ok, dab := database.CheckDashboardPermissions(c, database.Read, "path", -1)
if !ok {
return
}
c.JSON(http.StatusOK, gin.H{"dashboard": dab.Dashboard})
c.JSON(http.StatusOK, gin.H{"dashboard": dab})
}
// deleteDashboard godoc
@ -196,11 +198,14 @@ func getDashboard(c *gin.Context) {
// @Router /dashboards/{dashboardID} [delete]
// @Security Bearer
func deleteDashboard(c *gin.Context) {
ok, dab := CheckPermissions(c, database.Delete, "path", -1)
ok, dab_r := database.CheckDashboardPermissions(c, database.Delete, "path", -1)
if !ok {
return
}
var dab Dashboard
dab.Dashboard = dab_r
err := dab.delete()
if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"dashboard": dab.Dashboard})

View file

@ -23,7 +23,8 @@ package dashboard
import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
"log"
)
type Dashboard struct {
@ -47,8 +48,8 @@ func (d *Dashboard) ByID(id uint) error {
func (d *Dashboard) addToScenario() error {
db := database.GetDB()
var sim scenario.Scenario
err := sim.ByID(d.ScenarioID)
var sim database.Scenario
err := db.Find(&sim, d.ScenarioID).Error
if err != nil {
return err
}
@ -81,8 +82,8 @@ func (d *Dashboard) update(modifiedDab Dashboard) error {
func (d *Dashboard) delete() error {
db := database.GetDB()
var sim scenario.Scenario
err := sim.ByID(d.ScenarioID)
var sim database.Scenario
err := db.Find(&sim, d.ScenarioID).Error
if err != nil {
return err
}
@ -107,3 +108,35 @@ func (d *Dashboard) delete() error {
return err
}
func (d *Dashboard) Duplicate(scenarioID uint, signalMap map[uint]uint) error {
var duplicateD Dashboard
duplicateD.Grid = d.Grid
duplicateD.Name = d.Name
duplicateD.ScenarioID = scenarioID
duplicateD.Height = d.Height
err := duplicateD.addToScenario()
if err != nil {
return err
}
// add widgets to duplicated dashboard
var widgets []widget.Widget
db := database.GetDB()
err = db.Order("ID asc").Model(d).Related(&widgets, "Widgets").Error
if err != nil {
log.Printf("Error getting widgets for dashboard %d: %s", d.ID, err)
}
for _, w := range widgets {
err = w.Duplicate(duplicateD.ID, signalMap)
if err != nil {
log.Printf("error creating duplicate for widget %d: %s", w.ID, err)
continue
}
}
return nil
}

View file

@ -1,59 +0,0 @@
/** Dashboard package, middleware.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package dashboard
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
)
func CheckPermissions(c *gin.Context, operation database.CRUD, dabIDSource string, dabIDBody int) (bool, Dashboard) {
var dab Dashboard
err := database.ValidateRole(c, database.ModelDashboard, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation failed): %v", err.Error()))
return false, dab
}
dabID, err := helper.GetIDOfElement(c, "dashboardID", dabIDSource, dabIDBody)
if err != nil {
return false, dab
}
err = dab.ByID(uint(dabID))
if helper.DBError(c, err) {
return false, dab
}
ok, _ := scenario.CheckPermissions(c, operation, "body", int(dab.ScenarioID))
if !ok {
return false, dab
}
return true, dab
}

View file

@ -107,10 +107,10 @@ func TestMain(m *testing.M) {
func TestAddDashboard(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
scenarioID := addScenario(token)
@ -166,7 +166,7 @@ func TestAddDashboard(t *testing.T) {
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
// try to get dashboard as a user that is not in the scenario (userB)
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// this should fail with unprocessable entity
@ -187,10 +187,10 @@ func TestAddDashboard(t *testing.T) {
func TestUpdateDashboard(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
scenarioID := addScenario(token)
@ -212,7 +212,7 @@ func TestUpdateDashboard(t *testing.T) {
}
// authenticate as guest user
token, err = helper.AuthenticateForTest(router, helper.GuestCredentials)
token, err = helper.AuthenticateForTest(router, database.GuestCredentials)
assert.NoError(t, err)
// try to update a dashboard as guest
@ -223,7 +223,7 @@ func TestUpdateDashboard(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
code, resp, err = helper.TestEndpoint(router, token,
@ -261,10 +261,10 @@ func TestUpdateDashboard(t *testing.T) {
func TestDeleteDashboard(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
scenarioID := addScenario(token)
@ -281,7 +281,7 @@ func TestDeleteDashboard(t *testing.T) {
assert.NoError(t, err)
// try to delete a dashboard from a scenario to which the user has no access
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// this should fail with unprocessable entity
@ -291,7 +291,7 @@ func TestDeleteDashboard(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to delete a dashboard that does not exist; should return a not found error
@ -327,10 +327,10 @@ func TestDeleteDashboard(t *testing.T) {
func TestGetAllDashboardsOfScenario(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
scenarioID := addScenario(token)
@ -372,7 +372,7 @@ func TestGetAllDashboardsOfScenario(t *testing.T) {
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
// try to get all dashboards as a user that does not belong to scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// this should fail with unprocessable entity

View file

@ -26,7 +26,6 @@ import (
"net/http"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
@ -54,7 +53,7 @@ func RegisterFileEndpoints(r *gin.RouterGroup) {
// @Security Bearer
func getFiles(c *gin.Context) {
ok, so := scenario.CheckPermissions(c, database.Read, "query", -1)
ok, so := database.CheckScenarioPermissions(c, database.Read, "query", -1)
if !ok {
return
}
@ -92,7 +91,7 @@ func getFiles(c *gin.Context) {
// @Security Bearer
func addFile(c *gin.Context) {
ok, so := scenario.CheckPermissions(c, database.Read, "query", -1)
ok, so := database.CheckScenarioPermissions(c, database.Read, "query", -1)
if !ok {
return
}
@ -142,11 +141,14 @@ func addFile(c *gin.Context) {
func getFile(c *gin.Context) {
// check access
ok, f := CheckPermissions(c, database.Read)
ok, f_r := database.CheckFilePermissions(c, database.Read)
if !ok {
return
}
var f File
f.File = f_r
err := f.download(c)
helper.DBError(c, err)
}
@ -175,11 +177,14 @@ func getFile(c *gin.Context) {
func updateFile(c *gin.Context) {
// check access
ok, f := CheckPermissions(c, database.Update)
ok, f_r := database.CheckFilePermissions(c, database.Update)
if !ok {
return
}
var f File
f.File = f_r
// Extract file from PUT request form
fileHeader, err := c.FormFile("file")
if err != nil {
@ -209,11 +214,14 @@ func updateFile(c *gin.Context) {
func deleteFile(c *gin.Context) {
// check access
ok, f := CheckPermissions(c, database.Delete)
ok, f_r := database.CheckFilePermissions(c, database.Delete)
if !ok {
return
}
var f File
f.File = f_r
err := f.Delete()
if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"file": f.File})

View file

@ -36,7 +36,6 @@ import (
"time"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
@ -140,8 +139,8 @@ func (f *File) Register(fileHeader *multipart.FileHeader, scenarioID uint) error
// Create association to scenario
db := database.GetDB()
var so scenario.Scenario
err = so.ByID(scenarioID)
var so database.Scenario
err = db.Find(&so, scenarioID).Error
if err != nil {
return err
}
@ -219,8 +218,8 @@ func (f *File) Delete() error {
db := database.GetDB()
// remove association between file and scenario
var so scenario.Scenario
err := so.ByID(f.ScenarioID)
var so database.Scenario
err := db.Find(&so, f.ScenarioID).Error
if err != nil {
return err
}
@ -248,3 +247,38 @@ func (f *File) Delete() error {
return err
}
func (f *File) Duplicate(scenarioID uint) error {
var dup File
dup.Name = f.Name
dup.Key = f.Key
dup.Type = f.Type
dup.Size = f.Size
dup.Date = f.Date
dup.ScenarioID = scenarioID
dup.FileData = f.FileData
dup.ImageHeight = f.ImageHeight
dup.ImageWidth = f.ImageWidth
// file duplicate will point to the same data blob in the DB (SQL or postgres)
// Add duplicate File object with parameters to DB
err := dup.save()
if err != nil {
return err
}
// Create association of duplicate file to scenario ID of duplicate file
db := database.GetDB()
var so database.Scenario
err = db.Find(&so, scenarioID).Error
if err != nil {
return err
}
err = db.Model(&so).Association("Files").Append(&dup).Error
return err
}

View file

@ -1,61 +0,0 @@
/** File package, middleware.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package file
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"github.com/gin-gonic/gin"
)
func CheckPermissions(c *gin.Context, operation database.CRUD) (bool, File) {
var f File
err := database.ValidateRole(c, database.ModelFile, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of file failed): %v", err.Error()))
return false, f
}
fileID, err := helper.GetIDOfElement(c, "fileID", "path", -1)
if err != nil {
return false, f
}
err = f.ByID(uint(fileID))
if helper.DBError(c, err) {
return false, f
}
if operation != database.Read {
// check access to scenario only if operation is not Read (=download) of file
ok, _ := scenario.CheckPermissions(c, operation, "body", int(f.ScenarioID))
if !ok {
return false, f
}
}
return true, f
}

View file

@ -53,10 +53,10 @@ type ScenarioRequest struct {
func addScenario() (scenarioID uint) {
// authenticate as admin
token, _ := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, _ := helper.AuthenticateForTest(router, database.AdminCredentials)
// authenticate as normal user
token, _ = helper.AuthenticateForTest(router, helper.UserACredentials)
token, _ = helper.AuthenticateForTest(router, database.UserACredentials)
// POST $newScenario
newScenario := ScenarioRequest{
@ -103,14 +103,14 @@ func TestMain(m *testing.M) {
func TestAddFile(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// using the respective endpoints of the API
scenarioID := addScenario()
// authenticate as userB who has no access to the elements in the DB
token, err := helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err := helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
emptyBuf := &bytes.Buffer{}
@ -123,7 +123,7 @@ func TestAddFile(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal userA
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to POST without a scenario ID
@ -189,14 +189,14 @@ func TestUpdateFile(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// using the respective endpoints of the API
scenarioID := addScenario()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// create a testfile.txt in local folder
@ -236,7 +236,7 @@ func TestUpdateFile(t *testing.T) {
assert.NoError(t, err)
// authenticate as userB who has no access to the elements in the DB
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
emptyBuf := &bytes.Buffer{}
@ -249,7 +249,7 @@ func TestUpdateFile(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as guest user C
token, err = helper.AuthenticateForTest(router, helper.GuestCredentials)
token, err = helper.AuthenticateForTest(router, database.GuestCredentials)
assert.NoError(t, err)
// try to PUT as guest
@ -261,7 +261,7 @@ func TestUpdateFile(t *testing.T) {
// Prepare update
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to PUT with empty body
@ -318,14 +318,14 @@ func TestUpdateFile(t *testing.T) {
func TestDeleteFile(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// using the respective endpoints of the API
scenarioID := addScenario()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// create a testfile.txt in local folder
@ -385,7 +385,7 @@ func TestDeleteFile(t *testing.T) {
assert.NoError(t, err)
// authenticate as userB who has no access to the elements in the DB
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to DELETE file from scenario to which userB has no access
@ -396,7 +396,7 @@ func TestDeleteFile(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all files returned for scenario
@ -412,7 +412,7 @@ func TestDeleteFile(t *testing.T) {
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
// authenticate as guest user C
token, err = helper.AuthenticateForTest(router, helper.GuestCredentials)
token, err = helper.AuthenticateForTest(router, database.GuestCredentials)
assert.NoError(t, err)
// try to DELETE file of scenario as guest
@ -423,7 +423,7 @@ func TestDeleteFile(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Delete the added file 1
@ -450,14 +450,14 @@ func TestGetAllFilesOfScenario(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// using the respective endpoints of the API
scenarioID := addScenario()
// authenticate as userB who has no access to the elements in the DB
token, err := helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err := helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to get all files for scenario to which userB has not access
@ -468,7 +468,7 @@ func TestGetAllFilesOfScenario(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal userA
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
//try to get all files with missing scenario ID; should return a bad request error

View file

@ -86,7 +86,7 @@ func getICs(c *gin.Context) {
// @Security Bearer
func addIC(c *gin.Context) {
ok, _ := CheckPermissions(c, database.ModelInfrastructureComponent, database.Create, false)
ok, _ := database.CheckICPermissions(c, database.ModelInfrastructureComponent, database.Create, false)
if !ok {
return
}
@ -147,11 +147,14 @@ func addIC(c *gin.Context) {
// @Security Bearer
func updateIC(c *gin.Context) {
ok, oldIC := CheckPermissions(c, database.ModelInfrastructureComponent, database.Update, true)
ok, oldIC_r := database.CheckICPermissions(c, database.ModelInfrastructureComponent, database.Update, true)
if !ok {
return
}
var oldIC InfrastructureComponent
oldIC.InfrastructureComponent = oldIC_r
if oldIC.ManagedExternally {
helper.BadRequestError(c, "Cannot update externally managed component via API")
return
@ -196,12 +199,12 @@ func updateIC(c *gin.Context) {
// @Security Bearer
func getIC(c *gin.Context) {
ok, s := CheckPermissions(c, database.ModelInfrastructureComponent, database.Read, true)
ok, s := database.CheckICPermissions(c, database.ModelInfrastructureComponent, database.Read, true)
if !ok {
return
}
c.JSON(http.StatusOK, gin.H{"ic": s.InfrastructureComponent})
c.JSON(http.StatusOK, gin.H{"ic": s})
}
// deleteIC godoc
@ -219,11 +222,14 @@ func getIC(c *gin.Context) {
// @Security Bearer
func deleteIC(c *gin.Context) {
ok, s := CheckPermissions(c, database.ModelInfrastructureComponent, database.Delete, true)
ok, s_r := database.CheckICPermissions(c, database.ModelInfrastructureComponent, database.Delete, true)
if !ok {
return
}
var s InfrastructureComponent
s.InfrastructureComponent = s_r
// Check if IC is managed externally
if s.ManagedExternally {
// if so: refuse deletion
@ -258,11 +264,14 @@ func deleteIC(c *gin.Context) {
// @Security Bearer
func getConfigsOfIC(c *gin.Context) {
ok, s := CheckPermissions(c, database.ModelInfrastructureComponent, database.Read, true)
ok, s_r := database.CheckICPermissions(c, database.ModelInfrastructureComponent, database.Read, true)
if !ok {
return
}
var s InfrastructureComponent
s.InfrastructureComponent = s_r
// get all associated configurations
allConfigs, _, err := s.getConfigs()
if !helper.DBError(c, err) {
@ -287,7 +296,7 @@ func getConfigsOfIC(c *gin.Context) {
// @Security Bearer
func sendActionToIC(c *gin.Context) {
ok, s := CheckPermissions(c, database.ModelInfrastructureComponentAction, database.Update, true)
ok, s := database.CheckICPermissions(c, database.ModelInfrastructureComponentAction, database.Update, true)
if !ok {
return
}

View file

@ -1,55 +0,0 @@
/** InfrastructureComponent package, middleware.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package infrastructure_component
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"github.com/gin-gonic/gin"
)
func CheckPermissions(c *gin.Context, modeltype database.ModelName, operation database.CRUD, hasID bool) (bool, InfrastructureComponent) {
var s InfrastructureComponent
err := database.ValidateRole(c, modeltype, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of infrastructure component failed): %v", err.Error()))
return false, s
}
if hasID {
// Get the ID of the infrastructure component from the context
ICID, err := helper.GetIDOfElement(c, "ICID", "path", -1)
if err != nil {
return false, s
}
err = s.ByID(uint(ICID))
if helper.DBError(c, err) {
return false, s
}
}
return true, s
}

View file

@ -148,10 +148,10 @@ func TestMain(m *testing.M) {
func TestAddICAsAdmin(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// try to POST with non JSON body
@ -213,10 +213,10 @@ func TestAddICAsAdmin(t *testing.T) {
func TestAddICAsUser(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST ic/ $newIC
@ -232,10 +232,10 @@ func TestAddICAsUser(t *testing.T) {
func TestUpdateICAsAdmin(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// test POST ic/ $newIC
@ -321,10 +321,10 @@ func TestUpdateICAsAdmin(t *testing.T) {
func TestUpdateICAsUser(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// test POST ic/ $newIC
@ -338,7 +338,7 @@ func TestUpdateICAsUser(t *testing.T) {
assert.NoError(t, err)
// authenticate as user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Test PUT IC
@ -354,10 +354,10 @@ func TestUpdateICAsUser(t *testing.T) {
func TestDeleteICAsAdmin(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// test POST ic/ $newIC
@ -431,10 +431,10 @@ func TestDeleteICAsAdmin(t *testing.T) {
func TestDeleteICAsUser(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// test POST ic/ $newIC
@ -448,7 +448,7 @@ func TestDeleteICAsUser(t *testing.T) {
assert.NoError(t, err)
// authenticate as user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Test DELETE ICs
@ -463,10 +463,10 @@ func TestDeleteICAsUser(t *testing.T) {
func TestGetAllICs(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// get the length of the GET all ICs response for user
@ -495,7 +495,7 @@ func TestGetAllICs(t *testing.T) {
assert.Equal(t, finalNumber, initialNumber+2)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// get the length of the GET all ICs response again
@ -509,10 +509,10 @@ func TestGetAllICs(t *testing.T) {
func TestGetConfigsOfIC(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// test POST ic/ $newICA
@ -534,7 +534,7 @@ func TestGetConfigsOfIC(t *testing.T) {
assert.Equal(t, 0, numberOfConfigs)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test GET ic/ID/configs
@ -556,10 +556,10 @@ func TestGetConfigsOfIC(t *testing.T) {
func TestSendActionToIC(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// test POST ic/ $newICA
@ -605,10 +605,10 @@ func TestCreateUpdateViaAMQPRecv(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// fake an IC update message
@ -679,10 +679,10 @@ func TestDeleteICViaAMQPRecv(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// fake an IC update message

View file

@ -151,7 +151,7 @@ func AddTestData(cfg *config.Config, router *gin.Engine) (*bytes.Buffer, error)
return nil, nil
}
var Admin = helper.Credentials{
var Admin = database.Credentials{
Username: adminName,
Password: adminPW,
}

View file

@ -29,7 +29,6 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/file"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"github.com/gin-gonic/gin"
)
@ -57,7 +56,7 @@ func RegisterResultEndpoints(r *gin.RouterGroup) {
// @Security Bearer
func getResults(c *gin.Context) {
ok, sco := scenario.CheckPermissions(c, database.Read, "query", -1)
ok, sco := database.CheckScenarioPermissions(c, database.Read, "query", -1)
if !ok {
return
}
@ -103,7 +102,7 @@ func addResult(c *gin.Context) {
newResult := req.createResult()
// Check if user is allowed to modify scenario specified in request
ok, _ := scenario.CheckPermissions(c, database.Update, "body", int(newResult.ScenarioID))
ok, _ := database.CheckScenarioPermissions(c, database.Update, "body", int(newResult.ScenarioID))
if !ok {
return
}
@ -133,11 +132,14 @@ func addResult(c *gin.Context) {
// @Security Bearer
func updateResult(c *gin.Context) {
ok, oldResult := checkPermissions(c, database.Update, "path", -1)
ok, oldResult_r := database.CheckResultPermissions(c, database.Update, "path", -1)
if !ok {
return
}
var oldResult Result
oldResult.Result = oldResult_r
var req updateResultRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.BadRequestError(c, err.Error())
@ -175,12 +177,12 @@ func updateResult(c *gin.Context) {
// @Security Bearer
func getResult(c *gin.Context) {
ok, result := checkPermissions(c, database.Read, "path", -1)
ok, result := database.CheckResultPermissions(c, database.Read, "path", -1)
if !ok {
return
}
c.JSON(http.StatusOK, gin.H{"result": result.Result})
c.JSON(http.StatusOK, gin.H{"result": result})
}
// deleteResult godoc
@ -197,13 +199,16 @@ func getResult(c *gin.Context) {
// @Router /results/{resultID} [delete]
// @Security Bearer
func deleteResult(c *gin.Context) {
ok, result := checkPermissions(c, database.Delete, "path", -1)
ok, result_r := database.CheckResultPermissions(c, database.Delete, "path", -1)
if !ok {
return
}
var result Result
result.Result = result_r
// Check if user is allowed to modify scenario associated with result
ok, _ = scenario.CheckPermissions(c, database.Update, "body", int(result.ScenarioID))
ok, _ = database.CheckScenarioPermissions(c, database.Update, "body", int(result.ScenarioID))
if !ok {
return
}
@ -240,13 +245,16 @@ func deleteResult(c *gin.Context) {
// @Router /results/{resultID}/file [post]
// @Security Bearer
func addResultFile(c *gin.Context) {
ok, result := checkPermissions(c, database.Update, "path", -1)
ok, result_r := database.CheckResultPermissions(c, database.Update, "path", -1)
if !ok {
return
}
var result Result
result.Result = result_r
// Check if user is allowed to modify scenario associated with result
ok, sco := scenario.CheckPermissions(c, database.Update, "body", int(result.ScenarioID))
ok, sco := database.CheckScenarioPermissions(c, database.Update, "body", int(result.ScenarioID))
if !ok {
return
}
@ -290,18 +298,24 @@ func addResultFile(c *gin.Context) {
func deleteResultFile(c *gin.Context) {
// check access
ok, result := checkPermissions(c, database.Update, "path", -1)
ok, result_r := database.CheckResultPermissions(c, database.Update, "path", -1)
if !ok {
return
}
ok, f := file.CheckPermissions(c, database.Delete)
var result Result
result.Result = result_r
ok, f_r := database.CheckFilePermissions(c, database.Delete)
if !ok {
return
}
var f file.File
f.File = f_r
// Check if user is allowed to modify scenario associated with result
ok, _ = scenario.CheckPermissions(c, database.Update, "body", int(result.ScenarioID))
ok, _ = database.CheckScenarioPermissions(c, database.Update, "body", int(result.ScenarioID))
if !ok {
return
}

View file

@ -25,7 +25,6 @@ package result
import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/file"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"log"
)
@ -50,8 +49,8 @@ func (r *Result) ByID(id uint) error {
func (r *Result) addToScenario() error {
db := database.GetDB()
var sco scenario.Scenario
err := sco.ByID(r.ScenarioID)
var sco database.Scenario
err := db.Find(&sco, r.ScenarioID).Error
if err != nil {
return err
}
@ -84,8 +83,8 @@ func (r *Result) update(modifiedResult Result) error {
func (r *Result) delete() error {
db := database.GetDB()
var sco scenario.Scenario
err := sco.ByID(r.ScenarioID)
var sco database.Scenario
err := db.Find(&sco, r.ScenarioID).Error
if err != nil {
return err
}

View file

@ -1,59 +0,0 @@
/** Result package, middleware.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package result
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"github.com/gin-gonic/gin"
)
func checkPermissions(c *gin.Context, operation database.CRUD, resultIDSource string, resultIDBody int) (bool, Result) {
var result Result
err := database.ValidateRole(c, database.ModelResult, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation failed): %v", err.Error()))
return false, result
}
resultID, err := helper.GetIDOfElement(c, "resultID", resultIDSource, resultIDBody)
if err != nil {
return false, result
}
err = result.ByID(uint(resultID))
if helper.DBError(c, err) {
return false, result
}
ok, _ := scenario.CheckPermissions(c, operation, "body", int(result.ScenarioID))
if !ok {
return false, result
}
return true, result
}

View file

@ -70,10 +70,10 @@ var newResult = ResultRequest{
func addScenario() (scenarioID uint) {
// authenticate as admin
token, _ := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, _ := helper.AuthenticateForTest(router, database.AdminCredentials)
// authenticate as normal user
token, _ = helper.AuthenticateForTest(router, helper.UserACredentials)
token, _ = helper.AuthenticateForTest(router, database.UserACredentials)
// POST $newScenario
newScenario := ScenarioRequest{
@ -123,14 +123,14 @@ func TestGetAllResultsOfScenario(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario
scenarioID := addScenario()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST newResult
@ -152,7 +152,7 @@ func TestGetAllResultsOfScenario(t *testing.T) {
assert.Equal(t, 1, NumberOfConfigs)
// authenticate as normal userB who has no access to scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to get results without access
@ -168,7 +168,7 @@ func TestAddGetUpdateDeleteResult(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario
@ -178,7 +178,7 @@ func TestAddGetUpdateDeleteResult(t *testing.T) {
newResult.ScenarioID = scenarioID
newResult.ConfigSnapshots = confSnapshots
// authenticate as normal userB who has no access to new scenario
token, err := helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err := helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to POST with no access
@ -189,7 +189,7 @@ func TestAddGetUpdateDeleteResult(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to POST non JSON body
@ -234,7 +234,7 @@ func TestAddGetUpdateDeleteResult(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// Try to GET the newResult with no access
@ -259,7 +259,7 @@ func TestAddGetUpdateDeleteResult(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as guest user who has access to result
token, err = helper.AuthenticateForTest(router, helper.GuestCredentials)
token, err = helper.AuthenticateForTest(router, database.GuestCredentials)
assert.NoError(t, err)
// try to PUT as guest
@ -270,7 +270,7 @@ func TestAddGetUpdateDeleteResult(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to PUT a non JSON body
@ -300,7 +300,7 @@ func TestAddGetUpdateDeleteResult(t *testing.T) {
newResult.Description = updatedResult.Description
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to DELETE with no access
@ -311,7 +311,7 @@ func TestAddGetUpdateDeleteResult(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all the results returned for scenario
@ -341,7 +341,7 @@ func TestAddGetUpdateDeleteResult(t *testing.T) {
func TestAddDeleteResultFile(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario
@ -352,7 +352,7 @@ func TestAddDeleteResultFile(t *testing.T) {
newResult.ScenarioID = scenarioID
newResult.ConfigSnapshots = confSnapshots
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST newResult

View file

@ -22,14 +22,10 @@
package scenario
import (
"net/http"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"github.com/gin-gonic/gin"
"net/http"
)
func RegisterScenarioEndpoints(r *gin.RouterGroup) {
@ -60,15 +56,15 @@ func getScenarios(c *gin.Context) {
// ATTENTION: do not use c.GetInt (common.UserIDCtx) since userID is of type uint and not int
userID, _ := c.Get(database.UserIDCtx)
var u user.User
err := u.ByID(userID.(uint))
db := database.GetDB()
var u database.User
err := db.Find(&u, userID.(uint)).Error
if helper.DBError(c, err) {
return
}
// get all scenarios for the user who issues the request
db := database.GetDB()
var scenarios []database.Scenario
if u.Role == "Admin" { // Admin can see all scenarios
err = db.Order("ID asc").Find(&scenarios).Error
@ -102,16 +98,16 @@ func getScenarios(c *gin.Context) {
// @Security Bearer
func addScenario(c *gin.Context) {
ok, _ := CheckPermissions(c, database.Create, "none", -1)
ok, _ := database.CheckScenarioPermissions(c, database.Create, "none", -1)
if !ok {
return
}
// ATTENTION: do not use c.GetInt (common.UserIDCtx) since userID is of type uint and not int
userID, _ := c.Get(database.UserIDCtx)
var u user.User
err := u.ByID(userID.(uint))
db := database.GetDB()
var u database.User
err := db.Find(&u, userID.(uint)).Error
if helper.DBError(c, err) {
return
}
@ -138,7 +134,7 @@ func addScenario(c *gin.Context) {
}
// add user to new scenario
err = newScenario.addUser(&(u.User))
err = newScenario.addUser(&(u))
if helper.DBError(c, err) {
return
}
@ -163,11 +159,14 @@ func addScenario(c *gin.Context) {
// @Security Bearer
func updateScenario(c *gin.Context) {
ok, oldScenario := CheckPermissions(c, database.Update, "path", -1)
ok, oldScenario_r := database.CheckScenarioPermissions(c, database.Update, "path", -1)
if !ok {
return
}
var oldScenario Scenario
oldScenario.Scenario = oldScenario_r
// Bind the (context) with the updateScenarioRequest struct
var req updateScenarioRequest
if err := c.ShouldBindJSON(&req); err != nil {
@ -208,13 +207,13 @@ func updateScenario(c *gin.Context) {
// @Security Bearer
func getScenario(c *gin.Context) {
ok, so := CheckPermissions(c, database.Read, "path", -1)
ok, so := database.CheckScenarioPermissions(c, database.Read, "path", -1)
if !ok {
return
}
// TODO return list of configIDs, dashboardIDs and userIDs per scenario
c.JSON(http.StatusOK, gin.H{"scenario": so.Scenario})
c.JSON(http.StatusOK, gin.H{"scenario": so})
}
// deleteScenario godoc
@ -231,11 +230,14 @@ func getScenario(c *gin.Context) {
// @Security Bearer
func deleteScenario(c *gin.Context) {
ok, so := CheckPermissions(c, database.Delete, "path", -1)
ok, so_r := database.CheckScenarioPermissions(c, database.Delete, "path", -1)
if !ok {
return
}
var so Scenario
so.Scenario = so_r
err := so.delete()
if helper.DBError(c, err) {
return
@ -258,11 +260,14 @@ func deleteScenario(c *gin.Context) {
// @Security Bearer
func getUsersOfScenario(c *gin.Context) {
ok, so := CheckPermissions(c, database.Read, "path", -1)
ok, so_r := database.CheckScenarioPermissions(c, database.Read, "path", -1)
if !ok {
return
}
var so Scenario
so.Scenario = so_r
// Find all users of scenario
allUsers, _, err := so.getUsers()
if helper.DBError(c, err) {
@ -287,15 +292,18 @@ func getUsersOfScenario(c *gin.Context) {
// @Security Bearer
func addUserToScenario(c *gin.Context) {
ok, so := CheckPermissions(c, database.Update, "path", -1)
ok, so_r := database.CheckScenarioPermissions(c, database.Update, "path", -1)
if !ok {
return
}
username := c.Request.URL.Query().Get("username")
var so Scenario
so.Scenario = so_r
var u user.User
err := u.ByUsername(username)
username := c.Request.URL.Query().Get("username")
var u database.User
db := database.GetDB()
err := db.Find(&u, "Username = ?", username).Error
if helper.DBError(c, err) {
return
}
@ -305,12 +313,12 @@ func addUserToScenario(c *gin.Context) {
return
}
err = so.addUser(&(u.User))
err = so.addUser(&(u))
if helper.DBError(c, err) {
return
}
c.JSON(http.StatusOK, gin.H{"user": u.User})
c.JSON(http.StatusOK, gin.H{"user": u})
}
// deleteUserFromScenario godoc
@ -328,15 +336,18 @@ func addUserToScenario(c *gin.Context) {
// @Security Bearer
func deleteUserFromScenario(c *gin.Context) {
ok, so := CheckPermissions(c, database.Update, "path", -1)
ok, so_r := database.CheckScenarioPermissions(c, database.Update, "path", -1)
if !ok {
return
}
username := c.Request.URL.Query().Get("username")
var so Scenario
so.Scenario = so_r
var u user.User
err := u.ByUsername(username)
username := c.Request.URL.Query().Get("username")
var u database.User
db := database.GetDB()
err := db.Find(&u, "Username = ?", username).Error
if helper.DBError(c, err) {
return
}
@ -346,5 +357,5 @@ func deleteUserFromScenario(c *gin.Context) {
return
}
c.JSON(http.StatusOK, gin.H{"user": u.User})
c.JSON(http.StatusOK, gin.H{"user": u})
}

View file

@ -24,8 +24,13 @@ package scenario
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
component_configuration "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/file"
infrastructure_component "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component"
"github.com/jinzhu/gorm"
"log"
"time"
)
type Scenario struct {
@ -82,8 +87,8 @@ func (s *Scenario) addUser(u *database.User) error {
func (s *Scenario) deleteUser(username string) error {
db := database.GetDB()
var deletedUser user.User
err := deletedUser.ByUsername(username)
var deletedUser database.User
err := db.Find(&deletedUser, "Username = ?", username).Error
if err != nil {
return err
}
@ -92,18 +97,18 @@ func (s *Scenario) deleteUser(username string) error {
if no_users > 1 {
// remove user from scenario
err = db.Model(s).Association("Users").Delete(&deletedUser.User).Error
err = db.Model(s).Association("Users").Delete(&deletedUser).Error
if err != nil {
return err
}
// remove scenario from user
err = db.Model(&deletedUser.User).Association("Scenarios").Delete(s).Error
err = db.Model(&deletedUser).Association("Scenarios").Delete(s).Error
if err != nil {
return err
}
} else {
// There is only one associated user
var remainingUser user.User
var remainingUser database.User
err = db.Model(s).Related(&remainingUser, "Users").Error
if remainingUser.Username == username {
// if the remaining user is the one to be deleted
@ -152,32 +157,160 @@ func (s *Scenario) delete() error {
return nil
}
func (s *Scenario) checkAccess(userID uint, operation database.CRUD) bool {
func (s *Scenario) DuplicateScenarioForUser(user *database.User) <-chan error {
errs := make(chan error, 1)
go func() {
// get all component configs of the scenario
db := database.GetDB()
var configs []database.ComponentConfiguration
err := db.Order("ID asc").Model(s).Related(&configs, "ComponentConfigurations").Error
if err != nil {
log.Printf("Warning: scenario to duplicate (id=%d) has no component configurations", s.ID)
}
// iterate over component configs to check for ICs to duplicate
duplicatedICuuids := make(map[uint]string) // key: original icID; value: UUID of duplicate
var externalUUIDs []string // external ICs to wait for
for _, config := range configs {
icID := config.ICID
if duplicatedICuuids[icID] != "" { // this IC was already added
continue
}
var ic infrastructure_component.InfrastructureComponent
err = ic.ByID(icID)
if err != nil {
errs <- fmt.Errorf("Cannot find IC with id %d in DB, will not duplicate for User %s: %s", icID, user.Username, err)
continue
}
// create new kubernetes simulator OR use existing IC
if ic.Category == "simulator" && ic.Type == "kubernetes" {
duplicateUUID, err := ic.RequestICcreateAMQPsimpleManager(user.Username)
if err != nil {
errs <- fmt.Errorf("Duplication of IC (id=%d) unsuccessful, err: %s", icID, err)
continue
}
duplicatedICuuids[ic.ID] = duplicateUUID
externalUUIDs = append(externalUUIDs, duplicateUUID)
} else { // use existing IC
duplicatedICuuids[ic.ID] = ""
err = nil
}
}
// copy scenario after all new external ICs are in DB
icsToWaitFor := len(externalUUIDs)
//var duplicatedScenario database.Scenario
var timeout = 20 // seconds
for i := 0; i < timeout; i++ {
// duplicate scenario after all duplicated ICs have been found in the DB
if icsToWaitFor == 0 {
err := s.duplicateScenario(duplicatedICuuids, user)
if err != nil {
errs <- fmt.Errorf("duplicate scenario %v fails with error %v", s.Name, err.Error())
}
close(errs)
return
} else {
time.Sleep(1 * time.Second)
}
// check for new ICs with previously created UUIDs
for _, uuid := range externalUUIDs {
if uuid == "" {
continue
}
log.Printf("Looking for duplicated IC with UUID %s", uuid)
var duplicatedIC database.InfrastructureComponent
err = db.Find(&duplicatedIC, "UUID = ?", uuid).Error
if err != nil {
errs <- fmt.Errorf("Error looking up duplicated IC: %s", err)
} else {
icsToWaitFor--
uuid = ""
}
}
}
errs <- fmt.Errorf("ALERT! Timed out while waiting for IC duplication, scenario not properly duplicated")
close(errs)
}()
return errs
}
func (s *Scenario) duplicateScenario(icIds map[uint]string, user *database.User) error {
db := database.GetDB()
u := database.User{}
err := db.Find(&u, userID).Error
var duplicateSo Scenario
duplicateSo.Name = s.Name + ` ` + user.Username
duplicateSo.StartParameters.RawMessage = s.StartParameters.RawMessage
err := duplicateSo.save()
if err != nil {
return false
log.Printf("Could not create duplicate of scenario %d", s.ID)
return err
}
if u.Role == "Admin" {
return true
}
scenarioUser := database.User{}
err = db.Order("ID asc").Model(s).Where("ID = ?", userID).Related(&scenarioUser, "Users").Error
// associate user to new scenario
err = duplicateSo.addUser(user)
if err != nil {
return false
log.Printf("Could not associate User %s to scenario %d", user.Username, duplicateSo.ID)
}
log.Println("Associated user to duplicated scenario")
// duplicate files
var files []file.File
err = db.Order("ID asc").Model(s).Related(&files, "Files").Error
if err != nil {
log.Printf("error getting files for scenario %d", s.ID)
}
for _, f := range files {
err = f.Duplicate(duplicateSo.ID)
if err != nil {
log.Print("error creating duplicate file %d: %s", f.ID, err)
continue
}
}
if !scenarioUser.Active {
return false
} else if s.IsLocked && operation != database.Read {
return false
var configs []component_configuration.ComponentConfiguration
// map existing signal IDs to duplicated signal IDs for widget duplication
signalMap := make(map[uint]uint)
err = db.Order("ID asc").Model(s).Related(&configs, "ComponentConfigurations").Error
if err == nil {
for _, c := range configs {
err = c.Duplicate(duplicateSo.ID, icIds, &signalMap)
//err = duplicateComponentConfig(&c, duplicateSo, icIds, userName, &signalMap)
if err != nil {
log.Printf("Error duplicating component config %d: %s", c.ID, err)
continue
}
}
} else {
return true
return err
}
var dabs []dashboard.Dashboard
err = db.Order("ID asc").Model(s).Related(&dabs, "Dashboards").Error
if err != nil {
log.Printf("Error getting dashboards for scenario %d: %s", s.ID, err)
}
for _, dab := range dabs {
err = dab.Duplicate(duplicateSo.ID, signalMap)
if err != nil {
log.Printf("Error duplicating dashboard %d: %s", dab.ID, err)
continue
}
}
return err
}

View file

@ -1,64 +0,0 @@
/** Scenario package, middleware.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package scenario
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
)
func CheckPermissions(c *gin.Context, operation database.CRUD, scenarioIDsource string, scenarioIDbody int) (bool, Scenario) {
var so Scenario
err := database.ValidateRole(c, database.ModelScenario, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of scenario failed): %v", err))
return false, so
}
if operation == database.Create || (operation == database.Read && scenarioIDsource == "none") {
return true, so
}
scenarioID, err := helper.GetIDOfElement(c, "scenarioID", scenarioIDsource, scenarioIDbody)
if err != nil {
return false, so
}
userID, _ := c.Get(database.UserIDCtx)
err = so.ByID(uint(scenarioID))
if helper.DBError(c, err) {
return false, so
}
if so.checkAccess(userID.(uint), operation) == false {
helper.UnprocessableEntityError(c, "Access denied (user has no access or scenario is locked).")
return false, so
}
return true, so
}

View file

@ -91,10 +91,10 @@ func TestAddScenario(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to POST with non JSON body
@ -147,7 +147,7 @@ func TestAddScenario(t *testing.T) {
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
// authenticate as guest user
token, err = helper.AuthenticateForTest(router, helper.GuestCredentials)
token, err = helper.AuthenticateForTest(router, database.GuestCredentials)
assert.NoError(t, err)
// try to add scenario as guest user
@ -158,7 +158,7 @@ func TestAddScenario(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as userB who has no access to the added scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to GET a scenario to which user B has no access
@ -169,7 +169,7 @@ func TestAddScenario(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as admin user who has no access to everything
token, err = helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err = helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// try to GET a scenario that is not created by admin user; should work anyway
@ -183,10 +183,10 @@ func TestUpdateScenario(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario
@ -254,7 +254,7 @@ func TestUpdateScenario(t *testing.T) {
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
// authenticate as admin user who has no access to everything
token, err = helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err = helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// changed locked state of scenario as admin user (should work)
@ -290,7 +290,7 @@ func TestUpdateScenario(t *testing.T) {
assert.NoError(t, err)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Get the updatedScenario
@ -316,10 +316,10 @@ func TestGetAllScenariosAsAdmin(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err := helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// get the length of the GET all scenarios response for admin
@ -328,7 +328,7 @@ func TestGetAllScenariosAsAdmin(t *testing.T) {
assert.NoError(t, err)
// authenticate as normal userB
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario1
@ -338,7 +338,7 @@ func TestGetAllScenariosAsAdmin(t *testing.T) {
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as normal userA
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario2
@ -348,7 +348,7 @@ func TestGetAllScenariosAsAdmin(t *testing.T) {
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as admin
token, err = helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err = helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// get the length of the GET all scenarios response again
@ -363,10 +363,10 @@ func TestGetAllScenariosAsUser(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal userB
token, err := helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err := helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// get the length of the GET all scenarios response for userB
@ -381,7 +381,7 @@ func TestGetAllScenariosAsUser(t *testing.T) {
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as normal userA
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario1
@ -391,7 +391,7 @@ func TestGetAllScenariosAsUser(t *testing.T) {
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as normal userB
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// get the length of the GET all scenarios response again
@ -406,10 +406,10 @@ func TestDeleteScenario(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario
@ -429,7 +429,7 @@ func TestDeleteScenario(t *testing.T) {
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as guest user
token, err = helper.AuthenticateForTest(router, helper.GuestCredentials)
token, err = helper.AuthenticateForTest(router, database.GuestCredentials)
assert.NoError(t, err)
// try to delete scenario as guest
@ -440,7 +440,7 @@ func TestDeleteScenario(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all the scenarios returned for userA
@ -470,10 +470,10 @@ func TestAddUserToScenario(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario
@ -487,7 +487,7 @@ func TestAddUserToScenario(t *testing.T) {
assert.NoError(t, err)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to add new user User_C to scenario as userB
@ -505,7 +505,7 @@ func TestAddUserToScenario(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all the users returned for newScenario
@ -522,9 +522,9 @@ func TestAddUserToScenario(t *testing.T) {
// Compare resp to userB
userB := UserRequest{
Username: helper.UserB.Username,
Mail: helper.UserB.Mail,
Role: helper.UserB.Role,
Username: database.UserB.Username,
Mail: database.UserB.Mail,
Role: database.UserB.Role,
}
err = helper.CompareResponse(resp, helper.KeyModels{"user": userB})
assert.NoError(t, err)
@ -547,10 +547,10 @@ func TestGetAllUsersOfScenario(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario
@ -564,7 +564,7 @@ func TestGetAllUsersOfScenario(t *testing.T) {
assert.NoError(t, err)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to get all users of new scenario with userB
@ -575,7 +575,7 @@ func TestGetAllUsersOfScenario(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all the users returned for newScenario
@ -597,7 +597,7 @@ func TestGetAllUsersOfScenario(t *testing.T) {
assert.Equal(t, finalNumber, initialNumber+1)
// authenticate as admin
token, err = helper.AuthenticateForTest(router, helper.AdminCredentials)
token, err = helper.AuthenticateForTest(router, database.AdminCredentials)
assert.NoError(t, err)
// set userB as inactive
@ -608,7 +608,7 @@ func TestGetAllUsersOfScenario(t *testing.T) {
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count AGAIN the number of all the users returned for newScenario
@ -622,10 +622,10 @@ func TestRemoveUserFromScenario(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST scenarios/ $newScenario
@ -645,7 +645,7 @@ func TestRemoveUserFromScenario(t *testing.T) {
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to delete userC from new scenario
@ -656,7 +656,7 @@ func TestRemoveUserFromScenario(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all the users returned for newScenario
@ -673,9 +673,9 @@ func TestRemoveUserFromScenario(t *testing.T) {
// Compare DELETE's response with UserC's data
userC := UserRequest{
Username: helper.UserC.Username,
Mail: helper.UserC.Mail,
Role: helper.UserC.Role,
Username: database.UserC.Username,
Mail: database.UserC.Mail,
Role: database.UserC.Role,
}
err = helper.CompareResponse(resp, helper.KeyModels{"user": userC})
assert.NoError(t, err)
@ -708,3 +708,13 @@ func TestRemoveUserFromScenario(t *testing.T) {
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
}
func TestDuplicateScenarioForUser(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, database.AddTestUsers())
// TODO test duplicate scenario for user function here!!
}

View file

@ -29,7 +29,6 @@ import (
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
component_configuration "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
)
func RegisterSignalEndpoints(r *gin.RouterGroup) {
@ -55,7 +54,7 @@ func RegisterSignalEndpoints(r *gin.RouterGroup) {
// @Security Bearer
func getSignals(c *gin.Context) {
ok, m := component_configuration.CheckPermissions(c, database.Read, "query", -1)
ok, m := database.CheckComponentConfigPermissions(c, database.Read, "query", -1)
if !ok {
return
}
@ -111,13 +110,13 @@ func addSignal(c *gin.Context) {
// Create the new signal from the request
newSignal := req.createSignal()
ok, _ := component_configuration.CheckPermissions(c, database.Update, "body", int(newSignal.ConfigID))
ok, _ := database.CheckComponentConfigPermissions(c, database.Update, "body", int(newSignal.ConfigID))
if !ok {
return
}
// Add signal to component configuration
err := newSignal.addToConfig()
err := newSignal.AddToConfig()
if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"signal": newSignal.Signal})
}
@ -139,11 +138,14 @@ func addSignal(c *gin.Context) {
// @Router /signals/{signalID} [put]
// @Security Bearer
func updateSignal(c *gin.Context) {
ok, oldSignal := checkPermissions(c, database.Delete)
ok, oldSignal_r := database.CheckSignalPermissions(c, database.Delete)
if !ok {
return
}
var oldSignal Signal
oldSignal.Signal = oldSignal_r
var req updateSignalRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.BadRequestError(c, err.Error())
@ -181,12 +183,12 @@ func updateSignal(c *gin.Context) {
// @Router /signals/{signalID} [get]
// @Security Bearer
func getSignal(c *gin.Context) {
ok, sig := checkPermissions(c, database.Delete)
ok, sig := database.CheckSignalPermissions(c, database.Delete)
if !ok {
return
}
c.JSON(http.StatusOK, gin.H{"signal": sig.Signal})
c.JSON(http.StatusOK, gin.H{"signal": sig})
}
// deleteSignal godoc
@ -204,11 +206,14 @@ func getSignal(c *gin.Context) {
// @Security Bearer
func deleteSignal(c *gin.Context) {
ok, sig := checkPermissions(c, database.Delete)
ok, sig_r := database.CheckSignalPermissions(c, database.Delete)
if !ok {
return
}
var sig Signal
sig.Signal = sig_r
err := sig.delete()
if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"signal": sig.Signal})

View file

@ -23,7 +23,6 @@ package signal
import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
)
type Signal struct {
@ -45,11 +44,11 @@ func (s *Signal) byID(id uint) error {
return nil
}
func (s *Signal) addToConfig() error {
func (s *Signal) AddToConfig() error {
db := database.GetDB()
var err error
var m component_configuration.ComponentConfiguration
err = m.ByID(s.ConfigID)
var m database.ComponentConfiguration
err = db.Find(&m, s.ConfigID).Error
if err != nil {
return err
}
@ -92,8 +91,8 @@ func (s *Signal) delete() error {
db := database.GetDB()
var err error
var m component_configuration.ComponentConfiguration
err = m.ByID(s.ConfigID)
var m database.ComponentConfiguration
err = db.Find(&m, s.ConfigID).Error
if err != nil {
return err
}

View file

@ -1,59 +0,0 @@
/** Signal package, middleware.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package signal
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
)
func checkPermissions(c *gin.Context, operation database.CRUD) (bool, Signal) {
var sig Signal
err := database.ValidateRole(c, database.ModelSignal, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of signal failed): %v", err.Error()))
return false, sig
}
signalID, err := helper.GetIDOfElement(c, "signalID", "path", -1)
if err != nil {
return false, sig
}
err = sig.byID(uint(signalID))
if helper.DBError(c, err) {
return false, sig
}
ok, _ := component_configuration.CheckPermissions(c, operation, "body", int(sig.ConfigID))
if !ok {
return false, sig
}
return true, sig
}

View file

@ -91,7 +91,7 @@ func newFalse() *bool {
func addScenarioAndICAndConfig() (scenarioID uint, ICID uint, configID uint) {
// authenticate as admin
token, _ := helper.AuthenticateForTest(router, helper.AdminCredentials)
token, _ := helper.AuthenticateForTest(router, database.AdminCredentials)
// POST $newICA
newICA := ICRequest{
@ -114,7 +114,7 @@ func addScenarioAndICAndConfig() (scenarioID uint, ICID uint, configID uint) {
newICID, _ := helper.GetResponseID(resp)
// authenticate as normal user
token, _ = helper.AuthenticateForTest(router, helper.UserACredentials)
token, _ = helper.AuthenticateForTest(router, database.UserACredentials)
// POST $newScenario
newScenario := ScenarioRequest{
@ -181,7 +181,7 @@ func TestMain(m *testing.M) {
func TestAddSignal(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
@ -189,12 +189,12 @@ func TestAddSignal(t *testing.T) {
_, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
newSignal1.ConfigID = configID
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to POST to component config without access
@ -205,7 +205,7 @@ func TestAddSignal(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to POST a signal with non JSON body
@ -251,7 +251,7 @@ func TestAddSignal(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// Try to Get the newSignal as user B
@ -265,7 +265,7 @@ func TestAddSignal(t *testing.T) {
func TestUpdateSignal(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
@ -273,7 +273,7 @@ func TestUpdateSignal(t *testing.T) {
_, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST signals/ $newSignal
@ -294,7 +294,7 @@ func TestUpdateSignal(t *testing.T) {
}
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to PUT signal without access
@ -305,7 +305,7 @@ func TestUpdateSignal(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as guest user
token, err = helper.AuthenticateForTest(router, helper.GuestCredentials)
token, err = helper.AuthenticateForTest(router, database.GuestCredentials)
assert.NoError(t, err)
// try to update signal as guest who has access to scenario
@ -316,7 +316,7 @@ func TestUpdateSignal(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to PUT with non JSON body
@ -357,7 +357,7 @@ func TestUpdateSignal(t *testing.T) {
func TestDeleteSignal(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
@ -365,7 +365,7 @@ func TestDeleteSignal(t *testing.T) {
_, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// test POST signals/ $newSignal
@ -386,7 +386,7 @@ func TestDeleteSignal(t *testing.T) {
assert.NoError(t, err)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// Try to DELETE signal with no access
@ -397,7 +397,7 @@ func TestDeleteSignal(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all the input signals returned for component config
@ -443,7 +443,7 @@ func TestDeleteSignal(t *testing.T) {
func TestGetAllInputSignalsOfConfig(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// prepare the content of the DB for testing
// by adding a scenario and a IC to the DB
@ -451,7 +451,7 @@ func TestGetAllInputSignalsOfConfig(t *testing.T) {
_, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all the input signals returned for component config
@ -526,7 +526,7 @@ func TestGetAllInputSignalsOfConfig(t *testing.T) {
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
// authenticate as normal userB who has no access to new scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to get all input signals

View file

@ -23,6 +23,7 @@ package user
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"log"
"net/http"
"strings"
@ -69,7 +70,7 @@ func authenticated(c *gin.Context) {
userID, _ := c.Get(database.UserIDCtx)
var user User
err := user.ByID(userID.(uint))
err := user.byID(userID.(uint))
if helper.DBError(c, err) {
return
}
@ -205,7 +206,7 @@ func authenticateInternal(c *gin.Context) (User, error) {
}
// Find the username in the database
err := myUser.ByUsername(credentials.Username)
err := myUser.byUsername(credentials.Username)
if err != nil {
helper.UnauthorizedError(c, "Unknown username")
return myUser, err
@ -239,7 +240,7 @@ func authenticateExternal(c *gin.Context) (User, error) {
// preferred_username := c.Request.Header.Get("X-Forwarded-Preferred-Username")
// check if user already exists
err := myUser.ByUsername(username)
err := myUser.byUsername(username)
if err != nil {
// this is the first login, create new user
@ -262,7 +263,7 @@ func authenticateExternal(c *gin.Context) (User, error) {
for _, group := range groups {
if groupedArr, ok := configuration.ScenarioGroupMap[group]; ok {
for _, groupedScenario := range groupedArr {
var so database.Scenario
var so scenario.Scenario
err := db.Find(&so, groupedScenario.Scenario).Error
if err != nil {
log.Printf(`Cannot find scenario %s (id=%d) for adding/duplication.
@ -278,9 +279,11 @@ func authenticateExternal(c *gin.Context) (User, error) {
}
if groupedScenario.Duplicate {
if err := <-duplicateScenarioForUser(&so, &myUser.User); err != nil {
if err := <-so.DuplicateScenarioForUser(&myUser.User); err != nil {
return User{}, err
}
} else { // add user to scenario
err = db.Model(&so).Association("Users").Append(&(myUser.User)).Error
if err != nil {

View file

@ -179,7 +179,7 @@ func updateUser(c *gin.Context) {
// Find the user
var oldUser User
err = oldUser.ByID(uint(toBeUpdatedID))
err = oldUser.byID(uint(toBeUpdatedID))
if helper.DBError(c, err) {
return
}
@ -242,7 +242,7 @@ func getUser(c *gin.Context) {
}
var user User
err = user.ByID(uint(id))
err = user.byID(uint(id))
if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"user": user.User})
}
@ -276,7 +276,7 @@ func deleteUser(c *gin.Context) {
}
// Check that the user exist
err = user.ByID(uint(id))
err = user.byID(uint(id))
if helper.DBError(c, err) {
return
}

View file

@ -41,7 +41,7 @@ func NewUser(username, password, mail, role string, active bool) (User, error) {
var newUser User
// Check that the username is NOT taken
err := newUser.ByUsername(username)
err := newUser.byUsername(username)
if err == nil {
return newUser, fmt.Errorf("Username is already taken")
}
@ -83,13 +83,13 @@ func (u *User) remove() error {
return err
}
func (u *User) ByUsername(username string) error {
func (u *User) byUsername(username string) error {
db := database.GetDB()
err := db.Find(u, "Username = ?", username).Error
return err
}
func (u *User) ByID(id uint) error {
func (u *User) byID(id uint) error {
db := database.GetDB()
err := db.Find(u, id).Error
return err

View file

@ -41,7 +41,7 @@ func claimsToContext(c *gin.Context, claims jwt.MapClaims) error {
var user User
err := user.ByID(uint(userID))
err := user.byID(uint(userID))
if err != nil {
return err
}

View file

@ -88,7 +88,7 @@ func TestAuthenticate(t *testing.T) {
router.ServeHTTP(w1, req)
assert.Equalf(t, 401, w1.Code, "Response body: \n%v\n", w1.Body)
malformedCredentials := helper.Credentials{
malformedCredentials := database.Credentials{
Username: "TEST1",
}
// try to authenticate with malformed credentials
@ -126,7 +126,7 @@ func TestAuthenticate(t *testing.T) {
assert.Equal(t, 401, w4.Code, w4.Body)
// authenticate as admin
_, err = helper.AuthenticateForTest(router, helper.Credentials{Username: "admin", Password: adminpw})
_, err = helper.AuthenticateForTest(router, database.Credentials{Username: "admin", Password: adminpw})
assert.NoError(t, err)
}
@ -140,7 +140,7 @@ func TestUserGroups(t *testing.T) {
role := "User"
userGroups := strings.Split("testGroup1,testGroup2", ",")
err := myUser.ByUsername(username)
err := myUser.byUsername(username)
assert.Error(t, err)
myUser, err = NewUser(username, "", email, role, true)
assert.NoError(t, err)
@ -176,7 +176,7 @@ func TestAuthenticateQueryToken(t *testing.T) {
assert.NoError(t, err)
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.Credentials{Username: "admin", Password: adminpw})
token, err := helper.AuthenticateForTest(router, database.Credentials{Username: "admin", Password: adminpw})
assert.NoError(t, err)
w := httptest.NewRecorder()
@ -197,7 +197,7 @@ func TestAddGetUser(t *testing.T) {
assert.NoError(t, err)
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.Credentials{Username: "admin", Password: adminpw})
token, err := helper.AuthenticateForTest(router, database.Credentials{Username: "admin", Password: adminpw})
assert.NoError(t, err)
// try to POST with non JSON body
@ -321,7 +321,7 @@ func TestUsersNotAllowedActions(t *testing.T) {
assert.NoError(t, err)
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.Credentials{Username: "admin", Password: adminpw})
token, err := helper.AuthenticateForTest(router, database.Credentials{Username: "admin", Password: adminpw})
assert.NoError(t, err)
// Add a user
@ -380,7 +380,7 @@ func TestGetAllUsers(t *testing.T) {
assert.NoError(t, err)
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.Credentials{Username: "admin", Password: adminpw})
token, err := helper.AuthenticateForTest(router, database.Credentials{Username: "admin", Password: adminpw})
assert.NoError(t, err)
// get the length of the GET all users response
@ -407,7 +407,7 @@ func TestGetAllUsers(t *testing.T) {
assert.Equal(t, finalNumber, initialNumber+1)
newUserCredentials := helper.Credentials{
newUserCredentials := database.Credentials{
Username: newUser.Username,
Password: newUser.Password,
}
@ -433,7 +433,7 @@ func TestModifyAddedUserAsUser(t *testing.T) {
assert.NoError(t, err)
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.Credentials{Username: "admin", Password: adminpw})
token, err := helper.AuthenticateForTest(router, database.Credentials{Username: "admin", Password: adminpw})
assert.NoError(t, err)
// Add a user that will modify itself
@ -588,7 +588,7 @@ func TestInvalidUserUpdate(t *testing.T) {
assert.NoError(t, err)
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.Credentials{Username: "admin", Password: adminpw})
token, err := helper.AuthenticateForTest(router, database.Credentials{Username: "admin", Password: adminpw})
assert.NoError(t, err)
// Add a user
@ -661,7 +661,7 @@ func TestModifyAddedUserAsAdmin(t *testing.T) {
assert.NoError(t, err)
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.Credentials{Username: "admin", Password: adminpw})
token, err := helper.AuthenticateForTest(router, database.Credentials{Username: "admin", Password: adminpw})
assert.NoError(t, err)
// Add a user
@ -747,7 +747,7 @@ func TestModifyAddedUserAsAdmin(t *testing.T) {
assert.NoError(t, err)
// authenticate as admin
token, err = helper.AuthenticateForTest(router, helper.Credentials{Username: "admin", Password: adminpw})
token, err = helper.AuthenticateForTest(router, database.Credentials{Username: "admin", Password: adminpw})
assert.NoError(t, err)
// modify newUser's Active status
@ -778,7 +778,7 @@ func TestDeleteUser(t *testing.T) {
assert.NoError(t, err)
// authenticate as admin
token, err := helper.AuthenticateForTest(router, helper.Credentials{Username: "admin", Password: adminpw})
token, err := helper.AuthenticateForTest(router, database.Credentials{Username: "admin", Password: adminpw})
assert.NoError(t, err)
// Add a user

View file

@ -99,7 +99,7 @@ func (r *updateUserRequest) updatedUser(callerID interface{}, role interface{},
// Update the username making sure it is NOT taken
var testUser User
if err := testUser.ByUsername(r.User.Username); err == nil {
if err := testUser.byUsername(r.User.Username); err == nil {
return u, fmt.Errorf("Username is alreaday taken")
}
@ -116,7 +116,7 @@ func (r *updateUserRequest) updatedUser(callerID interface{}, role interface{},
if role == "Admin" { // admin has to enter admin password
var adminUser User
err := adminUser.ByID(callerID.(uint))
err := adminUser.byID(callerID.(uint))
if err != nil {
return u, err
}

View file

@ -29,7 +29,6 @@ import (
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard"
)
func RegisterWidgetEndpoints(r *gin.RouterGroup) {
@ -54,7 +53,7 @@ func RegisterWidgetEndpoints(r *gin.RouterGroup) {
// @Security Bearer
func getWidgets(c *gin.Context) {
ok, dab := dashboard.CheckPermissions(c, database.Read, "query", -1)
ok, dab := database.CheckDashboardPermissions(c, database.Read, "query", -1)
if !ok {
return
}
@ -100,7 +99,7 @@ func addWidget(c *gin.Context) {
newWidget := req.createWidget()
// Check if user is allowed to modify selected dashboard (scenario)
ok, _ := dashboard.CheckPermissions(c, database.Update, "body", int(newWidget.DashboardID))
ok, _ := database.CheckDashboardPermissions(c, database.Update, "body", int(newWidget.DashboardID))
if !ok {
return
}
@ -129,11 +128,14 @@ func addWidget(c *gin.Context) {
// @Security Bearer
func updateWidget(c *gin.Context) {
ok, oldWidget := CheckPermissions(c, database.Update, -1)
ok, oldWidget_r := database.CheckWidgetPermissions(c, database.Update, -1)
if !ok {
return
}
var oldWidget Widget
oldWidget.Widget = oldWidget_r
var req updateWidgetRequest
if err := c.ShouldBindJSON(&req); err != nil {
helper.BadRequestError(c, err.Error())
@ -172,12 +174,12 @@ func updateWidget(c *gin.Context) {
// @Security Bearer
func getWidget(c *gin.Context) {
ok, w := CheckPermissions(c, database.Read, -1)
ok, w := database.CheckWidgetPermissions(c, database.Read, -1)
if !ok {
return
}
c.JSON(http.StatusOK, gin.H{"widget": w.Widget})
c.JSON(http.StatusOK, gin.H{"widget": w})
}
// deleteWidget godoc
@ -195,11 +197,14 @@ func getWidget(c *gin.Context) {
// @Security Bearer
func deleteWidget(c *gin.Context) {
ok, w := CheckPermissions(c, database.Delete, -1)
ok, w_r := database.CheckWidgetPermissions(c, database.Delete, -1)
if !ok {
return
}
var w Widget
w.Widget = w_r
err := w.delete()
if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"widget": w.Widget})

View file

@ -23,7 +23,6 @@ package widget
import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard"
)
type Widget struct {
@ -47,8 +46,8 @@ func (w *Widget) ByID(id uint) error {
func (w *Widget) addToDashboard() error {
db := database.GetDB()
var dab dashboard.Dashboard
err := dab.ByID(uint(w.DashboardID))
var dab database.Dashboard
err := db.Find(&dab, uint(w.DashboardID)).Error
if err != nil {
return err
}
@ -89,8 +88,8 @@ func (w *Widget) update(modifiedWidget Widget) error {
func (w *Widget) delete() error {
db := database.GetDB()
var dab dashboard.Dashboard
err := dab.ByID(w.DashboardID)
var dab database.Dashboard
err := db.Find(&dab, uint(w.DashboardID)).Error
if err != nil {
return err
}
@ -106,3 +105,26 @@ func (w *Widget) delete() error {
return err
}
func (w *Widget) Duplicate(dashboardID uint, signalMap map[uint]uint) error {
var duplicateW Widget
duplicateW.DashboardID = dashboardID
duplicateW.CustomProperties = w.CustomProperties
duplicateW.Height = w.Height
duplicateW.Width = w.Width
duplicateW.MinHeight = w.MinHeight
duplicateW.MinWidth = w.MinWidth
duplicateW.Name = w.Name
duplicateW.Type = w.Type
duplicateW.X = w.X
duplicateW.Y = w.Y
duplicateW.Z = w.Z
duplicateW.SignalIDs = []int64{}
for _, id := range w.SignalIDs {
duplicateW.SignalIDs = append(duplicateW.SignalIDs, int64(signalMap[uint(id)]))
}
err := duplicateW.addToDashboard()
return err
}

View file

@ -1,64 +0,0 @@
/** Widget package, middleware.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package widget
import (
"fmt"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard"
)
func CheckPermissions(c *gin.Context, operation database.CRUD, widgetIDBody int) (bool, Widget) {
var w Widget
var err error
err = database.ValidateRole(c, database.ModelWidget, operation)
if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of widget failed): %v", err.Error()))
return false, w
}
var widgetID int
if widgetIDBody < 0 {
widgetID, err = helper.GetIDOfElement(c, "widgetID", "path", -1)
if err != nil {
return false, w
}
} else {
widgetID = widgetIDBody
}
err = w.ByID(uint(widgetID))
if helper.DBError(c, err) {
return false, w
}
ok, _ := dashboard.CheckPermissions(c, operation, "body", int(w.DashboardID))
if !ok {
return false, w
}
return true, w
}

View file

@ -145,17 +145,17 @@ func TestMain(m *testing.M) {
func TestAddWidget(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
_, dashboardID := addScenarioAndDashboard(token)
newWidget.DashboardID = dashboardID
// authenticate as userB who has no access to scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to POST the newWidget with no access to the scenario
@ -166,7 +166,7 @@ func TestAddWidget(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to POST non JSON body
@ -212,7 +212,7 @@ func TestAddWidget(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as userB who has no access to scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to GET the newWidget with no access to the scenario
@ -226,10 +226,10 @@ func TestAddWidget(t *testing.T) {
func TestUpdateWidget(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
_, dashboardID := addScenarioAndDashboard(token)
@ -257,7 +257,7 @@ func TestUpdateWidget(t *testing.T) {
}
// authenticate as userB who has no access to scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to PUT the updatedWidget with no access to the scenario
@ -268,7 +268,7 @@ func TestUpdateWidget(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as guest user who has access to scenario
token, err = helper.AuthenticateForTest(router, helper.GuestCredentials)
token, err = helper.AuthenticateForTest(router, database.GuestCredentials)
assert.NoError(t, err)
// try to PUT as guest
@ -279,7 +279,7 @@ func TestUpdateWidget(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// try to PUT non JSON body
@ -320,10 +320,10 @@ func TestUpdateWidget(t *testing.T) {
func TestDeleteWidget(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
_, dashboardID := addScenarioAndDashboard(token)
@ -340,7 +340,7 @@ func TestDeleteWidget(t *testing.T) {
assert.NoError(t, err)
// authenticate as userB who has no access to scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to DELETE the newWidget with no access to the scenario
@ -351,7 +351,7 @@ func TestDeleteWidget(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all the widgets returned for dashboard
@ -380,16 +380,16 @@ func TestDeleteWidget(t *testing.T) {
func TestGetAllWidgetsOfDashboard(t *testing.T) {
database.DropTables()
database.MigrateModels()
assert.NoError(t, helper.AddTestUsers())
assert.NoError(t, database.AddTestUsers())
// authenticate as normal user
token, err := helper.AuthenticateForTest(router, helper.UserACredentials)
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
_, dashboardID := addScenarioAndDashboard(token)
// authenticate as userB who has no access to scenario
token, err = helper.AuthenticateForTest(router, helper.UserBCredentials)
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
assert.NoError(t, err)
// try to GET all widgets of dashboard
@ -400,7 +400,7 @@ func TestGetAllWidgetsOfDashboard(t *testing.T) {
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user
token, err = helper.AuthenticateForTest(router, helper.UserACredentials)
token, err = helper.AuthenticateForTest(router, database.UserACredentials)
assert.NoError(t, err)
// Count the number of all the widgets returned for dashboard