mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-30 00:00:12 +01:00
Merge branch 'refactor-amqp-session' of https://git.rwth-aachen.de/acs/public/villas/web-backend-go into refactor-amqp-session
This commit is contained in:
commit
7a540db693
43 changed files with 496 additions and 355 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
villasweb-backend-go
|
villasweb-backend-go
|
||||||
routes/file/testfile.txt
|
routes/file/testfile.txt
|
||||||
|
routes/result/testfile.csv
|
||||||
routes/file/testfileupdated.txt
|
routes/file/testfileupdated.txt
|
||||||
web-backend-go
|
web-backend-go
|
||||||
|
|
|
@ -10,6 +10,14 @@ stages:
|
||||||
# Stage: test
|
# Stage: test
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
staticcheck:
|
||||||
|
stage: test
|
||||||
|
image: golang:1.16-buster
|
||||||
|
before_script:
|
||||||
|
- go install honnef.co/go/tools/cmd/staticcheck@latest
|
||||||
|
script:
|
||||||
|
- staticcheck ./...
|
||||||
|
|
||||||
test:
|
test:
|
||||||
stage: test
|
stage: test
|
||||||
image: golang:1.16-buster
|
image: golang:1.16-buster
|
||||||
|
|
|
@ -121,25 +121,25 @@ func InitConfig() error {
|
||||||
"k8sCluster": *k8sCluster,
|
"k8sCluster": *k8sCluster,
|
||||||
}
|
}
|
||||||
|
|
||||||
if *dbClear == true {
|
if *dbClear {
|
||||||
static["db.clear"] = "true"
|
static["db.clear"] = "true"
|
||||||
} else {
|
} else {
|
||||||
static["db.clear"] = "false"
|
static["db.clear"] = "false"
|
||||||
}
|
}
|
||||||
|
|
||||||
if *s3NoSSL == true {
|
if *s3NoSSL {
|
||||||
static["s3.nossl"] = "true"
|
static["s3.nossl"] = "true"
|
||||||
} else {
|
} else {
|
||||||
static["s3.nossl"] = "false"
|
static["s3.nossl"] = "false"
|
||||||
}
|
}
|
||||||
|
|
||||||
if *s3PathStyle == true {
|
if *s3PathStyle {
|
||||||
static["s3.pathstyle"] = "true"
|
static["s3.pathstyle"] = "true"
|
||||||
} else {
|
} else {
|
||||||
static["s3.pathstyle"] = "false"
|
static["s3.pathstyle"] = "false"
|
||||||
}
|
}
|
||||||
|
|
||||||
if *authExternal == true {
|
if *authExternal {
|
||||||
static["auth.external.enabled"] = "true"
|
static["auth.external.enabled"] = "true"
|
||||||
} else {
|
} else {
|
||||||
static["auth.external.enabled"] = "false"
|
static["auth.external.enabled"] = "false"
|
||||||
|
|
|
@ -23,12 +23,13 @@ package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
_ "github.com/jinzhu/gorm/dialects/postgres"
|
_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||||
"github.com/zpatrick/go-config"
|
"github.com/zpatrick/go-config"
|
||||||
|
@ -37,19 +38,22 @@ import (
|
||||||
var DBpool *gorm.DB // database used by backend
|
var DBpool *gorm.DB // database used by backend
|
||||||
|
|
||||||
// InitDB Initialize connection to the database
|
// InitDB Initialize connection to the database
|
||||||
func InitDB(cfg *config.Config, dbClear string) error {
|
func InitDB(cfg *config.Config, clear bool) error {
|
||||||
name, err := cfg.String("db.name")
|
name, err := cfg.String("db.name")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
host, err := cfg.String("db.host")
|
host, err := cfg.String("db.host")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
user, err := cfg.String("db.user")
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "Required setting 'db.user' not set") {
|
user, err := cfg.StringOr("db.user", "")
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pass := ""
|
pass := ""
|
||||||
if user != "" {
|
if user != "" {
|
||||||
pass, err = cfg.String("db.pass")
|
pass, err = cfg.String("db.pass")
|
||||||
|
@ -57,6 +61,7 @@ func InitDB(cfg *config.Config, dbClear string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sslmode, err := cfg.String("db.ssl")
|
sslmode, err := cfg.String("db.ssl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -75,7 +80,7 @@ func InitDB(cfg *config.Config, dbClear string) error {
|
||||||
DBpool = db
|
DBpool = db
|
||||||
|
|
||||||
// drop tables if parameter set
|
// drop tables if parameter set
|
||||||
if dbClear == "true" {
|
if clear {
|
||||||
DropTables()
|
DropTables()
|
||||||
log.Println("Database tables dropped")
|
log.Println("Database tables dropped")
|
||||||
}
|
}
|
||||||
|
@ -120,19 +125,19 @@ func MigrateModels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DBAddAdminUser adds a default admin user to the DB
|
// DBAddAdminUser adds a default admin user to the DB
|
||||||
func DBAddAdminUser(cfg *config.Config) (error, string) {
|
func DBAddAdminUser(cfg *config.Config) (string, error) {
|
||||||
DBpool.AutoMigrate(User{})
|
DBpool.AutoMigrate(User{})
|
||||||
|
|
||||||
// Check if admin user exists in DB
|
// Check if admin user exists in DB
|
||||||
var users []User
|
var users []User
|
||||||
err := DBpool.Where("Role = ?", "Admin").Find(&users).Error
|
DBpool.Where("Role = ?", "Admin").Find(&users)
|
||||||
|
|
||||||
adminPW := ""
|
adminPW := ""
|
||||||
adminName := ""
|
|
||||||
|
|
||||||
if len(users) == 0 {
|
if len(users) == 0 {
|
||||||
fmt.Println("No admin user found in DB, adding default admin user.")
|
fmt.Println("No admin user found in DB, adding default admin user.")
|
||||||
|
|
||||||
adminName, err = cfg.String("admin.user")
|
adminName, err := cfg.String("admin.user")
|
||||||
if err != nil || adminName == "" {
|
if err != nil || adminName == "" {
|
||||||
adminName = "admin"
|
adminName = "admin"
|
||||||
}
|
}
|
||||||
|
@ -157,10 +162,10 @@ func DBAddAdminUser(cfg *config.Config) (error, string) {
|
||||||
// add admin user to DB
|
// add admin user to DB
|
||||||
err = DBpool.Create(&user).Error
|
err = DBpool.Create(&user).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, ""
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, adminPW
|
return adminPW, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generatePassword(Len int) string {
|
func generatePassword(Len int) string {
|
||||||
|
@ -217,8 +222,8 @@ var UserC = User{Username: "User_C", Password: string(pwC),
|
||||||
Role: "Guest", Mail: "User_C@example.com", Active: true}
|
Role: "Guest", Mail: "User_C@example.com", Active: true}
|
||||||
|
|
||||||
type Credentials struct {
|
type Credentials struct {
|
||||||
Username string `json:"username,required"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password,required"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var AdminCredentials = Credentials{
|
var AdminCredentials = Credentials{
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -49,42 +48,25 @@ func TestInitDB(t *testing.T) {
|
||||||
defaults := config.NewStatic(static)
|
defaults := config.NewStatic(static)
|
||||||
env := config.NewEnvironment(mappings)
|
env := config.NewEnvironment(mappings)
|
||||||
|
|
||||||
ownconfig := config.NewConfig([]config.Provider{defaults, env})
|
ownConfig := config.NewConfig([]config.Provider{defaults, env})
|
||||||
|
|
||||||
err = InitDB(ownconfig, "true")
|
err = InitDB(ownConfig, true)
|
||||||
assert.Error(t, err)
|
|
||||||
dbname, err := configuration.GlobalConfig.String("db.name")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
static["db.name"] = dbname
|
|
||||||
ownconfig = config.NewConfig([]config.Provider{defaults, env})
|
|
||||||
err = InitDB(ownconfig, "true")
|
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
dbhost, err := configuration.GlobalConfig.String("db.host")
|
dbOptions := []string{"db.name", "db.host", "db.user", "db.pass", "db.ssl"}
|
||||||
assert.NoError(t, err)
|
for _, opt := range dbOptions {
|
||||||
static["db.host"] = dbhost
|
val, err := configuration.GlobalConfig.String(opt)
|
||||||
ownconfig = config.NewConfig([]config.Provider{defaults, env})
|
assert.NoError(t, err)
|
||||||
err = InitDB(ownconfig, "true")
|
static[opt] = val
|
||||||
assert.Error(t, err)
|
ownConfig = config.NewConfig([]config.Provider{defaults, env})
|
||||||
|
err = InitDB(ownConfig, true)
|
||||||
|
|
||||||
dbuser, err := configuration.GlobalConfig.String("db.user")
|
if opt == "db.ssl" {
|
||||||
static["db.user"] = dbuser
|
assert.NoError(t, err)
|
||||||
ownconfig = config.NewConfig([]config.Provider{defaults, env})
|
} else {
|
||||||
err = InitDB(ownconfig, "true")
|
assert.Error(t, err)
|
||||||
assert.Error(t, err)
|
}
|
||||||
|
}
|
||||||
dbpass, err := configuration.GlobalConfig.String("db.pass")
|
|
||||||
static["db.pass"] = dbpass
|
|
||||||
ownconfig = config.NewConfig([]config.Provider{defaults, env})
|
|
||||||
err = InitDB(ownconfig, "true")
|
|
||||||
assert.Error(t, err)
|
|
||||||
|
|
||||||
dbssl, err := configuration.GlobalConfig.String("db.ssl")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
static["db.ssl"] = dbssl
|
|
||||||
ownconfig = config.NewConfig([]config.Provider{defaults, env})
|
|
||||||
err = InitDB(ownconfig, "true")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Verify that you can connect to the database
|
// Verify that you can connect to the database
|
||||||
db := GetDB()
|
db := GetDB()
|
||||||
|
@ -118,7 +100,7 @@ func TestUserAssociations(t *testing.T) {
|
||||||
assert.NoError(t, DBpool.Model(&userB).Association("Scenarios").Append(&scenarioA).Error)
|
assert.NoError(t, DBpool.Model(&userB).Association("Scenarios").Append(&scenarioA).Error)
|
||||||
|
|
||||||
var usr1 User
|
var usr1 User
|
||||||
assert.NoError(t, DBpool.Find(&usr1, "ID = ?", 1).Error, fmt.Sprintf("Find User with ID=1"))
|
assert.NoError(t, DBpool.Find(&usr1, "ID = ?", 1).Error, "Find User with ID=1")
|
||||||
|
|
||||||
// Get scenarios of usr1
|
// Get scenarios of usr1
|
||||||
var scenarios []Scenario
|
var scenarios []Scenario
|
||||||
|
@ -196,7 +178,7 @@ func TestScenarioAssociations(t *testing.T) {
|
||||||
assert.NoError(t, DBpool.Model(&scenarioA).Association("Results").Append(&resultB).Error)
|
assert.NoError(t, DBpool.Model(&scenarioA).Association("Results").Append(&resultB).Error)
|
||||||
|
|
||||||
var scenario1 Scenario
|
var scenario1 Scenario
|
||||||
assert.NoError(t, DBpool.Find(&scenario1, 1).Error, fmt.Sprintf("Find Scenario with ID=1"))
|
assert.NoError(t, DBpool.Find(&scenario1, 1).Error, "Find Scenario with ID=1")
|
||||||
|
|
||||||
// Get users of scenario1
|
// Get users of scenario1
|
||||||
var users []User
|
var users []User
|
||||||
|
@ -263,7 +245,7 @@ func TestICAssociations(t *testing.T) {
|
||||||
assert.NoError(t, DBpool.Model(&icA).Association("ComponentConfigurations").Append(&configB).Error)
|
assert.NoError(t, DBpool.Model(&icA).Association("ComponentConfigurations").Append(&configB).Error)
|
||||||
|
|
||||||
var ic1 InfrastructureComponent
|
var ic1 InfrastructureComponent
|
||||||
assert.NoError(t, DBpool.Find(&ic1, 1).Error, fmt.Sprintf("Find InfrastructureComponent with ID=1"))
|
assert.NoError(t, DBpool.Find(&ic1, 1).Error, "Find InfrastructureComponent with ID=1")
|
||||||
|
|
||||||
// Get Component Configurations of ic1
|
// Get Component Configurations of ic1
|
||||||
var configs []ComponentConfiguration
|
var configs []ComponentConfiguration
|
||||||
|
@ -314,7 +296,7 @@ func TestComponentConfigurationAssociations(t *testing.T) {
|
||||||
assert.NoError(t, DBpool.Model(&icA).Association("ComponentConfigurations").Append(&configB).Error)
|
assert.NoError(t, DBpool.Model(&icA).Association("ComponentConfigurations").Append(&configB).Error)
|
||||||
|
|
||||||
var config1 ComponentConfiguration
|
var config1 ComponentConfiguration
|
||||||
assert.NoError(t, DBpool.Find(&config1, 1).Error, fmt.Sprintf("Find ComponentConfiguration with ID=1"))
|
assert.NoError(t, DBpool.Find(&config1, 1).Error, "Find ComponentConfiguration with ID=1")
|
||||||
|
|
||||||
// Check IC ID
|
// Check IC ID
|
||||||
if config1.ICID != 1 {
|
if config1.ICID != 1 {
|
||||||
|
@ -355,7 +337,7 @@ func TestDashboardAssociations(t *testing.T) {
|
||||||
assert.NoError(t, DBpool.Model(&dashboardA).Association("Widgets").Append(&widgetB).Error)
|
assert.NoError(t, DBpool.Model(&dashboardA).Association("Widgets").Append(&widgetB).Error)
|
||||||
|
|
||||||
var dashboard1 Dashboard
|
var dashboard1 Dashboard
|
||||||
assert.NoError(t, DBpool.Find(&dashboard1, 1).Error, fmt.Sprintf("Find Dashboard with ID=1"))
|
assert.NoError(t, DBpool.Find(&dashboard1, 1).Error, "Find Dashboard with ID=1")
|
||||||
|
|
||||||
//Get widgets of dashboard1
|
//Get widgets of dashboard1
|
||||||
var widgets []Widget
|
var widgets []Widget
|
||||||
|
@ -380,7 +362,7 @@ func TestWidgetAssociations(t *testing.T) {
|
||||||
assert.NoError(t, DBpool.Create(&widgetB).Error)
|
assert.NoError(t, DBpool.Create(&widgetB).Error)
|
||||||
|
|
||||||
var widget1 Widget
|
var widget1 Widget
|
||||||
assert.NoError(t, DBpool.Find(&widget1, 1).Error, fmt.Sprintf("Find Widget with ID=1"))
|
assert.NoError(t, DBpool.Find(&widget1, 1).Error, "Find Widget with ID=1")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFileAssociations(t *testing.T) {
|
func TestFileAssociations(t *testing.T) {
|
||||||
|
@ -401,5 +383,5 @@ func TestFileAssociations(t *testing.T) {
|
||||||
assert.NoError(t, DBpool.Create(&fileD).Error)
|
assert.NoError(t, DBpool.Create(&fileD).Error)
|
||||||
|
|
||||||
var file1 File
|
var file1 File
|
||||||
assert.NoError(t, DBpool.Find(&file1, 1).Error, fmt.Sprintf("Find File with ID=1"))
|
assert.NoError(t, DBpool.Find(&file1, 1).Error, "Find File with ID=1")
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,10 +65,11 @@ type RoleActions map[string]ModelActions
|
||||||
// Predefined CRUD operations permissions to be used in Roles
|
// Predefined CRUD operations permissions to be used in Roles
|
||||||
var crud = Permission{Create: true, Read: true, Update: true, Delete: true}
|
var crud = Permission{Create: true, Read: true, Update: true, Delete: true}
|
||||||
var _ru_ = Permission{Create: false, Read: true, Update: true, Delete: false}
|
var _ru_ = Permission{Create: false, Read: true, Update: true, Delete: false}
|
||||||
var __u_ = Permission{Create: false, Read: false, Update: true, Delete: false}
|
|
||||||
var _r__ = Permission{Create: false, Read: true, Update: false, Delete: false}
|
var _r__ = Permission{Create: false, Read: true, Update: false, Delete: false}
|
||||||
var none = Permission{Create: false, Read: false, Update: false, Delete: false}
|
var none = Permission{Create: false, Read: false, Update: false, Delete: false}
|
||||||
|
|
||||||
|
// var __u_ = Permission{Create: false, Read: false, Update: true, Delete: false}
|
||||||
|
|
||||||
// Roles is used as a look up variable to determine if a certain user is
|
// Roles is used as a look up variable to determine if a certain user is
|
||||||
// allowed to do a certain action on a given model based on his role
|
// allowed to do a certain action on a given model based on his role
|
||||||
var Roles = RoleActions{
|
var Roles = RoleActions{
|
||||||
|
@ -134,12 +135,12 @@ func ValidateRole(c *gin.Context, model ModelName, action CRUD) error {
|
||||||
// Get user's role from context
|
// Get user's role from context
|
||||||
role, exists := c.Get(UserRoleCtx)
|
role, exists := c.Get(UserRoleCtx)
|
||||||
if !exists {
|
if !exists {
|
||||||
return fmt.Errorf("Request does not contain user's role")
|
return fmt.Errorf("request does not contain user's role")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the role can execute the action on the model
|
// Check if the role can execute the action on the model
|
||||||
if !Roles[role.(string)][model][action] {
|
if !Roles[role.(string)][model][action] {
|
||||||
return fmt.Errorf("Action not allowed for role %v", role)
|
return fmt.Errorf("action not allowed for role %v", role)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
*********************************************************************************/
|
*********************************************************************************/
|
||||||
package api
|
package api
|
||||||
|
|
||||||
|
//lint:file-ignore U1000 Ignore all unused code, it's generated
|
||||||
|
|
||||||
import "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
import "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||||
|
|
||||||
// This file defines the responses to any endpoint in the backend
|
// This file defines the responses to any endpoint in the backend
|
||||||
|
|
|
@ -29,9 +29,6 @@ const (
|
||||||
|
|
||||||
// When setting up the channel after a channel exception
|
// When setting up the channel after a channel exception
|
||||||
reInitDelay = 2 * time.Second
|
reInitDelay = 2 * time.Second
|
||||||
|
|
||||||
// When resending messages the server didn't confirm
|
|
||||||
resendDelay = 5 * time.Second
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//var client AMQPsession
|
//var client AMQPsession
|
||||||
|
|
|
@ -25,11 +25,12 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/nsf/jsondiff"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/nsf/jsondiff"
|
||||||
)
|
)
|
||||||
|
|
||||||
// data type used in testing
|
// data type used in testing
|
||||||
|
@ -56,13 +57,13 @@ type UserRequest struct {
|
||||||
func GetResponseID(resp *bytes.Buffer) (int, error) {
|
func GetResponseID(resp *bytes.Buffer) (int, error) {
|
||||||
|
|
||||||
// Transform bytes buffer into byte slice
|
// Transform bytes buffer into byte slice
|
||||||
respBytes := []byte(resp.String())
|
respBytes := resp.Bytes()
|
||||||
|
|
||||||
// Map JSON response to a map[string]map[string]interface{}
|
// Map JSON response to a map[string]map[string]interface{}
|
||||||
var respRemapped map[string]map[string]interface{}
|
var respRemapped map[string]map[string]interface{}
|
||||||
err := json.Unmarshal(respBytes, &respRemapped)
|
err := json.Unmarshal(respBytes, &respRemapped)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("Unmarshal failed for respRemapped %v", err)
|
return 0, fmt.Errorf("failed to unmarshal for respRemapped %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get an arbitrary key from tha map. The only key (entry) of
|
// Get an arbitrary key from tha map. The only key (entry) of
|
||||||
|
@ -75,11 +76,11 @@ func GetResponseID(resp *bytes.Buffer) (int, error) {
|
||||||
// the conversion to integer before returning
|
// the conversion to integer before returning
|
||||||
id, ok := respRemapped[arbitrary_key]["id"].(float64)
|
id, ok := respRemapped[arbitrary_key]["id"].(float64)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, fmt.Errorf("Cannot type assert respRemapped")
|
return 0, fmt.Errorf("cannot type assert respRemapped")
|
||||||
}
|
}
|
||||||
return int(id), nil
|
return int(id), nil
|
||||||
}
|
}
|
||||||
return 0, fmt.Errorf("GetResponse reached exit")
|
return 0, fmt.Errorf("getResponse reached exit")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the length of an response in case it is an array
|
// Return the length of an response in case it is an array
|
||||||
|
@ -90,7 +91,7 @@ func LengthOfResponse(router *gin.Engine, token string, url string,
|
||||||
|
|
||||||
req, err := http.NewRequest(method, url, nil)
|
req, err := http.NewRequest(method, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("Failed to create new request: %v", err)
|
return 0, fmt.Errorf("failed to create new request: %v", err)
|
||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Add("Authorization", "Bearer "+token)
|
req.Header.Add("Authorization", "Bearer "+token)
|
||||||
|
@ -103,7 +104,7 @@ func LengthOfResponse(router *gin.Engine, token string, url string,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the response in array of bytes
|
// Convert the response in array of bytes
|
||||||
responseBytes := []byte(w.Body.String())
|
responseBytes := w.Body.Bytes()
|
||||||
|
|
||||||
// First we are trying to unmarshal the response into an array of
|
// First we are trying to unmarshal the response into an array of
|
||||||
// general type variables ([]interface{}). If this fails we will try
|
// general type variables ([]interface{}). If this fails we will try
|
||||||
|
@ -131,7 +132,7 @@ func LengthOfResponse(router *gin.Engine, token string, url string,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failed to identify response.
|
// Failed to identify response.
|
||||||
return 0, fmt.Errorf("Length of response cannot be detected")
|
return 0, fmt.Errorf("length of response cannot be detected")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a request to an endpoint
|
// Make a request to an endpoint
|
||||||
|
@ -143,13 +144,13 @@ func TestEndpoint(router *gin.Engine, token string, url string,
|
||||||
// Marshal the HTTP request body
|
// Marshal the HTTP request body
|
||||||
body, err := json.Marshal(requestBody)
|
body, err := json.Marshal(requestBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("Failed to marshal request body: %v", err)
|
return 0, nil, fmt.Errorf("failed to marshal request body: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the request
|
// Create the request
|
||||||
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
|
req, err := http.NewRequest(method, url, bytes.NewBuffer(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("Failed to create new request: %v", err)
|
return 0, nil, fmt.Errorf("failed to create new request: %v", err)
|
||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Add("Authorization", "Bearer "+token)
|
req.Header.Add("Authorization", "Bearer "+token)
|
||||||
|
@ -202,14 +203,14 @@ func CompareResponse(resp *bytes.Buffer, expected interface{}) error {
|
||||||
// Serialize expected response
|
// Serialize expected response
|
||||||
expectedBytes, err := json.Marshal(expected)
|
expectedBytes, err := json.Marshal(expected)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to marshal expected response: %v", err)
|
return fmt.Errorf("failed to marshal expected response: %v", err)
|
||||||
}
|
}
|
||||||
// Compare
|
// Compare
|
||||||
opts := jsondiff.DefaultConsoleOptions()
|
opts := jsondiff.DefaultConsoleOptions()
|
||||||
diff, text := jsondiff.Compare(resp.Bytes(), expectedBytes, &opts)
|
diff, text := jsondiff.Compare(resp.Bytes(), expectedBytes, &opts)
|
||||||
if diff.String() != "FullMatch" && diff.String() != "SupersetMatch" {
|
if diff.String() != "FullMatch" && diff.String() != "SupersetMatch" {
|
||||||
log.Println(text)
|
log.Println(text)
|
||||||
return fmt.Errorf("Response: Expected \"%v\". Got \"%v\".",
|
return fmt.Errorf("response: Expected \"%v\". Got \"%v\"",
|
||||||
"(FullMatch OR SupersetMatch)", diff.String())
|
"(FullMatch OR SupersetMatch)", diff.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,25 +225,25 @@ func AuthenticateForTest(router *gin.Engine, credentials interface{}) (string, e
|
||||||
// Marshal credentials
|
// Marshal credentials
|
||||||
body, err := json.Marshal(credentials)
|
body, err := json.Marshal(credentials)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed to marshal credentials: %v", err)
|
return "", fmt.Errorf("failed to marshal credentials: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", "/api/v2/authenticate/internal", bytes.NewBuffer(body))
|
req, err := http.NewRequest("POST", "/api/v2/authenticate/internal", bytes.NewBuffer(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed to create new request: %v", err)
|
return "", fmt.Errorf("failed to create new request: %v", err)
|
||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
// Check that return HTTP Code is 200 (OK)
|
// Check that return HTTP Code is 200 (OK)
|
||||||
if w.Code != http.StatusOK {
|
if w.Code != http.StatusOK {
|
||||||
return "", fmt.Errorf("HTTP Code: Expected \"%v\". Got \"%v\".",
|
return "", fmt.Errorf("http code: Expected \"%v\". Got \"%v\"",
|
||||||
http.StatusOK, w.Code)
|
http.StatusOK, w.Code)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the response
|
// Get the response
|
||||||
var body_data map[string]interface{}
|
var body_data map[string]interface{}
|
||||||
err = json.Unmarshal([]byte(w.Body.String()), &body_data)
|
err = json.Unmarshal(w.Body.Bytes(), &body_data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -250,16 +251,16 @@ func AuthenticateForTest(router *gin.Engine, credentials interface{}) (string, e
|
||||||
// Check the response
|
// Check the response
|
||||||
success, ok := body_data["success"].(bool)
|
success, ok := body_data["success"].(bool)
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf("Type asssertion of response[\"success\"] failed")
|
return "", fmt.Errorf("type asssertion of response[\"success\"] failed")
|
||||||
}
|
}
|
||||||
if !success {
|
if !success {
|
||||||
return "", fmt.Errorf("Authentication failed: %v", body_data["message"])
|
return "", fmt.Errorf("authentication failed: %v", body_data["message"])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the token
|
// Extract the token
|
||||||
token, ok := body_data["token"].(string)
|
token, ok := body_data["token"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf("Type assertion of response[\"token\"] failed")
|
return "", fmt.Errorf("type assertion of response[\"token\"] failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the token and nil error
|
// Return the token and nil error
|
||||||
|
|
|
@ -33,14 +33,14 @@ func GetIDOfElement(c *gin.Context, elementName string, source string, providedI
|
||||||
if source == "path" {
|
if source == "path" {
|
||||||
id, err := strconv.Atoi(c.Param(elementName))
|
id, err := strconv.Atoi(c.Param(elementName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
BadRequestError(c, fmt.Sprintf("No or incorrect format of path parameter"))
|
BadRequestError(c, "No or incorrect format of path parameter")
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
return id, nil
|
return id, nil
|
||||||
} else if source == "query" {
|
} else if source == "query" {
|
||||||
id, err := strconv.Atoi(c.Request.URL.Query().Get(elementName))
|
id, err := strconv.Atoi(c.Request.URL.Query().Get(elementName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
BadRequestError(c, fmt.Sprintf("No or incorrect format of query parameter"))
|
BadRequestError(c, "No or incorrect format of query parameter")
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
return id, nil
|
return id, nil
|
||||||
|
|
|
@ -22,8 +22,9 @@
|
||||||
package component_configuration
|
package component_configuration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ComponentConfiguration struct {
|
type ComponentConfiguration struct {
|
||||||
|
@ -148,7 +149,7 @@ func (m *ComponentConfiguration) delete() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for sig, _ := range InputMappingSignals {
|
for sig := range InputMappingSignals {
|
||||||
err = db.Delete(&sig).Error
|
err = db.Delete(&sig).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -161,7 +162,7 @@ func (m *ComponentConfiguration) delete() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for sig, _ := range OutputMappingSignals {
|
for sig := range OutputMappingSignals {
|
||||||
err = db.Delete(&sig).Error
|
err = db.Delete(&sig).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -85,16 +85,18 @@ func addScenarioAndIC() (scenarioID uint, ICID uint) {
|
||||||
|
|
||||||
// POST $newICA
|
// POST $newICA
|
||||||
newICA := ICRequest{
|
newICA := ICRequest{
|
||||||
UUID: "7be0322d-354e-431e-84bd-ae4c9633138b",
|
UUID: "7be0322d-354e-431e-84bd-ae4c9633138b",
|
||||||
WebsocketURL: "https://villas.k8s.eonerc.rwth-aachen.de/ws/ws_sig",
|
WebsocketURL: "https://villas.k8s.eonerc.rwth-aachen.de/ws/ws_sig",
|
||||||
Type: "villas-node",
|
Type: "villas-node",
|
||||||
Name: "ACS Demo Signals",
|
Name: "ACS Demo Signals",
|
||||||
Category: "gateway",
|
Category: "gateway",
|
||||||
State: "idle",
|
State: "idle",
|
||||||
Location: "k8s",
|
Location: "k8s",
|
||||||
Description: "A signal generator for testing purposes",
|
Description: "A signal generator for testing purposes",
|
||||||
StartParameterSchema: postgres.Jsonb{json.RawMessage(`{"prop1" : "a nice prop"}`)},
|
StartParameterSchema: postgres.Jsonb{
|
||||||
ManagedExternally: newFalse(),
|
RawMessage: json.RawMessage(`{"prop1" : "a nice prop"}`),
|
||||||
|
},
|
||||||
|
ManagedExternally: newFalse(),
|
||||||
}
|
}
|
||||||
|
|
||||||
code, resp, err := helper.TestEndpoint(router, token,
|
code, resp, err := helper.TestEndpoint(router, token,
|
||||||
|
@ -118,8 +120,10 @@ func addScenarioAndIC() (scenarioID uint, ICID uint) {
|
||||||
|
|
||||||
// POST $newScenario
|
// POST $newScenario
|
||||||
newScenario := ScenarioRequest{
|
newScenario := ScenarioRequest{
|
||||||
Name: "Scenario1",
|
Name: "Scenario1",
|
||||||
StartParameters: postgres.Jsonb{json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`)},
|
StartParameters: postgres.Jsonb{
|
||||||
|
RawMessage: json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
code, resp, err = helper.TestEndpoint(router, token,
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
"/api/v2/scenarios", "POST", helper.KeyModels{"scenario": newScenario})
|
"/api/v2/scenarios", "POST", helper.KeyModels{"scenario": newScenario})
|
||||||
|
@ -131,7 +135,7 @@ func addScenarioAndIC() (scenarioID uint, ICID uint) {
|
||||||
newScenarioID, _ := helper.GetResponseID(resp)
|
newScenarioID, _ := helper.GetResponseID(resp)
|
||||||
|
|
||||||
// add the guest user to the new scenario
|
// add the guest user to the new scenario
|
||||||
_, resp, _ = helper.TestEndpoint(router, token,
|
_, _, _ = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
||||||
|
|
||||||
return uint(newScenarioID), uint(newICID)
|
return uint(newScenarioID), uint(newICID)
|
||||||
|
@ -143,7 +147,7 @@ func TestMain(m *testing.M) {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,9 @@ func (d *Dashboard) delete() error {
|
||||||
|
|
||||||
// remove association between Dashboard and Scenario
|
// remove association between Dashboard and Scenario
|
||||||
err = db.Model(&sim).Association("Dashboards").Delete(d).Error
|
err = db.Model(&sim).Association("Dashboards").Delete(d).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// get all widgets of the dashboard
|
// get all widgets of the dashboard
|
||||||
var widgets []database.Widget
|
var widgets []database.Widget
|
||||||
|
@ -97,8 +100,11 @@ func (d *Dashboard) delete() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete widgets
|
// Delete widgets
|
||||||
for widget, _ := range widgets {
|
for widget := range widgets {
|
||||||
err = db.Delete(&widget).Error
|
err = db.Delete(&widget).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete dashboard
|
// Delete dashboard
|
||||||
|
|
|
@ -61,8 +61,10 @@ func addScenario(token string) (scenarioID uint) {
|
||||||
|
|
||||||
// POST $newScenario
|
// POST $newScenario
|
||||||
newScenario := ScenarioRequest{
|
newScenario := ScenarioRequest{
|
||||||
Name: "Scenario1",
|
Name: "Scenario1",
|
||||||
StartParameters: postgres.Jsonb{json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`)},
|
StartParameters: postgres.Jsonb{
|
||||||
|
RawMessage: json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
_, resp, err := helper.TestEndpoint(router, token,
|
_, resp, err := helper.TestEndpoint(router, token,
|
||||||
"/api/v2/scenarios", "POST", helper.KeyModels{"scenario": newScenario})
|
"/api/v2/scenarios", "POST", helper.KeyModels{"scenario": newScenario})
|
||||||
|
@ -74,7 +76,7 @@ func addScenario(token string) (scenarioID uint) {
|
||||||
newScenarioID, _ := helper.GetResponseID(resp)
|
newScenarioID, _ := helper.GetResponseID(resp)
|
||||||
|
|
||||||
// add the guest user to the new scenario
|
// add the guest user to the new scenario
|
||||||
_, resp, _ = helper.TestEndpoint(router, token,
|
_, _, _ = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
||||||
|
|
||||||
return uint(newScenarioID)
|
return uint(newScenarioID)
|
||||||
|
@ -85,7 +87,7 @@ func TestMain(m *testing.M) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,8 +98,13 @@ func (f *File) Register(fileHeader *multipart.FileHeader, scenarioID uint) error
|
||||||
defer fileContent.Close()
|
defer fileContent.Close()
|
||||||
|
|
||||||
bucket, err := configuration.GlobalConfig.String("s3.bucket")
|
bucket, err := configuration.GlobalConfig.String("s3.bucket")
|
||||||
if bucket == "" {
|
if err != nil || bucket == "" {
|
||||||
|
// s3 object storage not used, s3.bucket param is empty
|
||||||
|
// save file to postgres DB
|
||||||
f.FileData, err = ioutil.ReadAll(fileContent)
|
f.FileData, err = ioutil.ReadAll(fileContent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
f.Key = ""
|
f.Key = ""
|
||||||
} else {
|
} else {
|
||||||
err := f.putS3(fileContent)
|
err := f.putS3(fileContent)
|
||||||
|
@ -160,8 +165,13 @@ func (f *File) update(fileHeader *multipart.FileHeader) error {
|
||||||
defer fileContent.Close()
|
defer fileContent.Close()
|
||||||
|
|
||||||
bucket, err := configuration.GlobalConfig.String("s3.bucket")
|
bucket, err := configuration.GlobalConfig.String("s3.bucket")
|
||||||
if bucket == "" {
|
if err != nil || bucket == "" {
|
||||||
|
// s3 object storage not used, s3.bucket param is empty
|
||||||
|
// save file to postgres DB
|
||||||
f.FileData, err = ioutil.ReadAll(fileContent)
|
f.FileData, err = ioutil.ReadAll(fileContent)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
f.Key = ""
|
f.Key = ""
|
||||||
} else {
|
} else {
|
||||||
err := f.putS3(fileContent)
|
err := f.putS3(fileContent)
|
||||||
|
|
|
@ -58,9 +58,21 @@ func getS3Session() (*session.Session, string, error) {
|
||||||
|
|
||||||
func createS3Session() (*session.Session, error) {
|
func createS3Session() (*session.Session, error) {
|
||||||
endpoint, err := configuration.GlobalConfig.String("s3.endpoint")
|
endpoint, err := configuration.GlobalConfig.String("s3.endpoint")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
region, err := configuration.GlobalConfig.String("s3.region")
|
region, err := configuration.GlobalConfig.String("s3.region")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
pathStyle, err := configuration.GlobalConfig.Bool("s3.pathstyle")
|
pathStyle, err := configuration.GlobalConfig.Bool("s3.pathstyle")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
nossl, err := configuration.GlobalConfig.Bool("s3.nossl")
|
nossl, err := configuration.GlobalConfig.Bool("s3.nossl")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
sess, err := session.NewSession(
|
sess, err := session.NewSession(
|
||||||
&aws.Config{
|
&aws.Config{
|
||||||
|
@ -134,6 +146,7 @@ func (f *File) getS3Url() (string, error) {
|
||||||
return urlStr, nil
|
return urlStr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//lint:ignore U1000 will be used later
|
||||||
func (f *File) deleteS3() error {
|
func (f *File) deleteS3() error {
|
||||||
|
|
||||||
// The session the S3 Uploader will use
|
// The session the S3 Uploader will use
|
||||||
|
|
|
@ -53,10 +53,10 @@ type ScenarioRequest struct {
|
||||||
func addScenario() (scenarioID uint) {
|
func addScenario() (scenarioID uint) {
|
||||||
|
|
||||||
// authenticate as admin
|
// authenticate as admin
|
||||||
token, _ := helper.AuthenticateForTest(router, database.AdminCredentials)
|
_, _ = helper.AuthenticateForTest(router, database.AdminCredentials)
|
||||||
|
|
||||||
// authenticate as normal user
|
// authenticate as normal user
|
||||||
token, _ = helper.AuthenticateForTest(router, database.UserACredentials)
|
token, _ := helper.AuthenticateForTest(router, database.UserACredentials)
|
||||||
|
|
||||||
// POST $newScenario
|
// POST $newScenario
|
||||||
newScenario := ScenarioRequest{
|
newScenario := ScenarioRequest{
|
||||||
|
@ -70,7 +70,7 @@ func addScenario() (scenarioID uint) {
|
||||||
newScenarioID, _ := helper.GetResponseID(resp)
|
newScenarioID, _ := helper.GetResponseID(resp)
|
||||||
|
|
||||||
// add the guest user to the new scenario
|
// add the guest user to the new scenario
|
||||||
_, resp, _ = helper.TestEndpoint(router, token,
|
_, _, _ = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
||||||
|
|
||||||
return uint(newScenarioID)
|
return uint(newScenarioID)
|
||||||
|
@ -81,7 +81,7 @@ func TestMain(m *testing.M) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ func TestAddFile(t *testing.T) {
|
||||||
// try to POST without a scenario ID
|
// try to POST without a scenario ID
|
||||||
// should return a bad request error
|
// should return a bad request error
|
||||||
code, resp, err = helper.TestEndpoint(router, token,
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/files"), "POST", emptyBuf)
|
"/api/v2/files", "POST", emptyBuf)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
@ -304,6 +304,7 @@ func TestUpdateFile(t *testing.T) {
|
||||||
assert.Equalf(t, 200, w_updated.Code, "Response body: \n%v\n", w_updated.Body)
|
assert.Equalf(t, 200, w_updated.Code, "Response body: \n%v\n", w_updated.Body)
|
||||||
|
|
||||||
newFileIDUpdated, err := helper.GetResponseID(w_updated.Body)
|
newFileIDUpdated, err := helper.GetResponseID(w_updated.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, newFileID, newFileIDUpdated)
|
assert.Equal(t, newFileID, newFileIDUpdated)
|
||||||
|
|
||||||
|
@ -407,7 +408,7 @@ func TestDeleteFile(t *testing.T) {
|
||||||
// try to DELETE non-existing fileID
|
// try to DELETE non-existing fileID
|
||||||
// should return not found
|
// should return not found
|
||||||
code, resp, err = helper.TestEndpoint(router, token,
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/files/5"), "DELETE", nil)
|
"/api/v2/files/5", "DELETE", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 404, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
@ -473,7 +474,7 @@ func TestGetAllFilesOfScenario(t *testing.T) {
|
||||||
|
|
||||||
//try to get all files with missing scenario ID; should return a bad request error
|
//try to get all files with missing scenario ID; should return a bad request error
|
||||||
code, resp, err = helper.TestEndpoint(router, token,
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/files"), "GET", nil)
|
"/api/v2/files", "GET", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration"
|
"git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration"
|
||||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||||
|
@ -62,8 +61,8 @@ func getHealth(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if connection to AMQP broker is alive if backend was started with AMQP client
|
// check if connection to AMQP broker is alive if backend was started with AMQP client
|
||||||
url, err := configuration.GlobalConfig.String("amqp.host")
|
url, err := configuration.GlobalConfig.StringOr("amqp.host", "not-set")
|
||||||
if err != nil && strings.Contains(err.Error(), "Required setting 'amqp.host' not set") {
|
if err != nil && url == "not-set" {
|
||||||
c.JSON(http.StatusOK, gin.H{})
|
c.JSON(http.StatusOK, gin.H{})
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
|
|
@ -41,7 +41,7 @@ func TestHealthz(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// connect DB
|
// connect DB
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer database.DBpool.Close()
|
defer database.DBpool.Close()
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ func TestHealthz(t *testing.T) {
|
||||||
assert.Equalf(t, 500, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 500, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
// reconnect DB
|
// reconnect DB
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer database.DBpool.Close()
|
defer database.DBpool.Close()
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,12 @@ package infrastructure_component
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
"github.com/jinzhu/gorm/dialects/postgres"
|
"github.com/jinzhu/gorm/dialects/postgres"
|
||||||
"github.com/streadway/amqp"
|
"github.com/streadway/amqp"
|
||||||
"log"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Action struct {
|
type Action struct {
|
||||||
|
@ -91,7 +91,7 @@ func ProcessMessage(message amqp.Delivery) {
|
||||||
ICUUID := payload.Properties.UUID
|
ICUUID := payload.Properties.UUID
|
||||||
_, err = uuid.Parse(ICUUID)
|
_, err = uuid.Parse(ICUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("AMQP: UUID not valid: %v, message ignored: %v \n", ICUUID, string(message.Body))
|
log.Printf("amqp: UUID not valid: %v, message ignored: %v \n", ICUUID, string(message.Body))
|
||||||
}
|
}
|
||||||
|
|
||||||
var sToBeUpdated InfrastructureComponent
|
var sToBeUpdated InfrastructureComponent
|
||||||
|
@ -108,7 +108,7 @@ func ProcessMessage(message amqp.Delivery) {
|
||||||
err = sToBeUpdated.updateExternalIC(payload, message.Body)
|
err = sToBeUpdated.updateExternalIC(payload, message.Body)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf(err.Error())
|
log.Println(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ func (s *InfrastructureComponent) updateExternalIC(payload ICUpdate, body []byte
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// if component could not be deleted there are still configurations using it in the DB
|
// if component could not be deleted there are still configurations using it in the DB
|
||||||
// continue with the update to save the new state of the component and get back to the deletion later
|
// continue with the update to save the new state of the component and get back to the deletion later
|
||||||
if strings.Contains(err.Error(), "postponed") {
|
if _, ok := err.(*DeletionPostponed); ok {
|
||||||
log.Println(err) // print log message
|
log.Println(err) // print log message
|
||||||
} else {
|
} else {
|
||||||
return err // return upon DB error
|
return err // return upon DB error
|
||||||
|
|
|
@ -25,23 +25,21 @@ package infrastructure_component
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
|
||||||
"github.com/go-resty/resty/v2"
|
|
||||||
"github.com/jinzhu/gorm/dialects/postgres"
|
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
"github.com/jinzhu/gorm/dialects/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
func QueryICAPIs(d time.Duration) {
|
func QueryICAPIs(d time.Duration) {
|
||||||
|
|
||||||
client := resty.New()
|
|
||||||
//client.SetDebug(true)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
|
||||||
for _ = range time.Tick(d) {
|
for range time.Tick(d) {
|
||||||
//log.Println("Querying IC APIs at time:", x)
|
//log.Println("Querying IC APIs at time:", x)
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -55,134 +53,143 @@ func QueryICAPIs(d time.Duration) {
|
||||||
|
|
||||||
// iterate over ICs in DB
|
// iterate over ICs in DB
|
||||||
for _, ic := range ics {
|
for _, ic := range ics {
|
||||||
|
err := queryIC(&ic)
|
||||||
if ic.ManagedExternally {
|
if err != nil {
|
||||||
continue
|
fmt.Println(err)
|
||||||
}
|
|
||||||
|
|
||||||
if ic.APIURL == "" || (!strings.HasPrefix(ic.APIURL, "http://") && !strings.HasPrefix(ic.APIURL, "https://")) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if ic.Category == "gateway" && ic.Type == "villas-node" {
|
|
||||||
|
|
||||||
log.Println("External API: checking for villas-node gateway", ic.Name)
|
|
||||||
statusResponse, err := client.R().SetHeader("Accept", "application/json").Get(ic.APIURL + "/status")
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error querying status of", ic.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var status map[string]interface{}
|
|
||||||
err = json.Unmarshal(statusResponse.Body(), &status)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error unmarshalling status of", ic.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(ic.WebsocketURL, "/")
|
|
||||||
if len(parts) > 0 && parts[len(parts)-1] != "" {
|
|
||||||
|
|
||||||
configResponse, _ := client.R().SetHeader("Accept", "application/json").Get(ic.APIURL + "/node/" + parts[len(parts)-1])
|
|
||||||
statsResponse, _ := client.R().SetHeader("Accept", "application/json").Get(ic.APIURL + "/node/" + parts[len(parts)-1] + "/stats")
|
|
||||||
|
|
||||||
var config map[string]interface{}
|
|
||||||
err = json.Unmarshal(configResponse.Body(), &config)
|
|
||||||
if err == nil {
|
|
||||||
status["config"] = config
|
|
||||||
}
|
|
||||||
var stats map[string]interface{}
|
|
||||||
err = json.Unmarshal(statsResponse.Body(), &stats)
|
|
||||||
if err == nil {
|
|
||||||
status["statistics"] = stats
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var updatedIC UpdateICRequest
|
|
||||||
statusRaw, _ := json.Marshal(status)
|
|
||||||
updatedIC.InfrastructureComponent.StatusUpdateRaw = postgres.Jsonb{RawMessage: statusRaw}
|
|
||||||
updatedIC.InfrastructureComponent.State = fmt.Sprintf("%v", status["state"])
|
|
||||||
updatedIC.InfrastructureComponent.UUID = fmt.Sprintf("%v", status["uuid"])
|
|
||||||
timeNow, myerr := strconv.ParseFloat(fmt.Sprintf("%v", status["time_now"]), 64)
|
|
||||||
if myerr != nil {
|
|
||||||
log.Println("Error parsing time_now to float", myerr.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
timeStarted, myerr := strconv.ParseFloat(fmt.Sprintf("%v", status["time_started"]), 64)
|
|
||||||
if myerr != nil {
|
|
||||||
log.Println("Error parsing time_started to float", myerr.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
uptime := timeNow - timeStarted
|
|
||||||
updatedIC.InfrastructureComponent.Uptime = uptime
|
|
||||||
|
|
||||||
// validate the update
|
|
||||||
err = updatedIC.validate()
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error validating updated villas-node gateway", ic.Name, ic.UUID, err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the update and update IC in DB
|
|
||||||
var x InfrastructureComponent
|
|
||||||
err = x.ByID(ic.ID)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error getting villas-node gateway by ID", ic.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
u := updatedIC.updatedIC(x)
|
|
||||||
err = x.update(u)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error updating villas-node gateway", ic.Name, ic.UUID, err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if ic.Category == "manager" && ic.Type == "villas-relay" {
|
|
||||||
|
|
||||||
log.Println("External API: checking for villas-relay manager", ic.Name)
|
|
||||||
statusResponse, err := client.R().SetHeader("Accept", "application/json").Get(ic.APIURL)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error querying API of", ic.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var status map[string]interface{}
|
|
||||||
err = json.Unmarshal(statusResponse.Body(), &status)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error unmarshalling status villas-relay manager", ic.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var updatedIC UpdateICRequest
|
|
||||||
statusRaw, _ := json.Marshal(status)
|
|
||||||
updatedIC.InfrastructureComponent.StatusUpdateRaw = postgres.Jsonb{RawMessage: statusRaw}
|
|
||||||
updatedIC.InfrastructureComponent.UUID = fmt.Sprintf("%v", status["uuid"])
|
|
||||||
|
|
||||||
// validate the update
|
|
||||||
err = updatedIC.validate()
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error validating updated villas-relay manager", ic.Name, ic.UUID, err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the update and update IC in DB
|
|
||||||
var x InfrastructureComponent
|
|
||||||
err = x.ByID(ic.ID)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error getting villas-relay manager by ID", ic.Name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
u := updatedIC.updatedIC(x)
|
|
||||||
err = x.update(u)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error updating villas-relay manager", ic.Name, ic.UUID, err.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if ic.Category == "gateway" && ic.Type == "villas-relay" {
|
|
||||||
|
|
||||||
// TODO add code here once API for VILLASrelay sessions is available
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func queryIC(ic *database.InfrastructureComponent) error {
|
||||||
|
if ic.ManagedExternally || ic.APIURL == "" || (!strings.HasPrefix(ic.APIURL, "http://") && !strings.HasPrefix(ic.APIURL, "https://")) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ic.Category == "gateway" {
|
||||||
|
if ic.Type == "villas-node" {
|
||||||
|
err := queryVillasNodeGateway(ic)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if ic.Type == "villas-relay" {
|
||||||
|
err := queryVillasRelayGateway(ic)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryVillasNodeGateway(ic *database.InfrastructureComponent) error {
|
||||||
|
client := resty.New()
|
||||||
|
|
||||||
|
log.Println("External API: checking for villas-node gateway", ic.Name)
|
||||||
|
statusResponse, err := client.R().SetHeader("Accept", "application/json").Get(ic.APIURL + "/status")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to query the status of %s: %w", ic.Name, err)
|
||||||
|
}
|
||||||
|
var status map[string]interface{}
|
||||||
|
err = json.Unmarshal(statusResponse.Body(), &status)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal status of %s: %w", ic.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(ic.WebsocketURL, "/")
|
||||||
|
if len(parts) > 0 && parts[len(parts)-1] != "" {
|
||||||
|
|
||||||
|
configResponse, _ := client.R().SetHeader("Accept", "application/json").Get(ic.APIURL + "/node/" + parts[len(parts)-1])
|
||||||
|
statsResponse, _ := client.R().SetHeader("Accept", "application/json").Get(ic.APIURL + "/node/" + parts[len(parts)-1] + "/stats")
|
||||||
|
|
||||||
|
var config map[string]interface{}
|
||||||
|
err = json.Unmarshal(configResponse.Body(), &config)
|
||||||
|
if err == nil {
|
||||||
|
status["config"] = config
|
||||||
|
}
|
||||||
|
var stats map[string]interface{}
|
||||||
|
err = json.Unmarshal(statsResponse.Body(), &stats)
|
||||||
|
if err == nil {
|
||||||
|
status["statistics"] = stats
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var updatedIC UpdateICRequest
|
||||||
|
statusRaw, _ := json.Marshal(status)
|
||||||
|
updatedIC.InfrastructureComponent.StatusUpdateRaw = postgres.Jsonb{RawMessage: statusRaw}
|
||||||
|
updatedIC.InfrastructureComponent.State = fmt.Sprintf("%v", status["state"])
|
||||||
|
updatedIC.InfrastructureComponent.UUID = fmt.Sprintf("%v", status["uuid"])
|
||||||
|
timeNow, err := strconv.ParseFloat(fmt.Sprintf("%v", status["time_now"]), 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse time_now to float: %w", err)
|
||||||
|
}
|
||||||
|
timeStarted, err := strconv.ParseFloat(fmt.Sprintf("%v", status["time_started"]), 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse time_started to float: %w", err)
|
||||||
|
}
|
||||||
|
uptime := timeNow - timeStarted
|
||||||
|
updatedIC.InfrastructureComponent.Uptime = uptime
|
||||||
|
|
||||||
|
// validate the update
|
||||||
|
err = updatedIC.validate()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to validate updated villas-node gateway: %s (%s): %w", ic.Name, ic.UUID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the update and update IC in DB
|
||||||
|
var x InfrastructureComponent
|
||||||
|
err = x.ByID(ic.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get villas-node gateway by ID %s (%s): %w", ic.Name, ic.UUID, err)
|
||||||
|
}
|
||||||
|
u := updatedIC.updatedIC(x)
|
||||||
|
err = x.update(u)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to update villas-node gateway %s (%s): %w", ic.Name, ic.UUID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryVillasRelayGateway(ic *database.InfrastructureComponent) error {
|
||||||
|
client := resty.New()
|
||||||
|
|
||||||
|
log.Println("External API: checking for villas-relay manager", ic.Name)
|
||||||
|
statusResponse, err := client.R().SetHeader("Accept", "application/json").Get(ic.APIURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed querying API of %s (%s): %w", ic.Name, ic.UUID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var status map[string]interface{}
|
||||||
|
err = json.Unmarshal(statusResponse.Body(), &status)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal status villas-relay manager %s (%s): %w", ic.Name, ic.UUID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var updatedIC UpdateICRequest
|
||||||
|
statusRaw, _ := json.Marshal(status)
|
||||||
|
updatedIC.InfrastructureComponent.StatusUpdateRaw = postgres.Jsonb{RawMessage: statusRaw}
|
||||||
|
updatedIC.InfrastructureComponent.UUID = fmt.Sprintf("%v", status["uuid"])
|
||||||
|
|
||||||
|
// validate the update
|
||||||
|
err = updatedIC.validate()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to validate updated villas-relay manager %s (%s): %w", ic.Name, ic.UUID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the update and update IC in DB
|
||||||
|
var x InfrastructureComponent
|
||||||
|
err = x.ByID(ic.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get villas-relay manager by ID %s (%s): %w", ic.Name, ic.UUID, err)
|
||||||
|
}
|
||||||
|
u := updatedIC.updatedIC(x)
|
||||||
|
err = x.update(u)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to update villas-relay manager %s (%s): %w", ic.Name, ic.UUID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ func addIC(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if IC to be created is managed externally
|
// Check if IC to be created is managed externally
|
||||||
if *req.InfrastructureComponent.ManagedExternally == true {
|
if *req.InfrastructureComponent.ManagedExternally {
|
||||||
// if so: refuse creation
|
// if so: refuse creation
|
||||||
helper.BadRequestError(c, "create for externally managed IC not possible with this endpoint - use /ic/{ICID}/action endpoint instead to request creation of the component")
|
helper.BadRequestError(c, "create for externally managed IC not possible with this endpoint - use /ic/{ICID}/action endpoint instead to request creation of the component")
|
||||||
return
|
return
|
||||||
|
|
32
routes/infrastructure-component/ic_errors.go
Normal file
32
routes/infrastructure-component/ic_errors.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/** User package, methods.
|
||||||
|
*
|
||||||
|
* @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"
|
||||||
|
|
||||||
|
type DeletionPostponed struct {
|
||||||
|
References int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DeletionPostponed) Error() string {
|
||||||
|
return fmt.Sprintf("deletion of IC postponed, %d config(s) associated to it", e.References)
|
||||||
|
}
|
|
@ -22,7 +22,6 @@
|
||||||
package infrastructure_component
|
package infrastructure_component
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -68,7 +67,7 @@ func (s *InfrastructureComponent) delete() error {
|
||||||
noConfigs := db.Model(s).Association("ComponentConfigurations").Count()
|
noConfigs := db.Model(s).Association("ComponentConfigurations").Count()
|
||||||
|
|
||||||
if noConfigs > 0 {
|
if noConfigs > 0 {
|
||||||
return fmt.Errorf("deletion of IC postponed, %v config(s) associated to it", noConfigs)
|
return &DeletionPostponed{References: noConfigs}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete InfrastructureComponent from DB (does NOT remain as dangling)
|
// delete InfrastructureComponent from DB (does NOT remain as dangling)
|
||||||
|
|
|
@ -84,8 +84,8 @@ var newIC1 = ICRequest{
|
||||||
State: "idle",
|
State: "idle",
|
||||||
Location: "k8s",
|
Location: "k8s",
|
||||||
Description: "A signal generator for testing purposes",
|
Description: "A signal generator for testing purposes",
|
||||||
StartParameterSchema: postgres.Jsonb{json.RawMessage(`{"startprop1" : "a nice prop"}`)},
|
StartParameterSchema: postgres.Jsonb{RawMessage: json.RawMessage(`{"startprop1" : "a nice prop"}`)},
|
||||||
CreateParameterSchema: postgres.Jsonb{json.RawMessage(`{"createprop1" : "a really nice prop"}`)},
|
CreateParameterSchema: postgres.Jsonb{RawMessage: json.RawMessage(`{"createprop1" : "a really nice prop"}`)},
|
||||||
ManagedExternally: newFalse(),
|
ManagedExternally: newFalse(),
|
||||||
Manager: "7be0322d-354e-431e-84bd-ae4c9633beef",
|
Manager: "7be0322d-354e-431e-84bd-ae4c9633beef",
|
||||||
}
|
}
|
||||||
|
@ -100,8 +100,8 @@ var newIC2 = ICRequest{
|
||||||
State: "running",
|
State: "running",
|
||||||
Location: "k8s",
|
Location: "k8s",
|
||||||
Description: "This is a test description",
|
Description: "This is a test description",
|
||||||
StartParameterSchema: postgres.Jsonb{json.RawMessage(`{"startprop1" : "a nice prop"}`)},
|
StartParameterSchema: postgres.Jsonb{RawMessage: json.RawMessage(`{"startprop1" : "a nice prop"}`)},
|
||||||
CreateParameterSchema: postgres.Jsonb{json.RawMessage(`{"createprop1" : "a really nice prop"}`)},
|
CreateParameterSchema: postgres.Jsonb{RawMessage: json.RawMessage(`{"createprop1" : "a really nice prop"}`)},
|
||||||
ManagedExternally: newTrue(),
|
ManagedExternally: newTrue(),
|
||||||
Manager: "4854af30-325f-44a5-ad59-b67b2597de99",
|
Manager: "4854af30-325f-44a5-ad59-b67b2597de99",
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ func TestMain(m *testing.M) {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
@ -132,9 +132,9 @@ func TestMain(m *testing.M) {
|
||||||
|
|
||||||
// connect AMQP client
|
// connect AMQP client
|
||||||
// Make sure that AMQP_HOST, AMQP_USER, AMQP_PASS are set
|
// Make sure that AMQP_HOST, AMQP_USER, AMQP_PASS are set
|
||||||
host, err := configuration.GlobalConfig.String("amqp.host")
|
host, _ := configuration.GlobalConfig.String("amqp.host")
|
||||||
usr, err := configuration.GlobalConfig.String("amqp.user")
|
usr, _ := configuration.GlobalConfig.String("amqp.user")
|
||||||
pass, err := configuration.GlobalConfig.String("amqp.pass")
|
pass, _ := configuration.GlobalConfig.String("amqp.pass")
|
||||||
amqpURI := "amqp://" + usr + ":" + pass + "@" + host
|
amqpURI := "amqp://" + usr + ":" + pass + "@" + host
|
||||||
|
|
||||||
// AMQP Connection startup is tested here
|
// AMQP Connection startup is tested here
|
||||||
|
@ -584,7 +584,7 @@ func TestSendActionToIC(t *testing.T) {
|
||||||
var params startParams
|
var params startParams
|
||||||
params.UUID = newIC1.UUID
|
params.UUID = newIC1.UUID
|
||||||
|
|
||||||
paramsRaw, err := json.Marshal(¶ms)
|
paramsRaw, _ := json.Marshal(¶ms)
|
||||||
action1.Parameters = paramsRaw
|
action1.Parameters = paramsRaw
|
||||||
actions := [1]Action{action1}
|
actions := [1]Action{action1}
|
||||||
|
|
||||||
|
@ -738,11 +738,13 @@ func TestDeleteICViaAMQPRecv(t *testing.T) {
|
||||||
|
|
||||||
// Add component config and associate with IC and scenario
|
// Add component config and associate with IC and scenario
|
||||||
newConfig := ConfigRequest{
|
newConfig := ConfigRequest{
|
||||||
Name: "ConfigA",
|
Name: "ConfigA",
|
||||||
ScenarioID: uint(newScenarioID),
|
ScenarioID: uint(newScenarioID),
|
||||||
ICID: 1,
|
ICID: 1,
|
||||||
StartParameters: postgres.Jsonb{json.RawMessage(`{"parameter1" : "testValue1B", "parameter2" : "testValue2B", "parameter3" : 55}`)},
|
StartParameters: postgres.Jsonb{
|
||||||
FileIDs: []int64{},
|
RawMessage: json.RawMessage(`{"parameter1" : "testValue1B", "parameter2" : "testValue2B", "parameter3" : 55}`),
|
||||||
|
},
|
||||||
|
FileIDs: []int64{},
|
||||||
}
|
}
|
||||||
|
|
||||||
code, resp, err = helper.TestEndpoint(router, token,
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
|
|
|
@ -88,7 +88,7 @@ func (r *AddICRequest) validate() error {
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
if *r.InfrastructureComponent.ManagedExternally == true {
|
if *r.InfrastructureComponent.ManagedExternally {
|
||||||
// check if valid manager UUID is provided
|
// check if valid manager UUID is provided
|
||||||
_, errs = uuid.Parse(r.InfrastructureComponent.Manager)
|
_, errs = uuid.Parse(r.InfrastructureComponent.Manager)
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
|
@ -119,8 +119,7 @@ func (r *UpdateICRequest) validate() error {
|
||||||
|
|
||||||
func (r *AddICRequest) createIC() (InfrastructureComponent, error) {
|
func (r *AddICRequest) createIC() (InfrastructureComponent, error) {
|
||||||
var s InfrastructureComponent
|
var s InfrastructureComponent
|
||||||
var err error
|
var err error = nil
|
||||||
err = nil
|
|
||||||
|
|
||||||
s.UUID = r.InfrastructureComponent.UUID
|
s.UUID = r.InfrastructureComponent.UUID
|
||||||
s.WebsocketURL = r.InfrastructureComponent.WebsocketURL
|
s.WebsocketURL = r.InfrastructureComponent.WebsocketURL
|
||||||
|
|
|
@ -311,7 +311,7 @@ func AddTestData(cfg *config.Config, router *gin.Engine) (*bytes.Buffer, error)
|
||||||
defer fh.Close()
|
defer fh.Close()
|
||||||
|
|
||||||
// io copy
|
// io copy
|
||||||
_, err = io.Copy(fileWriter, fh)
|
_, _ = io.Copy(fileWriter, fh)
|
||||||
contentType := bodyWriter.FormDataContentType()
|
contentType := bodyWriter.FormDataContentType()
|
||||||
bodyWriter.Close()
|
bodyWriter.Close()
|
||||||
|
|
||||||
|
@ -338,7 +338,7 @@ func AddTestData(cfg *config.Config, router *gin.Engine) (*bytes.Buffer, error)
|
||||||
defer fh.Close()
|
defer fh.Close()
|
||||||
|
|
||||||
// io copy
|
// io copy
|
||||||
_, err = io.Copy(fileWriter, fh)
|
_, _ = io.Copy(fileWriter, fh)
|
||||||
contentType := bodyWriter.FormDataContentType()
|
contentType := bodyWriter.FormDataContentType()
|
||||||
bodyWriter.Close()
|
bodyWriter.Close()
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ func TestMain(m *testing.M) {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,10 @@
|
||||||
package result
|
package result
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
"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/file"
|
||||||
"log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Result struct {
|
type Result struct {
|
||||||
|
@ -91,6 +92,9 @@ func (r *Result) delete() error {
|
||||||
|
|
||||||
// remove association between Result and Scenario
|
// remove association between Result and Scenario
|
||||||
err = db.Model(&sco).Association("Results").Delete(r).Error
|
err = db.Model(&sco).Association("Results").Delete(r).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Delete result files
|
// Delete result files
|
||||||
for _, fileid := range r.ResultFileIDs {
|
for _, fileid := range r.ResultFileIDs {
|
||||||
|
|
|
@ -70,10 +70,10 @@ var newResult = ResultRequest{
|
||||||
func addScenario() (scenarioID uint) {
|
func addScenario() (scenarioID uint) {
|
||||||
|
|
||||||
// authenticate as admin
|
// authenticate as admin
|
||||||
token, _ := helper.AuthenticateForTest(router, database.AdminCredentials)
|
_, _ = helper.AuthenticateForTest(router, database.AdminCredentials)
|
||||||
|
|
||||||
// authenticate as normal user
|
// authenticate as normal user
|
||||||
token, _ = helper.AuthenticateForTest(router, database.UserACredentials)
|
token, _ := helper.AuthenticateForTest(router, database.UserACredentials)
|
||||||
|
|
||||||
// POST $newScenario
|
// POST $newScenario
|
||||||
newScenario := ScenarioRequest{
|
newScenario := ScenarioRequest{
|
||||||
|
@ -87,7 +87,7 @@ func addScenario() (scenarioID uint) {
|
||||||
newScenarioID, _ := helper.GetResponseID(resp)
|
newScenarioID, _ := helper.GetResponseID(resp)
|
||||||
|
|
||||||
// add the guest user to the new scenario
|
// add the guest user to the new scenario
|
||||||
_, resp, _ = helper.TestEndpoint(router, token,
|
_, _, _ = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
||||||
|
|
||||||
return uint(newScenarioID)
|
return uint(newScenarioID)
|
||||||
|
@ -98,7 +98,7 @@ func TestMain(m *testing.M) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,9 @@ func TestGetAllResultsOfScenario(t *testing.T) {
|
||||||
|
|
||||||
// test POST newResult
|
// test POST newResult
|
||||||
configSnapshot1 := json.RawMessage(`{"configs": [ {"Name" : "conf1", "scenarioID" : 1}, {"Name" : "conf2", "scenarioID" : 1}]}`)
|
configSnapshot1 := json.RawMessage(`{"configs": [ {"Name" : "conf1", "scenarioID" : 1}, {"Name" : "conf2", "scenarioID" : 1}]}`)
|
||||||
confSnapshots := postgres.Jsonb{configSnapshot1}
|
confSnapshots := postgres.Jsonb{
|
||||||
|
RawMessage: configSnapshot1,
|
||||||
|
}
|
||||||
|
|
||||||
newResult.ScenarioID = scenarioID
|
newResult.ScenarioID = scenarioID
|
||||||
newResult.ConfigSnapshots = confSnapshots
|
newResult.ConfigSnapshots = confSnapshots
|
||||||
|
@ -174,7 +176,9 @@ func TestAddGetUpdateDeleteResult(t *testing.T) {
|
||||||
// by adding a scenario
|
// by adding a scenario
|
||||||
scenarioID := addScenario()
|
scenarioID := addScenario()
|
||||||
configSnapshot1 := json.RawMessage(`{"configs": [ {"Name" : "conf1", "scenarioID" : 1}, {"Name" : "conf2", "scenarioID" : 1}]}`)
|
configSnapshot1 := json.RawMessage(`{"configs": [ {"Name" : "conf1", "scenarioID" : 1}, {"Name" : "conf2", "scenarioID" : 1}]}`)
|
||||||
confSnapshots := postgres.Jsonb{configSnapshot1}
|
confSnapshots := postgres.Jsonb{
|
||||||
|
RawMessage: configSnapshot1,
|
||||||
|
}
|
||||||
newResult.ScenarioID = scenarioID
|
newResult.ScenarioID = scenarioID
|
||||||
newResult.ConfigSnapshots = confSnapshots
|
newResult.ConfigSnapshots = confSnapshots
|
||||||
// authenticate as normal userB who has no access to new scenario
|
// authenticate as normal userB who has no access to new scenario
|
||||||
|
@ -347,7 +351,9 @@ func TestAddDeleteResultFile(t *testing.T) {
|
||||||
// by adding a scenario
|
// by adding a scenario
|
||||||
scenarioID := addScenario()
|
scenarioID := addScenario()
|
||||||
configSnapshot1 := json.RawMessage(`{"configs": [ {"Name" : "conf1", "scenarioID" : 1}, {"Name" : "conf2", "scenarioID" : 1}]}`)
|
configSnapshot1 := json.RawMessage(`{"configs": [ {"Name" : "conf1", "scenarioID" : 1}, {"Name" : "conf2", "scenarioID" : 1}]}`)
|
||||||
confSnapshots := postgres.Jsonb{configSnapshot1}
|
confSnapshots := postgres.Jsonb{
|
||||||
|
RawMessage: configSnapshot1,
|
||||||
|
}
|
||||||
|
|
||||||
newResult.ScenarioID = scenarioID
|
newResult.ScenarioID = scenarioID
|
||||||
newResult.ConfigSnapshots = confSnapshots
|
newResult.ConfigSnapshots = confSnapshots
|
||||||
|
@ -404,6 +410,7 @@ func TestAddDeleteResultFile(t *testing.T) {
|
||||||
|
|
||||||
assert.Equalf(t, 200, w.Code, "Response body: \n%v\n", w.Body)
|
assert.Equalf(t, 200, w.Code, "Response body: \n%v\n", w.Body)
|
||||||
err = helper.CompareResponse(w.Body, helper.KeyModels{"result": newResult})
|
err = helper.CompareResponse(w.Body, helper.KeyModels{"result": newResult})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// extract file ID from response body
|
// extract file ID from response body
|
||||||
var respResult ResponseResult
|
var respResult ResponseResult
|
||||||
|
@ -455,6 +462,7 @@ func TestAddDeleteResultFile(t *testing.T) {
|
||||||
|
|
||||||
assert.Equalf(t, 200, w2.Code, "Response body: \n%v\n", w2.Body)
|
assert.Equalf(t, 200, w2.Code, "Response body: \n%v\n", w2.Body)
|
||||||
err = helper.CompareResponse(w2.Body, helper.KeyModels{"result": newResult})
|
err = helper.CompareResponse(w2.Body, helper.KeyModels{"result": newResult})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// extract file ID from response body
|
// extract file ID from response body
|
||||||
var respResult3 ResponseResult
|
var respResult3 ResponseResult
|
||||||
|
|
|
@ -23,6 +23,7 @@ package scenario
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
)
|
)
|
||||||
|
@ -104,6 +105,9 @@ func (s *Scenario) deleteUser(username string) error {
|
||||||
// There is only one associated user
|
// There is only one associated user
|
||||||
var remainingUser database.User
|
var remainingUser database.User
|
||||||
err = db.Model(s).Related(&remainingUser, "Users").Error
|
err = db.Model(s).Related(&remainingUser, "Users").Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if remainingUser.Username == username {
|
if remainingUser.Username == username {
|
||||||
// if the remaining user is the one to be deleted
|
// if the remaining user is the one to be deleted
|
||||||
return fmt.Errorf("cannot delete last user from scenario without deleting scenario itself, doing nothing")
|
return fmt.Errorf("cannot delete last user from scenario without deleting scenario itself, doing nothing")
|
||||||
|
|
|
@ -53,15 +53,19 @@ type UserRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
var newScenario1 = ScenarioRequest{
|
var newScenario1 = ScenarioRequest{
|
||||||
Name: "Scenario1",
|
Name: "Scenario1",
|
||||||
StartParameters: postgres.Jsonb{json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`)},
|
StartParameters: postgres.Jsonb{
|
||||||
IsLocked: false,
|
RawMessage: json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`),
|
||||||
|
},
|
||||||
|
IsLocked: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
var newScenario2 = ScenarioRequest{
|
var newScenario2 = ScenarioRequest{
|
||||||
Name: "Scenario2",
|
Name: "Scenario2",
|
||||||
StartParameters: postgres.Jsonb{json.RawMessage(`{"parameter1" : "testValue1B", "parameter2" : "testValue2B", "parameter3" : 55}`)},
|
StartParameters: postgres.Jsonb{
|
||||||
IsLocked: false,
|
RawMessage: json.RawMessage(`{"parameter1" : "testValue1B", "parameter2" : "testValue2B", "parameter3" : 55}`),
|
||||||
|
},
|
||||||
|
IsLocked: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
@ -70,7 +74,7 @@ func TestMain(m *testing.M) {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,14 +35,14 @@ func (s *Signal) save() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Signal) byID(id uint) error {
|
/*func (s *Signal) byID(id uint) error {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
err := db.Find(s, id).Error
|
err := db.Find(s, id).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}*/
|
||||||
|
|
||||||
func (s *Signal) AddToConfig() error {
|
func (s *Signal) AddToConfig() error {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
|
|
|
@ -95,17 +95,21 @@ func addScenarioAndICAndConfig() (scenarioID uint, ICID uint, configID uint) {
|
||||||
|
|
||||||
// POST $newICA
|
// POST $newICA
|
||||||
newICA := ICRequest{
|
newICA := ICRequest{
|
||||||
UUID: "7be0322d-354e-431e-84bd-ae4c9633138b",
|
UUID: "7be0322d-354e-431e-84bd-ae4c9633138b",
|
||||||
WebsocketURL: "https://villas.k8s.eonerc.rwth-aachen.de/ws/ws_sig",
|
WebsocketURL: "https://villas.k8s.eonerc.rwth-aachen.de/ws/ws_sig",
|
||||||
Type: "villas-node",
|
Type: "villas-node",
|
||||||
Name: "ACS Demo Signals",
|
Name: "ACS Demo Signals",
|
||||||
Category: "gateway",
|
Category: "gateway",
|
||||||
State: "idle",
|
State: "idle",
|
||||||
Location: "k8s",
|
Location: "k8s",
|
||||||
Description: "A signal generator for testing purposes",
|
Description: "A signal generator for testing purposes",
|
||||||
StartParameterSchema: postgres.Jsonb{json.RawMessage(`{"startprop1" : "a nice prop"}`)},
|
StartParameterSchema: postgres.Jsonb{
|
||||||
CreateParameterSchema: postgres.Jsonb{json.RawMessage(`{"createprop1" : "a really nice prop"}`)},
|
RawMessage: json.RawMessage(`{"startprop1" : "a nice prop"}`),
|
||||||
ManagedExternally: newFalse(),
|
},
|
||||||
|
CreateParameterSchema: postgres.Jsonb{
|
||||||
|
RawMessage: json.RawMessage(`{"createprop1" : "a really nice prop"}`),
|
||||||
|
},
|
||||||
|
ManagedExternally: newFalse(),
|
||||||
}
|
}
|
||||||
_, resp, _ := helper.TestEndpoint(router, token,
|
_, resp, _ := helper.TestEndpoint(router, token,
|
||||||
"/api/v2/ic", "POST", helper.KeyModels{"ic": newICA})
|
"/api/v2/ic", "POST", helper.KeyModels{"ic": newICA})
|
||||||
|
@ -118,8 +122,10 @@ func addScenarioAndICAndConfig() (scenarioID uint, ICID uint, configID uint) {
|
||||||
|
|
||||||
// POST $newScenario
|
// POST $newScenario
|
||||||
newScenario := ScenarioRequest{
|
newScenario := ScenarioRequest{
|
||||||
Name: "Scenario1",
|
Name: "Scenario1",
|
||||||
StartParameters: postgres.Jsonb{json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`)},
|
StartParameters: postgres.Jsonb{
|
||||||
|
RawMessage: json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
_, resp, _ = helper.TestEndpoint(router, token,
|
_, resp, _ = helper.TestEndpoint(router, token,
|
||||||
"/api/v2/scenarios", "POST", helper.KeyModels{"scenario": newScenario})
|
"/api/v2/scenarios", "POST", helper.KeyModels{"scenario": newScenario})
|
||||||
|
@ -141,7 +147,7 @@ func addScenarioAndICAndConfig() (scenarioID uint, ICID uint, configID uint) {
|
||||||
newConfigID, _ := helper.GetResponseID(resp)
|
newConfigID, _ := helper.GetResponseID(resp)
|
||||||
|
|
||||||
// add the guest user to the new scenario
|
// add the guest user to the new scenario
|
||||||
_, resp, _ = helper.TestEndpoint(router, token,
|
_, _, _ = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
||||||
|
|
||||||
return uint(newScenarioID), uint(newICID), uint(newConfigID)
|
return uint(newScenarioID), uint(newICID), uint(newConfigID)
|
||||||
|
@ -153,7 +159,7 @@ func TestMain(m *testing.M) {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
@ -189,12 +195,12 @@ func TestAddSignal(t *testing.T) {
|
||||||
_, _, configID := addScenarioAndICAndConfig()
|
_, _, configID := addScenarioAndICAndConfig()
|
||||||
|
|
||||||
// authenticate as normal user
|
// authenticate as normal user
|
||||||
token, err := helper.AuthenticateForTest(router, database.UserACredentials)
|
_, err := helper.AuthenticateForTest(router, database.UserACredentials)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
newSignal1.ConfigID = configID
|
newSignal1.ConfigID = configID
|
||||||
// authenticate as normal userB who has no access to new scenario
|
// authenticate as normal userB who has no access to new scenario
|
||||||
token, err = helper.AuthenticateForTest(router, database.UserBCredentials)
|
token, err := helper.AuthenticateForTest(router, database.UserBCredentials)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// try to POST to component config without access
|
// try to POST to component config without access
|
||||||
|
|
|
@ -65,7 +65,7 @@ func duplicateScenarioForUser(s database.Scenario, user *database.User) <-chan e
|
||||||
if ic.Category == "simulator" && ic.Type == "kubernetes" {
|
if ic.Category == "simulator" && ic.Type == "kubernetes" {
|
||||||
duplicateUUID, err := duplicateIC(ic, user.Username)
|
duplicateUUID, err := duplicateIC(ic, user.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs <- fmt.Errorf("Duplication of IC (id=%d) unsuccessful, err: %s", icID, err)
|
errs <- fmt.Errorf("duplication of IC (id=%d) unsuccessful, err: %s", icID, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,6 +278,9 @@ func duplicateComponentConfig(m database.ComponentConfiguration, scenarioID uint
|
||||||
// duplication of signals
|
// duplication of signals
|
||||||
var sigs []database.Signal
|
var sigs []database.Signal
|
||||||
err = db.Order("ID asc").Model(&m).Related(&sigs, "OutputMapping").Error
|
err = db.Order("ID asc").Model(&m).Related(&sigs, "OutputMapping").Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
smap := *signalMap
|
smap := *signalMap
|
||||||
for _, s := range sigs {
|
for _, s := range sigs {
|
||||||
var sigDup database.Signal
|
var sigDup database.Signal
|
||||||
|
|
|
@ -24,7 +24,6 @@ package user
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
|
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
|
||||||
|
|
||||||
|
@ -188,9 +187,9 @@ func updateUser(c *gin.Context) {
|
||||||
// case that the request updates the role of the old user)
|
// case that the request updates the role of the old user)
|
||||||
updatedUser, err := req.updatedUser(callerID, callerRole, oldUser)
|
updatedUser, err := req.updatedUser(callerID, callerRole, oldUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "Admin") || strings.Contains(err.Error(), "pw not changed") {
|
if _, ok := err.(*ForbiddenError); ok {
|
||||||
helper.ForbiddenError(c, err.Error())
|
helper.ForbiddenError(c, err.Error())
|
||||||
} else if strings.Contains(err.Error(), "Username") || strings.Contains(err.Error(), "old or admin password") {
|
} else if _, ok := err.(*UsernameAlreadyTaken); ok {
|
||||||
helper.BadRequestError(c, err.Error())
|
helper.BadRequestError(c, err.Error())
|
||||||
} else { // password encryption failed
|
} else { // password encryption failed
|
||||||
helper.InternalServerError(c, err.Error())
|
helper.InternalServerError(c, err.Error())
|
||||||
|
|
40
routes/user/user_errors.go
Normal file
40
routes/user/user_errors.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/** User package, methods.
|
||||||
|
*
|
||||||
|
* @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 user
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type UsernameAlreadyTaken struct {
|
||||||
|
Username string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UsernameAlreadyTaken) Error() string {
|
||||||
|
return fmt.Sprintf("username is already taken: %s", e.Username)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ForbiddenError struct {
|
||||||
|
Reason string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ForbiddenError) Error() string {
|
||||||
|
return fmt.Sprintf("permission denied: %s", e.Reason)
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ func NewUser(username, password, mail, role string, active bool) (User, error) {
|
||||||
// Check that the username is NOT taken
|
// Check that the username is NOT taken
|
||||||
err := newUser.byUsername(username)
|
err := newUser.byUsername(username)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return newUser, fmt.Errorf("Username is already taken")
|
return newUser, &UsernameAlreadyTaken{Username: username}
|
||||||
}
|
}
|
||||||
|
|
||||||
newUser.Username = username
|
newUser.Username = username
|
||||||
|
@ -97,12 +97,12 @@ func (u *User) byID(id uint) error {
|
||||||
|
|
||||||
func (u *User) setPassword(password string) error {
|
func (u *User) setPassword(password string) error {
|
||||||
if len(password) == 0 {
|
if len(password) == 0 {
|
||||||
return fmt.Errorf("Password cannot be empty")
|
return fmt.Errorf("password cannot be empty")
|
||||||
}
|
}
|
||||||
newPassword, err :=
|
newPassword, err :=
|
||||||
bcrypt.GenerateFromPassword([]byte(password), bcryptCost)
|
bcrypt.GenerateFromPassword([]byte(password), bcryptCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to generate hash from password")
|
return fmt.Errorf("failed to generate hash from password")
|
||||||
}
|
}
|
||||||
u.Password = string(newPassword)
|
u.Password = string(newPassword)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -62,7 +62,7 @@ func isAuthenticated(c *gin.Context) (bool, error) {
|
||||||
func(token *jwt.Token) (interface{}, error) {
|
func(token *jwt.Token) (interface{}, error) {
|
||||||
// Validate alg for signing the jwt
|
// Validate alg for signing the jwt
|
||||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
return nil, fmt.Errorf("Unexpected signing alg: %v",
|
return nil, fmt.Errorf("unexpected signing alg: %v",
|
||||||
token.Header["alg"])
|
token.Header["alg"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,11 +66,11 @@ type UserRequest struct {
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
err := configuration.InitConfig()
|
err := configuration.InitConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(err)
|
||||||
}
|
}
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer database.DBpool.Close()
|
defer database.DBpool.Close()
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ func TestMain(m *testing.M) {
|
||||||
func TestAuthenticate(t *testing.T) {
|
func TestAuthenticate(t *testing.T) {
|
||||||
database.DropTables()
|
database.DropTables()
|
||||||
database.MigrateModels()
|
database.MigrateModels()
|
||||||
err, adminpw := database.DBAddAdminUser(configuration.GlobalConfig)
|
adminpw, err := database.DBAddAdminUser(configuration.GlobalConfig)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// try to authenticate with non JSON body
|
// try to authenticate with non JSON body
|
||||||
|
@ -190,7 +190,7 @@ func TestAuthenticateQueryToken(t *testing.T) {
|
||||||
|
|
||||||
database.DropTables()
|
database.DropTables()
|
||||||
database.MigrateModels()
|
database.MigrateModels()
|
||||||
err, adminpw := database.DBAddAdminUser(configuration.GlobalConfig)
|
adminpw, err := database.DBAddAdminUser(configuration.GlobalConfig)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// authenticate as admin
|
// authenticate as admin
|
||||||
|
@ -211,7 +211,7 @@ func TestAddGetUser(t *testing.T) {
|
||||||
|
|
||||||
database.DropTables()
|
database.DropTables()
|
||||||
database.MigrateModels()
|
database.MigrateModels()
|
||||||
err, adminpw := database.DBAddAdminUser(configuration.GlobalConfig)
|
adminpw, err := database.DBAddAdminUser(configuration.GlobalConfig)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// authenticate as admin
|
// authenticate as admin
|
||||||
|
@ -326,7 +326,7 @@ func TestAddGetUser(t *testing.T) {
|
||||||
// try to GET user with invalid user ID
|
// try to GET user with invalid user ID
|
||||||
// should result in bad request
|
// should result in bad request
|
||||||
code, resp, err = helper.TestEndpoint(router, token,
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/users/bla"), "GET", nil)
|
"/api/v2/users/bla", "GET", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
}
|
}
|
||||||
|
@ -335,7 +335,7 @@ func TestUsersNotAllowedActions(t *testing.T) {
|
||||||
|
|
||||||
database.DropTables()
|
database.DropTables()
|
||||||
database.MigrateModels()
|
database.MigrateModels()
|
||||||
err, adminpw := database.DBAddAdminUser(configuration.GlobalConfig)
|
adminpw, err := database.DBAddAdminUser(configuration.GlobalConfig)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// authenticate as admin
|
// authenticate as admin
|
||||||
|
@ -394,7 +394,7 @@ func TestGetAllUsers(t *testing.T) {
|
||||||
|
|
||||||
database.DropTables()
|
database.DropTables()
|
||||||
database.MigrateModels()
|
database.MigrateModels()
|
||||||
err, adminpw := database.DBAddAdminUser(configuration.GlobalConfig)
|
adminpw, err := database.DBAddAdminUser(configuration.GlobalConfig)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// authenticate as admin
|
// authenticate as admin
|
||||||
|
@ -447,7 +447,7 @@ func TestModifyAddedUserAsUser(t *testing.T) {
|
||||||
|
|
||||||
database.DropTables()
|
database.DropTables()
|
||||||
database.MigrateModels()
|
database.MigrateModels()
|
||||||
err, adminpw := database.DBAddAdminUser(configuration.GlobalConfig)
|
adminpw, err := database.DBAddAdminUser(configuration.GlobalConfig)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// authenticate as admin
|
// authenticate as admin
|
||||||
|
@ -478,7 +478,7 @@ func TestModifyAddedUserAsUser(t *testing.T) {
|
||||||
|
|
||||||
// Try PUT with invalid user ID in path
|
// Try PUT with invalid user ID in path
|
||||||
// Should return a bad request
|
// Should return a bad request
|
||||||
code, resp, err = helper.TestEndpoint(router, token, fmt.Sprintf("/api/v2/users/blabla"), "PUT",
|
code, resp, err = helper.TestEndpoint(router, token, "/api/v2/users/blabla", "PUT",
|
||||||
helper.KeyModels{"user": newUser})
|
helper.KeyModels{"user": newUser})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
@ -559,7 +559,7 @@ func TestModifyAddedUserAsUser(t *testing.T) {
|
||||||
fmt.Sprintf("/api/v2/users/%v", newUserID), "PUT",
|
fmt.Sprintf("/api/v2/users/%v", newUserID), "PUT",
|
||||||
helper.KeyModels{"user": modRequest})
|
helper.KeyModels{"user": modRequest})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 403, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
// modify newUser's password with wring old password
|
// modify newUser's password with wring old password
|
||||||
modRequest = UserRequest{
|
modRequest = UserRequest{
|
||||||
|
@ -602,7 +602,7 @@ func TestInvalidUserUpdate(t *testing.T) {
|
||||||
|
|
||||||
database.DropTables()
|
database.DropTables()
|
||||||
database.MigrateModels()
|
database.MigrateModels()
|
||||||
err, adminpw := database.DBAddAdminUser(configuration.GlobalConfig)
|
adminpw, err := database.DBAddAdminUser(configuration.GlobalConfig)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// authenticate as admin
|
// authenticate as admin
|
||||||
|
@ -668,14 +668,13 @@ func TestInvalidUserUpdate(t *testing.T) {
|
||||||
helper.KeyModels{"user": modRequest})
|
helper.KeyModels{"user": modRequest})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestModifyAddedUserAsAdmin(t *testing.T) {
|
func TestModifyAddedUserAsAdmin(t *testing.T) {
|
||||||
|
|
||||||
database.DropTables()
|
database.DropTables()
|
||||||
database.MigrateModels()
|
database.MigrateModels()
|
||||||
err, adminpw := database.DBAddAdminUser(configuration.GlobalConfig)
|
adminpw, err := database.DBAddAdminUser(configuration.GlobalConfig)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// authenticate as admin
|
// authenticate as admin
|
||||||
|
@ -744,7 +743,7 @@ func TestModifyAddedUserAsAdmin(t *testing.T) {
|
||||||
fmt.Sprintf("/api/v2/users/%v", newUserID), "PUT",
|
fmt.Sprintf("/api/v2/users/%v", newUserID), "PUT",
|
||||||
helper.KeyModels{"user": modRequest})
|
helper.KeyModels{"user": modRequest})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 403, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
// modify newUser's password, requires admin password
|
// modify newUser's password, requires admin password
|
||||||
modRequest = UserRequest{
|
modRequest = UserRequest{
|
||||||
|
@ -792,7 +791,7 @@ func TestDeleteUser(t *testing.T) {
|
||||||
|
|
||||||
database.DropTables()
|
database.DropTables()
|
||||||
database.MigrateModels()
|
database.MigrateModels()
|
||||||
err, adminpw := database.DBAddAdminUser(configuration.GlobalConfig)
|
adminpw, err := database.DBAddAdminUser(configuration.GlobalConfig)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// authenticate as admin
|
// authenticate as admin
|
||||||
|
@ -817,7 +816,7 @@ func TestDeleteUser(t *testing.T) {
|
||||||
// try to DELETE with invalid ID
|
// try to DELETE with invalid ID
|
||||||
// should result in bad request
|
// should result in bad request
|
||||||
code, resp, err = helper.TestEndpoint(router, token,
|
code, resp, err = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/users/bla"), "DELETE", nil)
|
"/api/v2/users/bla", "DELETE", nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
assert.Equalf(t, 400, code, "Response body: \n%v\n", resp)
|
||||||
|
|
||||||
|
|
|
@ -82,16 +82,16 @@ func (r *updateUserRequest) updatedUser(callerID interface{}, role interface{},
|
||||||
// Only the Admin must be able to update user's role
|
// Only the Admin must be able to update user's role
|
||||||
if role != "Admin" && r.User.Role != "" {
|
if role != "Admin" && r.User.Role != "" {
|
||||||
if r.User.Role != u.Role {
|
if r.User.Role != u.Role {
|
||||||
return u, fmt.Errorf("Only Admin can update user's Role")
|
return u, &ForbiddenError{Reason: "only Admin can update user's Role"}
|
||||||
}
|
}
|
||||||
} else if role == "Admin" && r.User.Role != "" {
|
} else if role == "Admin" && r.User.Role != "" {
|
||||||
u.Role = r.User.Role
|
u.Role = r.User.Role
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only the Admin must be able to update users Active state
|
// Only the Admin must be able to update users Active state
|
||||||
if (r.User.Active == "yes" && u.Active == false) || (r.User.Active == "no" && u.Active == true) {
|
if (r.User.Active == "yes" && !u.Active) || (r.User.Active == "no" && u.Active) {
|
||||||
if role != "Admin" {
|
if role != "Admin" {
|
||||||
return u, fmt.Errorf("Only Admin can update user's Active state")
|
return u, &ForbiddenError{Reason: "only Admin can update user's Active state"}
|
||||||
} else {
|
} else {
|
||||||
u.Active = !u.Active
|
u.Active = !u.Active
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ func (r *updateUserRequest) updatedUser(callerID interface{}, role interface{},
|
||||||
// Update the username making sure it is NOT taken
|
// Update the username making sure it is NOT taken
|
||||||
var testUser User
|
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")
|
return u, &UsernameAlreadyTaken{Username: r.User.Username}
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.User.Username != "" {
|
if r.User.Username != "" {
|
||||||
|
@ -111,7 +111,7 @@ func (r *updateUserRequest) updatedUser(callerID interface{}, role interface{},
|
||||||
if r.User.Password != "" {
|
if r.User.Password != "" {
|
||||||
|
|
||||||
if r.User.OldPassword == "" { // admin or old password has to be present for pw change
|
if r.User.OldPassword == "" { // admin or old password has to be present for pw change
|
||||||
return u, fmt.Errorf("old or admin password is missing in request")
|
return u, &ForbiddenError{Reason: "missing old or admin password"}
|
||||||
}
|
}
|
||||||
|
|
||||||
if role == "Admin" { // admin has to enter admin password
|
if role == "Admin" { // admin has to enter admin password
|
||||||
|
@ -123,14 +123,14 @@ func (r *updateUserRequest) updatedUser(callerID interface{}, role interface{},
|
||||||
|
|
||||||
err = adminUser.validatePassword(r.User.OldPassword)
|
err = adminUser.validatePassword(r.User.OldPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return u, fmt.Errorf("admin password not correct, pw not changed")
|
return u, &ForbiddenError{Reason: "admin password not correct, pw not changed"}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { //normal or guest user has to enter old password
|
} else { //normal or guest user has to enter old password
|
||||||
|
|
||||||
err := oldUser.validatePassword(r.User.OldPassword)
|
err := oldUser.validatePassword(r.User.OldPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return u, fmt.Errorf("previous password not correct, pw not changed")
|
return u, &ForbiddenError{Reason: "previous password not correct, pw not changed"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,8 +86,10 @@ func addScenarioAndDashboard(token string) (scenarioID uint, dashboardID uint) {
|
||||||
|
|
||||||
// POST $newScenario
|
// POST $newScenario
|
||||||
newScenario := ScenarioRequest{
|
newScenario := ScenarioRequest{
|
||||||
Name: "Scenario1",
|
Name: "Scenario1",
|
||||||
StartParameters: postgres.Jsonb{json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`)},
|
StartParameters: postgres.Jsonb{
|
||||||
|
RawMessage: json.RawMessage(`{"parameter1" : "testValue1A", "parameter2" : "testValue2A", "parameter3" : 42}`),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
_, resp, _ := helper.TestEndpoint(router, token,
|
_, resp, _ := helper.TestEndpoint(router, token,
|
||||||
"/api/v2/scenarios", "POST", helper.KeyModels{"scenario": newScenario})
|
"/api/v2/scenarios", "POST", helper.KeyModels{"scenario": newScenario})
|
||||||
|
@ -108,7 +110,7 @@ func addScenarioAndDashboard(token string) (scenarioID uint, dashboardID uint) {
|
||||||
newDashboardID, _ := helper.GetResponseID(resp)
|
newDashboardID, _ := helper.GetResponseID(resp)
|
||||||
|
|
||||||
// add the guest user to the new scenario
|
// add the guest user to the new scenario
|
||||||
_, resp, _ = helper.TestEndpoint(router, token,
|
_, _, _ = helper.TestEndpoint(router, token,
|
||||||
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
fmt.Sprintf("/api/v2/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
||||||
|
|
||||||
return uint(newScenarioID), uint(newDashboardID)
|
return uint(newScenarioID), uint(newDashboardID)
|
||||||
|
@ -120,7 +122,7 @@ func TestMain(m *testing.M) {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = database.InitDB(configuration.GlobalConfig, "true")
|
err = database.InitDB(configuration.GlobalConfig, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(m)
|
panic(m)
|
||||||
}
|
}
|
||||||
|
|
4
start.go
4
start.go
|
@ -103,7 +103,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init database
|
// Init database
|
||||||
err = database.InitDB(configuration.GlobalConfig, dbClear)
|
err = database.InitDB(configuration.GlobalConfig, dbClear == "true")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error during initialization of database: %s, aborting.", err)
|
log.Fatalf("Error during initialization of database: %s, aborting.", err)
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that at least one admin user exists in DB
|
// Make sure that at least one admin user exists in DB
|
||||||
err, _ = database.DBAddAdminUser(configuration.GlobalConfig)
|
_, err = database.DBAddAdminUser(configuration.GlobalConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("error: adding admin user failed:", err.Error())
|
fmt.Println("error: adding admin user failed:", err.Error())
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|
Loading…
Add table
Reference in a new issue