renaming: simulation model = component configuration

This commit is contained in:
Sonja Happ 2020-03-06 15:14:29 +01:00
parent 5d63fc3e26
commit ef1dede70c
32 changed files with 1948 additions and 1943 deletions

View file

@ -95,10 +95,10 @@ test:scenario:
variables: variables:
TEST_FOLDER: routes/scenario TEST_FOLDER: routes/scenario
test:simulationmodel: test:component-configuration:
extends: test:scenario extends: test:database
variables: variables:
TEST_FOLDER: routes/simulationmodel TEST_FOLDER: routes/component-configuration
test:signal: test:signal:
extends: test:database extends: test:database

View file

@ -104,7 +104,7 @@ func GetDB() *gorm.DB {
func DropTables(db *gorm.DB) { func DropTables(db *gorm.DB) {
db.DropTableIfExists(&InfrastructureComponent{}) db.DropTableIfExists(&InfrastructureComponent{})
db.DropTableIfExists(&Signal{}) db.DropTableIfExists(&Signal{})
db.DropTableIfExists(&SimulationModel{}) db.DropTableIfExists(&ComponentConfiguration{})
db.DropTableIfExists(&File{}) db.DropTableIfExists(&File{})
db.DropTableIfExists(&Scenario{}) db.DropTableIfExists(&Scenario{})
db.DropTableIfExists(&User{}) db.DropTableIfExists(&User{})
@ -118,7 +118,7 @@ func DropTables(db *gorm.DB) {
func MigrateModels(db *gorm.DB) { func MigrateModels(db *gorm.DB) {
db.AutoMigrate(&InfrastructureComponent{}) db.AutoMigrate(&InfrastructureComponent{})
db.AutoMigrate(&Signal{}) db.AutoMigrate(&Signal{})
db.AutoMigrate(&SimulationModel{}) db.AutoMigrate(&ComponentConfiguration{})
db.AutoMigrate(&File{}) db.AutoMigrate(&File{})
db.AutoMigrate(&Scenario{}) db.AutoMigrate(&Scenario{})
db.AutoMigrate(&User{}) db.AutoMigrate(&User{})

View file

@ -107,8 +107,8 @@ func TestScenarioAssociations(t *testing.T) {
user0 := User0 user0 := User0
userA := UserA userA := UserA
userB := UserB userB := UserB
modelA := SimulationModelA configA := ConfigA
modelB := SimulationModelB configB := ConfigB
dashboardA := DashboardA dashboardA := DashboardA
dashboardB := DashboardB dashboardB := DashboardB
@ -121,9 +121,9 @@ func TestScenarioAssociations(t *testing.T) {
assert.NoError(t, db.Create(&userA).Error) // Normal User assert.NoError(t, db.Create(&userA).Error) // Normal User
assert.NoError(t, db.Create(&userB).Error) // Normal User assert.NoError(t, db.Create(&userB).Error) // Normal User
// add simulation models to DB // add component configurations to DB
assert.NoError(t, db.Create(&modelA).Error) assert.NoError(t, db.Create(&configA).Error)
assert.NoError(t, db.Create(&modelB).Error) assert.NoError(t, db.Create(&configB).Error)
// add dashboards to DB // add dashboards to DB
assert.NoError(t, db.Create(&dashboardA).Error) assert.NoError(t, db.Create(&dashboardA).Error)
@ -136,9 +136,9 @@ func TestScenarioAssociations(t *testing.T) {
assert.NoError(t, db.Model(&scenarioB).Association("Users").Append(&userA).Error) assert.NoError(t, db.Model(&scenarioB).Association("Users").Append(&userA).Error)
assert.NoError(t, db.Model(&scenarioB).Association("Users").Append(&userB).Error) assert.NoError(t, db.Model(&scenarioB).Association("Users").Append(&userB).Error)
// add scenario has many simulation models associations // add scenario has many component configurations associations
assert.NoError(t, db.Model(&scenarioA).Association("SimulationModels").Append(&modelA).Error) assert.NoError(t, db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configA).Error)
assert.NoError(t, db.Model(&scenarioA).Association("SimulationModels").Append(&modelB).Error) assert.NoError(t, db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configB).Error)
// Scenario HM Dashboards // Scenario HM Dashboards
assert.NoError(t, db.Model(&scenarioA).Association("Dashboards").Append(&dashboardA).Error) assert.NoError(t, db.Model(&scenarioA).Association("Dashboards").Append(&dashboardA).Error)
@ -156,12 +156,12 @@ func TestScenarioAssociations(t *testing.T) {
"Expected to have %v Users. Has %v.", 2, len(users)) "Expected to have %v Users. Has %v.", 2, len(users))
} }
// Get simulation models of scenario1 // Get component configurations of scenario1
var models []SimulationModel var configs []ComponentConfiguration
assert.NoError(t, db.Model(&scenario1).Related(&models, "SimulationModels").Error) assert.NoError(t, db.Model(&scenario1).Related(&configs, "ComponentConfigurations").Error)
if len(models) != 2 { if len(configs) != 2 {
assert.Fail(t, "Scenario Associations", assert.Fail(t, "Scenario Associations",
"Expected to have %v simulation models. Has %v.", 2, len(models)) "Expected to have %v component configs. Has %v.", 2, len(configs))
} }
// Get dashboards of scenario1 // Get dashboards of scenario1
@ -181,42 +181,42 @@ func TestICAssociations(t *testing.T) {
// create copies of global test data // create copies of global test data
icA := ICA icA := ICA
icB := ICB icB := ICB
modelA := SimulationModelA configA := ConfigA
modelB := SimulationModelB configB := ConfigB
// add ICs to DB // add ICs to DB
assert.NoError(t, db.Create(&icA).Error) assert.NoError(t, db.Create(&icA).Error)
assert.NoError(t, db.Create(&icB).Error) assert.NoError(t, db.Create(&icB).Error)
// add simulation models to DB // add component configurations to DB
assert.NoError(t, db.Create(&modelA).Error) assert.NoError(t, db.Create(&configA).Error)
assert.NoError(t, db.Create(&modelB).Error) assert.NoError(t, db.Create(&configB).Error)
// add IC has many simulation models association to DB // add IC has many component configurations association to DB
assert.NoError(t, db.Model(&icA).Association("SimulationModels").Append(&modelA).Error) assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configA).Error)
assert.NoError(t, db.Model(&icA).Association("SimulationModels").Append(&modelB).Error) assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configB).Error)
var ic1 InfrastructureComponent var ic1 InfrastructureComponent
assert.NoError(t, db.Find(&ic1, 1).Error, fmt.Sprintf("Find InfrastructureComponent with ID=1")) assert.NoError(t, db.Find(&ic1, 1).Error, fmt.Sprintf("Find InfrastructureComponent with ID=1"))
assert.EqualValues(t, "Host_A", ic1.Host) assert.EqualValues(t, "Host_A", ic1.Host)
// Get simulation models of ic1 // Get Component Configurations of ic1
var models []SimulationModel var configs []ComponentConfiguration
assert.NoError(t, db.Model(&ic1).Association("SimulationModels").Find(&models).Error) assert.NoError(t, db.Model(&ic1).Association("ComponentConfigurations").Find(&configs).Error)
if len(models) != 2 { if len(configs) != 2 {
assert.Fail(t, "InfrastructureComponent Associations", assert.Fail(t, "InfrastructureComponent Associations",
"Expected to have %v SimulationModels. Has %v.", 2, len(models)) "Expected to have %v Component Configurations. Has %v.", 2, len(configs))
} }
} }
func TestSimulationModelAssociations(t *testing.T) { func TestComponentConfigurationAssociations(t *testing.T) {
DropTables(db) DropTables(db)
MigrateModels(db) MigrateModels(db)
// create copies of global test data // create copies of global test data
modelA := SimulationModelA configA := ConfigA
modelB := SimulationModelB configB := ConfigB
outSignalA := OutSignalA outSignalA := OutSignalA
outSignalB := OutSignalB outSignalB := OutSignalB
inSignalA := InSignalA inSignalA := InSignalA
@ -228,9 +228,9 @@ func TestSimulationModelAssociations(t *testing.T) {
icA := ICA icA := ICA
icB := ICB icB := ICB
// add simulation models to DB // add Component Configurations to DB
assert.NoError(t, db.Create(&modelA).Error) assert.NoError(t, db.Create(&configA).Error)
assert.NoError(t, db.Create(&modelB).Error) assert.NoError(t, db.Create(&configB).Error)
// add signals to DB // add signals to DB
assert.NoError(t, db.Create(&outSignalA).Error) assert.NoError(t, db.Create(&outSignalA).Error)
@ -248,42 +248,42 @@ func TestSimulationModelAssociations(t *testing.T) {
assert.NoError(t, db.Create(&icA).Error) assert.NoError(t, db.Create(&icA).Error)
assert.NoError(t, db.Create(&icB).Error) assert.NoError(t, db.Create(&icB).Error)
// add simulation model has many signals associations // add Component Configuration has many signals associations
assert.NoError(t, db.Model(&modelA).Association("InputMapping").Append(&inSignalA).Error) assert.NoError(t, db.Model(&configA).Association("InputMapping").Append(&inSignalA).Error)
assert.NoError(t, db.Model(&modelA).Association("InputMapping").Append(&inSignalB).Error) assert.NoError(t, db.Model(&configA).Association("InputMapping").Append(&inSignalB).Error)
assert.NoError(t, db.Model(&modelA).Association("OutputMapping").Append(&outSignalA).Error) assert.NoError(t, db.Model(&configA).Association("OutputMapping").Append(&outSignalA).Error)
assert.NoError(t, db.Model(&modelA).Association("OutputMapping").Append(&outSignalB).Error) assert.NoError(t, db.Model(&configA).Association("OutputMapping").Append(&outSignalB).Error)
// add simulation model has many files associations // add Component Configuration has many files associations
assert.NoError(t, db.Model(&modelA).Association("Files").Append(&fileC).Error) assert.NoError(t, db.Model(&configA).Association("Files").Append(&fileC).Error)
assert.NoError(t, db.Model(&modelA).Association("Files").Append(&fileD).Error) assert.NoError(t, db.Model(&configA).Association("Files").Append(&fileD).Error)
// associate simulation models with IC // associate Component Configurations with IC
assert.NoError(t, db.Model(&icA).Association("SimulationModels").Append(&modelA).Error) assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configA).Error)
assert.NoError(t, db.Model(&icA).Association("SimulationModels").Append(&modelB).Error) assert.NoError(t, db.Model(&icA).Association("ComponentConfigurations").Append(&configB).Error)
var model1 SimulationModel var config1 ComponentConfiguration
assert.NoError(t, db.Find(&model1, 1).Error, fmt.Sprintf("Find SimulationModel with ID=1")) assert.NoError(t, db.Find(&config1, 1).Error, fmt.Sprintf("Find ComponentConfiguration with ID=1"))
assert.EqualValues(t, "SimulationModel_A", model1.Name) assert.EqualValues(t, ConfigA.Name, config1.Name)
// Check IC ID // Check IC ID
if model1.ICID != 1 { if config1.ICID != 1 {
assert.Fail(t, "Simulation Model expected to have InfrastructureComponent ID 1, but is %v", model1.ICID) assert.Fail(t, "Component Configurations expected to have Infrastructure Component ID 1, but is %v", config1.ICID)
} }
// Get OutputMapping signals of model1 // Get OutputMapping signals of config1
var signals []Signal var signals []Signal
assert.NoError(t, db.Model(&model1).Where("Direction = ?", "out").Related(&signals, "OutputMapping").Error) assert.NoError(t, db.Model(&config1).Where("Direction = ?", "out").Related(&signals, "OutputMapping").Error)
if len(signals) != 2 { if len(signals) != 2 {
assert.Fail(t, "SimulationModel Associations", assert.Fail(t, "ComponentConfiguration Associations",
"Expected to have %v Output Signals. Has %v.", 2, len(signals)) "Expected to have %v Output Signals. Has %v.", 2, len(signals))
} }
// Get files of model1 // Get files of config1
var files []File var files []File
assert.NoError(t, db.Model(&model1).Related(&files, "Files").Error) assert.NoError(t, db.Model(&config1).Related(&files, "Files").Error)
if len(files) != 2 { if len(files) != 2 {
assert.Fail(t, "SimulationModel Associations", assert.Fail(t, "ComponentConfiguration Associations",
"Expected to have %v Files. Has %v.", 2, len(files)) "Expected to have %v Files. Has %v.", 2, len(files))
} }
} }

View file

@ -65,35 +65,35 @@ type Scenario struct {
StartParameters postgres.Jsonb `json:"startParameters"` StartParameters postgres.Jsonb `json:"startParameters"`
// Users that have access to the scenario // Users that have access to the scenario
Users []*User `json:"-" gorm:"many2many:user_scenarios;"` Users []*User `json:"-" gorm:"many2many:user_scenarios;"`
// SimulationModels that belong to the scenario // ComponentConfigurations that belong to the scenario
SimulationModels []SimulationModel `json:"-" gorm:"foreignkey:ScenarioID" ` ComponentConfigurations []ComponentConfiguration `json:"-" gorm:"foreignkey:ScenarioID" `
// Dashboards that belong to the Scenario // Dashboards that belong to the Scenario
Dashboards []Dashboard `json:"-" gorm:"foreignkey:ScenarioID" ` Dashboards []Dashboard `json:"-" gorm:"foreignkey:ScenarioID" `
} }
// SimulationModel data model // ComponentConfiguration data model
type SimulationModel struct { type ComponentConfiguration struct {
Model Model
// Name of simulation model // Name of Component Configuration
Name string `json:"name" gorm:"not null"` Name string `json:"name" gorm:"not null"`
// Number of output signals // Number of output signals
OutputLength int `json:"outputLength" gorm:"default:0"` OutputLength int `json:"outputLength" gorm:"default:0"`
// Number of input signals // Number of input signals
InputLength int `json:"inputLength" gorm:"default:0"` InputLength int `json:"inputLength" gorm:"default:0"`
// Start parameters of simulation model as JSON // Start parameters of Component Configuration as JSON
StartParameters postgres.Jsonb `json:"startParameters"` StartParameters postgres.Jsonb `json:"startParameters"`
// ID of Scenario to which simulation model belongs // ID of Scenario to which Component Configuration belongs
ScenarioID uint `json:"scenarioID"` ScenarioID uint `json:"scenarioID"`
// ID of IC associated with simulation model // ID of IC associated with Component Configuration
ICID uint `json:"icID"` ICID uint `json:"icID"`
// Mapping of output signals of the simulation model, order of signals is important // Mapping of output signals of the ComponentConfiguration, order of signals is important
OutputMapping []Signal `json:"-" gorm:"foreignkey:SimulationModelID"` OutputMapping []Signal `json:"-" gorm:"foreignkey:ConfigID"`
// Mapping of input signals of the simulation model, order of signals is important // Mapping of input signals of the Component Configuration, order of signals is important
InputMapping []Signal `json:"-" gorm:"foreignkey:SimulationModelID"` InputMapping []Signal `json:"-" gorm:"foreignkey:ConfigID"`
// Files of simulation model (can be CIM and other simulation model file formats) // Files of Component Configuration (can be CIM and other ComponentConfiguration file formats)
Files []File `json:"-" gorm:"foreignkey:SimulationModelID"` Files []File `json:"-" gorm:"foreignkey:ConfigID"`
// Currently selected simulation model FileID // Currently selected FileID
SelectedModelFileID uint `json:"selectedModelFileID" gorm:"default:0"` SelectedFileID uint `json:"selectedFileID" gorm:"default:0"`
} }
// Signal data model // Signal data model
@ -107,8 +107,8 @@ type Signal struct {
Index uint `json:"index"` Index uint `json:"index"`
// Direction of the signal (in or out) // Direction of the signal (in or out)
Direction string `json:"direction"` Direction string `json:"direction"`
// ID of simulation model // ID of Component Configuration
SimulationModelID uint `json:"simulationModelID"` ConfigID uint `json:"configID"`
} }
// InfrastructureComponent data model // InfrastructureComponent data model
@ -130,8 +130,8 @@ type InfrastructureComponent struct {
Properties postgres.Jsonb `json:"properties"` Properties postgres.Jsonb `json:"properties"`
// Raw properties of IC as JSON string // Raw properties of IC as JSON string
RawProperties postgres.Jsonb `json:"rawProperties"` RawProperties postgres.Jsonb `json:"rawProperties"`
// SimulationModels in which the IC is used // ComponentConfigurations in which the IC is used
SimulationModels []SimulationModel `json:"-" gorm:"foreignkey:ICID"` ComponentConfigurations []ComponentConfiguration `json:"-" gorm:"foreignkey:ICID"`
} }
// Dashboard data model // Dashboard data model
@ -195,8 +195,8 @@ type File struct {
ImageWidth uint `json:"imageWidth"` ImageWidth uint `json:"imageWidth"`
// Last modification time of file // Last modification time of file
Date string `json:"date"` Date string `json:"date"`
// ID of model to which file belongs // ID of Component Configuration to which file belongs
SimulationModelID uint `json:"simulationModelID"` ConfigID uint `json:"configID"`
// ID of widget to which file belongs // ID of widget to which file belongs
WidgetID uint `json:"widgetID"` WidgetID uint `json:"widgetID"`
// File itself // File itself

View file

@ -42,7 +42,7 @@ const ModelInfrastructureComponent = ModelName("ic")
const ModelInfrastructureComponentAction = ModelName("icaction") const ModelInfrastructureComponentAction = ModelName("icaction")
const ModelDashboard = ModelName("dashboard") const ModelDashboard = ModelName("dashboard")
const ModelWidget = ModelName("widget") const ModelWidget = ModelName("widget")
const ModelSimulationModel = ModelName("simulationmodel") const ModelComponentConfiguration = ModelName("component-configuration")
const ModelSignal = ModelName("signal") const ModelSignal = ModelName("signal")
const ModelFile = ModelName("file") const ModelFile = ModelName("file")
@ -76,7 +76,7 @@ var Roles = RoleActions{
ModelUser: crud, ModelUser: crud,
ModelUsers: crud, ModelUsers: crud,
ModelScenario: crud, ModelScenario: crud,
ModelSimulationModel: crud, ModelComponentConfiguration: crud,
ModelInfrastructureComponent: crud, ModelInfrastructureComponent: crud,
ModelInfrastructureComponentAction: crud, ModelInfrastructureComponentAction: crud,
ModelWidget: crud, ModelWidget: crud,
@ -88,7 +88,7 @@ var Roles = RoleActions{
ModelUser: _ru_, ModelUser: _ru_,
ModelUsers: none, ModelUsers: none,
ModelScenario: crud, ModelScenario: crud,
ModelSimulationModel: crud, ModelComponentConfiguration: crud,
ModelInfrastructureComponent: _r__, ModelInfrastructureComponent: _r__,
ModelInfrastructureComponentAction: _ru_, ModelInfrastructureComponentAction: _ru_,
ModelWidget: crud, ModelWidget: crud,
@ -98,7 +98,7 @@ var Roles = RoleActions{
}, },
"Guest": { "Guest": {
ModelScenario: _r__, ModelScenario: _r__,
ModelSimulationModel: _r__, ModelComponentConfiguration: _r__,
ModelDashboard: _r__, ModelDashboard: _r__,
ModelWidget: _r__, ModelWidget: _r__,
ModelInfrastructureComponent: _r__, ModelInfrastructureComponent: _r__,

View file

@ -98,18 +98,18 @@ var ScenarioB = Scenario{
StartParameters: postgres.Jsonb{startParametersB}, StartParameters: postgres.Jsonb{startParametersB},
} }
// Simulation Models // Component Configuration
var SimulationModelA = SimulationModel{ var ConfigA = ComponentConfiguration{
Name: "SimulationModel_A", Name: "Example simulation",
StartParameters: postgres.Jsonb{startParametersA}, StartParameters: postgres.Jsonb{startParametersA},
SelectedModelFileID: 3, SelectedFileID: 3,
} }
var SimulationModelB = SimulationModel{ var ConfigB = ComponentConfiguration{
Name: "SimulationModel_B", Name: "VILLASnode gateway X",
StartParameters: postgres.Jsonb{startParametersB}, StartParameters: postgres.Jsonb{startParametersB},
SelectedModelFileID: 4, SelectedFileID: 4,
} }
// Signals // Signals
@ -198,7 +198,7 @@ var customPropertiesLabel = json.RawMessage(`{"textSize" : "20", "fontColor" : 5
var customPropertiesButton = json.RawMessage(`{"toggle" : "Value1", "on_value" : "Value2", "off_value" : Value3}`) var customPropertiesButton = json.RawMessage(`{"toggle" : "Value1", "on_value" : "Value2", "off_value" : Value3}`)
var customPropertiesCustomActions = json.RawMessage(`{"actions" : "Value1", "icon" : "Value2"}`) var customPropertiesCustomActions = json.RawMessage(`{"actions" : "Value1", "icon" : "Value2"}`)
var customPropertiesGauge = json.RawMessage(`{ "valueMin": 0, "valueMax": 1}`) var customPropertiesGauge = json.RawMessage(`{ "valueMin": 0, "valueMax": 1}`)
var customPropertiesLamp = json.RawMessage(`{"simulationModel" : "null", "signal" : 0, "on_color" : 4, "off_color": 2 , "threshold" : 0.5}`) var customPropertiesLamp = json.RawMessage(`{"signal" : 0, "on_color" : 4, "off_color": 2 , "threshold" : 0.5}`)
var WidgetA = Widget{ var WidgetA = Widget{
Name: "Label", Name: "Label",
@ -327,8 +327,8 @@ func DBAddTestData(db *gorm.DB) error {
inSignalA := InSignalA inSignalA := InSignalA
inSignalB := InSignalB inSignalB := InSignalB
modelA := SimulationModelA configA := ConfigA
modelB := SimulationModelB configB := ConfigB
dashboardA := DashboardA dashboardA := DashboardA
dashboardB := DashboardB dashboardB := DashboardB
@ -368,9 +368,9 @@ func DBAddTestData(db *gorm.DB) error {
err = db.Create(&outSignalA).Error err = db.Create(&outSignalA).Error
err = db.Create(&outSignalB).Error err = db.Create(&outSignalB).Error
// Simulation Models // Component Configuration
err = db.Create(&modelA).Error err = db.Create(&configA).Error
err = db.Create(&modelB).Error err = db.Create(&configB).Error
// Dashboards // Dashboards
err = db.Create(&dashboardA).Error err = db.Create(&dashboardA).Error
@ -400,9 +400,9 @@ func DBAddTestData(db *gorm.DB) error {
err = db.Model(&scenarioA).Association("Users").Append(&userC).Error err = db.Model(&scenarioA).Association("Users").Append(&userC).Error
err = db.Model(&scenarioA).Association("Users").Append(&user0).Error err = db.Model(&scenarioA).Association("Users").Append(&user0).Error
// Scenario HM SimulationModels // Scenario HM Component Configurations
err = db.Model(&scenarioA).Association("SimulationModels").Append(&modelA).Error err = db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configA).Error
err = db.Model(&scenarioA).Association("SimulationModels").Append(&modelB).Error err = db.Model(&scenarioA).Association("ComponentConfigurations").Append(&configB).Error
// Scenario HM Dashboards // Scenario HM Dashboards
err = db.Model(&scenarioA).Association("Dashboards").Append(&dashboardA).Error err = db.Model(&scenarioA).Association("Dashboards").Append(&dashboardA).Error
@ -415,19 +415,19 @@ func DBAddTestData(db *gorm.DB) error {
err = db.Model(&dashboardA).Association("Widgets").Append(&widgetD).Error err = db.Model(&dashboardA).Association("Widgets").Append(&widgetD).Error
err = db.Model(&dashboardA).Association("Widgets").Append(&widgetE).Error err = db.Model(&dashboardA).Association("Widgets").Append(&widgetE).Error
// SimulationModel HM Signals // ComponentConfiguration HM Signals
err = db.Model(&modelA).Association("InputMapping").Append(&inSignalA).Error err = db.Model(&configA).Association("InputMapping").Append(&inSignalA).Error
err = db.Model(&modelA).Association("InputMapping").Append(&inSignalB).Error err = db.Model(&configA).Association("InputMapping").Append(&inSignalB).Error
err = db.Model(&modelA).Association("InputMapping").Append(&outSignalA).Error err = db.Model(&configA).Association("InputMapping").Append(&outSignalA).Error
err = db.Model(&modelA).Association("InputMapping").Append(&outSignalB).Error err = db.Model(&configA).Association("InputMapping").Append(&outSignalB).Error
// SimulationModel HM Files // ComponentConfiguration HM Files
err = db.Model(&modelA).Association("Files").Append(&fileC).Error err = db.Model(&configA).Association("Files").Append(&fileC).Error
err = db.Model(&modelA).Association("Files").Append(&fileD).Error err = db.Model(&configA).Association("Files").Append(&fileD).Error
// InfrastructureComponent HM SimulationModels // InfrastructureComponent HM ComponentConfigurations
err = db.Model(&ICA).Association("SimulationModels").Append(&modelA).Error err = db.Model(&ICA).Association("ComponentConfigurations").Append(&configA).Error
err = db.Model(&ICA).Association("SimulationModels").Append(&modelB).Error err = db.Model(&ICA).Association("ComponentConfigurations").Append(&configB).Error
// Widget HM Files // Widget HM Files
err = db.Model(&widgetA).Association("Files").Append(&fileA).Error err = db.Model(&widgetA).Association("Files").Append(&fileA).Error

File diff suppressed because it is too large Load diff

View file

@ -62,12 +62,12 @@ type ResponseScenario struct {
scenario database.Scenario scenario database.Scenario
} }
type ResponseSimulationModels struct { type ResponseConfigs struct {
simulationModels []database.SimulationModel configs []database.ComponentConfiguration
} }
type ResponseSimulationModel struct { type ResponseConfig struct {
simulationModel database.SimulationModel config database.ComponentConfiguration
} }
type ResponseDashboards struct { type ResponseDashboards struct {

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,46 @@
basePath: /api/v2 basePath: /api/v2
definitions: definitions:
component_configuration.addConfigRequest:
properties:
config:
$ref: '#/definitions/component_configuration.validNewConfig'
type: object
type: object
component_configuration.updateConfigRequest:
properties:
config:
$ref: '#/definitions/component_configuration.validUpdatedConfig'
type: object
type: object
component_configuration.validNewConfig:
properties:
ICID:
type: integer
Name:
type: string
ScenarioID:
type: integer
SelectedFileID:
type: integer
StartParameters:
type: string
required:
- ICID
- Name
- ScenarioID
- StartParameters
type: object
component_configuration.validUpdatedConfig:
properties:
ICID:
type: integer
Name:
type: string
SelectedFileID:
type: integer
StartParameters:
type: string
type: object
dashboard.addDashboardRequest: dashboard.addDashboardRequest:
properties: properties:
dashboard: dashboard:
@ -32,6 +73,32 @@ definitions:
name: name:
type: string type: string
type: object type: object
database.ComponentConfiguration:
properties:
icID:
description: ID of IC associated with Component Configuration
type: integer
id:
type: integer
inputLength:
description: Number of input signals
type: integer
name:
description: Name of Component Configuration
type: string
outputLength:
description: Number of output signals
type: integer
scenarioID:
description: ID of Scenario to which Component Configuration belongs
type: integer
selectedFileID:
description: Currently selected FileID
type: integer
startParameters:
description: Start parameters of Component Configuration as JSON
type: string
type: object
database.Dashboard: database.Dashboard:
properties: properties:
grid: grid:
@ -48,6 +115,9 @@ definitions:
type: object type: object
database.File: database.File:
properties: properties:
configID:
description: ID of Component Configuration to which file belongs
type: integer
date: date:
description: Last modification time of file description: Last modification time of file
type: string type: string
@ -62,9 +132,6 @@ definitions:
name: name:
description: Name of file description: Name of file
type: string type: string
simulationModelID:
description: ID of model to which file belongs
type: integer
size: size:
description: Size of file (in byte) description: Size of file (in byte)
type: integer type: integer
@ -120,6 +187,9 @@ definitions:
type: object type: object
database.Signal: database.Signal:
properties: properties:
configID:
description: ID of Component Configuration
type: integer
direction: direction:
description: Direction of the signal (in or out) description: Direction of the signal (in or out)
type: string type: string
@ -131,39 +201,10 @@ definitions:
name: name:
description: Name of Signal description: Name of Signal
type: string type: string
simulationModelID:
description: ID of simulation model
type: integer
unit: unit:
description: Unit of Signal description: Unit of Signal
type: string type: string
type: object type: object
database.SimulationModel:
properties:
icID:
description: ID of IC associated with simulation model
type: integer
id:
type: integer
inputLength:
description: Number of input signals
type: integer
name:
description: Name of simulation model
type: string
outputLength:
description: Number of output signals
type: integer
scenarioID:
description: ID of Scenario to which simulation model belongs
type: integer
selectedModelFileID:
description: Currently selected simulation model FileID
type: integer
startParameters:
description: Start parameters of simulation model as JSON
type: string
type: object
database.User: database.User:
properties: properties:
active: active:
@ -238,6 +279,19 @@ definitions:
$ref: '#/definitions/database.User' $ref: '#/definitions/database.User'
type: object type: object
type: object type: object
docs.ResponseConfig:
properties:
config:
$ref: '#/definitions/database.ComponentConfiguration'
type: object
type: object
docs.ResponseConfigs:
properties:
configs:
items:
$ref: '#/definitions/database.ComponentConfiguration'
type: array
type: object
docs.ResponseDashboard: docs.ResponseDashboard:
properties: properties:
dashboard: dashboard:
@ -310,19 +364,6 @@ definitions:
$ref: '#/definitions/database.Signal' $ref: '#/definitions/database.Signal'
type: array type: array
type: object type: object
docs.ResponseSimulationModel:
properties:
simulationModel:
$ref: '#/definitions/database.SimulationModel'
type: object
type: object
docs.ResponseSimulationModels:
properties:
simulationModels:
items:
$ref: '#/definitions/database.SimulationModel'
type: array
type: object
docs.ResponseUser: docs.ResponseUser:
properties: properties:
user: user:
@ -439,21 +480,21 @@ definitions:
type: object type: object
signal.validNewSignal: signal.validNewSignal:
properties: properties:
ConfigID:
type: integer
Direction: Direction:
type: string type: string
Index: Index:
type: integer type: integer
Name: Name:
type: string type: string
SimulationModelID:
type: integer
Unit: Unit:
type: string type: string
required: required:
- ConfigID
- Direction - Direction
- Index - Index
- Name - Name
- SimulationModelID
type: object type: object
signal.validUpdatedSignal: signal.validUpdatedSignal:
properties: properties:
@ -464,47 +505,6 @@ definitions:
Unit: Unit:
type: string type: string
type: object type: object
simulationmodel.addSimulationModelRequest:
properties:
simulationModel:
$ref: '#/definitions/simulationmodel.validNewSimulationModel'
type: object
type: object
simulationmodel.updateSimulationModelRequest:
properties:
simulationModel:
$ref: '#/definitions/simulationmodel.validUpdatedSimulationModel'
type: object
type: object
simulationmodel.validNewSimulationModel:
properties:
ICID:
type: integer
Name:
type: string
ScenarioID:
type: integer
SelectedModelFileID:
type: integer
StartParameters:
type: string
required:
- ICID
- Name
- ScenarioID
- StartParameters
type: object
simulationmodel.validUpdatedSimulationModel:
properties:
ICID:
type: integer
Name:
type: string
SelectedModelFileID:
type: integer
StartParameters:
type: string
type: object
user.addUserRequest: user.addUserRequest:
properties: properties:
user: user:
@ -686,6 +686,237 @@ paths:
summary: Authentication for user summary: Authentication for user
tags: tags:
- authentication - authentication
/configs:
get:
operationId: getConfigs
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Scenario ID
in: query
name: scenarioID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: Component configurations which belong to scenario
schema:
$ref: '#/definitions/docs.ResponseConfigs'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Get all component configurations of scenario
tags:
- component-configurations
post:
consumes:
- application/json
operationId: addConfig
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: component configuration to be added incl. IDs of scenario and
IC
in: body
name: inputConfig
required: true
schema:
$ref: '#/definitions/component_configuration.addConfigRequest'
type: object
produces:
- application/json
responses:
"200":
description: Component configuration that was added
schema:
$ref: '#/definitions/docs.ResponseConfig'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Add a component configuration to a scenario
tags:
- component-configurations
/configs/{configID}:
delete:
operationId: deleteConfig
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Config ID
in: path
name: configID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: component configuration that was deleted
schema:
$ref: '#/definitions/docs.ResponseConfig'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Delete a component configuration
tags:
- component-configurations
get:
operationId: getConfig
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Config ID
in: path
name: configID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: component configuration that was requested
schema:
$ref: '#/definitions/docs.ResponseConfig'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Get a component configuration
tags:
- component-configurations
put:
consumes:
- application/json
operationId: updateConfig
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: component configuration to be updated
in: body
name: inputConfig
required: true
schema:
$ref: '#/definitions/component_configuration.updateConfigRequest'
type: object
- description: Config ID
in: path
name: configID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: Component configuration that was added
schema:
$ref: '#/definitions/docs.ResponseConfig'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Update a component configuration
tags:
- component-configurations
/dashboards: /dashboards:
get: get:
operationId: getDashboards operationId: getDashboards
@ -925,12 +1156,13 @@ paths:
name: Authorization name: Authorization
required: true required: true
type: string type: string
- description: Set to model for files of model, set to widget for files of widget - description: Set to config for files of component configuration, set to widget
for files of widget
in: query in: query
name: objectType name: objectType
required: true required: true
type: string type: string
- description: ID of either model or widget of which files are requested - description: ID of either config or widget of which files are requested
in: query in: query
name: objectID name: objectID
required: true required: true
@ -939,7 +1171,7 @@ paths:
- application/json - application/json
responses: responses:
"200": "200":
description: Files which belong to simulation model or widget description: Files which belong to config or widget
schema: schema:
$ref: '#/definitions/docs.ResponseFiles' $ref: '#/definitions/docs.ResponseFiles'
type: object type: object
@ -958,7 +1190,7 @@ paths:
schema: schema:
$ref: '#/definitions/docs.ResponseError' $ref: '#/definitions/docs.ResponseError'
type: object type: object
summary: Get all files of a specific model or widget summary: Get all files of a specific component configuration or widget
tags: tags:
- files - files
post: post:
@ -981,12 +1213,13 @@ paths:
name: inputFile name: inputFile
required: true required: true
type: file type: file
- description: Set to model for files of model, set to widget for files of widget - description: Set to config for files of component config, set to widget for
files of widget
in: query in: query
name: objectType name: objectType
required: true required: true
type: string type: string
- description: ID of either model or widget of which files are requested - description: ID of either config or widget of which files are requested
in: query in: query
name: objectID name: objectID
required: true required: true
@ -1019,7 +1252,7 @@ paths:
schema: schema:
$ref: '#/definitions/docs.ResponseError' $ref: '#/definitions/docs.ResponseError'
type: object type: object
summary: Add a file to a specific model or widget summary: Add a file to a specific component config or widget
tags: tags:
- files - files
/files/{fileID}: /files/{fileID}:
@ -1480,7 +1713,7 @@ paths:
"200": "200":
description: Configs requested by user description: Configs requested by user
schema: schema:
$ref: '#/definitions/docs.ResponseSimulationModels' $ref: '#/definitions/docs.ResponseConfigs'
type: object type: object
"400": "400":
description: Bad request description: Bad request
@ -1516,236 +1749,6 @@ paths:
summary: Prometheus metrics endpoint summary: Prometheus metrics endpoint
tags: tags:
- metrics - metrics
/models:
get:
operationId: getSimulationModels
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Scenario ID
in: query
name: scenarioID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: Simulation models which belong to scenario
schema:
$ref: '#/definitions/docs.ResponseSimulationModels'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Get all simulation models of scenario
tags:
- simulationModels
post:
consumes:
- application/json
operationId: addSimulationModel
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Simulation model to be added incl. IDs of scenario and IC
in: body
name: inputSimulationModel
required: true
schema:
$ref: '#/definitions/simulationmodel.addSimulationModelRequest'
type: object
produces:
- application/json
responses:
"200":
description: simulation model that was added
schema:
$ref: '#/definitions/docs.ResponseSimulationModel'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Add a simulation model to a scenario
tags:
- simulationModels
/models/{modelID}:
delete:
operationId: deleteSimulationModel
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Model ID
in: path
name: modelID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: simulation model that was deleted
schema:
$ref: '#/definitions/docs.ResponseSimulationModel'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Delete a simulation model
tags:
- simulationModels
get:
operationId: getSimulationModel
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Model ID
in: path
name: modelID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: simulation model that was requested
schema:
$ref: '#/definitions/docs.ResponseSimulationModel'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Get a simulation model
tags:
- simulationModels
put:
consumes:
- application/json
operationId: updateSimulationModel
parameters:
- description: Authorization token
in: header
name: Authorization
required: true
type: string
- description: Simulation model to be updated
in: body
name: inputSimulationModel
required: true
schema:
$ref: '#/definitions/simulationmodel.updateSimulationModelRequest'
type: object
- description: Model ID
in: path
name: modelID
required: true
type: integer
produces:
- application/json
responses:
"200":
description: simulation model that was added
schema:
$ref: '#/definitions/docs.ResponseSimulationModel'
type: object
"400":
description: Bad request
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"404":
description: Not found
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"422":
description: Unprocessable entity
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
"500":
description: Internal server error
schema:
$ref: '#/definitions/docs.ResponseError'
type: object
summary: Update a simulation model
tags:
- simulationModels
/scenarios: /scenarios:
get: get:
operationId: getScenarios operationId: getScenarios
@ -2099,9 +2102,9 @@ paths:
name: direction name: direction
required: true required: true
type: string type: string
- description: Model ID of signals to be obtained - description: Config ID of signals to be obtained
in: query in: query
name: modelID name: configID
required: true required: true
type: string type: string
- description: Authorization token - description: Authorization token
@ -2113,7 +2116,7 @@ paths:
- application/json - application/json
responses: responses:
"200": "200":
description: Signals which belong to simulation model description: Signals which belong to component configuration
schema: schema:
$ref: '#/definitions/docs.ResponseSignals' $ref: '#/definitions/docs.ResponseSignals'
type: object type: object
@ -2145,8 +2148,8 @@ paths:
name: Authorization name: Authorization
required: true required: true
type: string type: string
- description: A signal to be added to the model incl. direction and model ID - description: A signal to be added to the component configuration incl. direction
to which signal shall be added and config ID to which signal shall be added
in: body in: body
name: inputSignal name: inputSignal
required: true required: true
@ -2181,7 +2184,7 @@ paths:
schema: schema:
$ref: '#/definitions/docs.ResponseError' $ref: '#/definitions/docs.ResponseError'
type: object type: object
summary: Add a signal to a signal mapping of a model summary: Add a signal to a signal mapping of a component configuration
tags: tags:
- signals - signals
/signals/{signalID}: /signals/{signalID}:

View file

@ -1,4 +1,4 @@
/** Simulationmodel package, endpoints. /** component_configuration package, endpoints.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulationmodel package component_configuration
import ( import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
@ -31,27 +31,27 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
) )
func RegisterSimulationModelEndpoints(r *gin.RouterGroup) { func RegisterComponentConfigurationEndpoints(r *gin.RouterGroup) {
r.GET("", getSimulationModels) r.GET("", getConfigs)
r.POST("", addSimulationModel) r.POST("", addConfig)
r.PUT("/:modelID", updateSimulationModel) r.PUT("/:configID", updateConfig)
r.GET("/:modelID", getSimulationModel) r.GET("/:configID", getConfig)
r.DELETE("/:modelID", deleteSimulationModel) r.DELETE("/:configID", deleteConfig)
} }
// getSimulationModels godoc // getConfigs godoc
// @Summary Get all simulation models of scenario // @Summary Get all component configurations of scenario
// @ID getSimulationModels // @ID getConfigs
// @Produce json // @Produce json
// @Tags simulationModels // @Tags component-configurations
// @Success 200 {object} docs.ResponseSimulationModels "Simulation models which belong to scenario" // @Success 200 {object} docs.ResponseConfigs "Component configurations which belong to scenario"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param scenarioID query int true "Scenario ID" // @Param scenarioID query int true "Scenario ID"
// @Router /models [get] // @Router /configs [get]
func getSimulationModels(c *gin.Context) { func getConfigs(c *gin.Context) {
ok, so := scenario.CheckPermissions(c, database.Read, "query", -1) ok, so := scenario.CheckPermissions(c, database.Read, "query", -1)
if !ok { if !ok {
@ -59,32 +59,32 @@ func getSimulationModels(c *gin.Context) {
} }
db := database.GetDB() db := database.GetDB()
var models []database.SimulationModel var configs []database.ComponentConfiguration
err := db.Order("ID asc").Model(so).Related(&models, "Models").Error err := db.Order("ID asc").Model(so).Related(&configs, "ComponentConfigurations").Error
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulationModels": models}) c.JSON(http.StatusOK, gin.H{"configs": configs})
} }
} }
// addSimulationModel godoc // addConfig godoc
// @Summary Add a simulation model to a scenario // @Summary Add a component configuration to a scenario
// @ID addSimulationModel // @ID addConfig
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Tags simulationModels // @Tags component-configurations
// @Success 200 {object} docs.ResponseSimulationModel "simulation model that was added" // @Success 200 {object} docs.ResponseConfig "Component configuration that was added"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param inputSimulationModel body simulationmodel.addSimulationModelRequest true "Simulation model to be added incl. IDs of scenario and IC" // @Param inputConfig body component_configuration.addConfigRequest true "component configuration to be added incl. IDs of scenario and IC"
// @Router /models [post] // @Router /configs [post]
func addSimulationModel(c *gin.Context) { func addConfig(c *gin.Context) {
// Bind the request to JSON // Bind the request to JSON
var req addSimulationModelRequest var req addConfigRequest
err := c.ShouldBindJSON(&req) err := c.ShouldBindJSON(&req)
if err != nil { if err != nil {
helper.BadRequestError(c, "Bad request. Error binding form data to JSON: "+err.Error()) helper.BadRequestError(c, "Bad request. Error binding form data to JSON: "+err.Error())
@ -97,46 +97,46 @@ func addSimulationModel(c *gin.Context) {
return return
} }
// Create the new simulation model from the request // Create the new Component Configuration from the request
newSimulationModel := req.createSimulationModel() newConfig := req.createConfig()
// check access to the scenario // check access to the scenario
ok, _ := scenario.CheckPermissions(c, database.Update, "body", int(newSimulationModel.ScenarioID)) ok, _ := scenario.CheckPermissions(c, database.Update, "body", int(newConfig.ScenarioID))
if !ok { if !ok {
return return
} }
// add the new simulation model to the scenario // add the new Component Configuration to the scenario
err = newSimulationModel.addToScenario() err = newConfig.addToScenario()
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulationModel": newSimulationModel.SimulationModel}) c.JSON(http.StatusOK, gin.H{"config": newConfig.ComponentConfiguration})
} }
} }
// updateSimulationModel godoc // updateConfig godoc
// @Summary Update a simulation model // @Summary Update a component configuration
// @ID updateSimulationModel // @ID updateConfig
// @Tags simulationModels // @Tags component-configurations
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulationModel "simulation model that was added" // @Success 200 {object} docs.ResponseConfig "Component configuration that was added"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param inputSimulationModel body simulationmodel.updateSimulationModelRequest true "Simulation model to be updated" // @Param inputConfig body component_configuration.updateConfigRequest true "component configuration to be updated"
// @Param modelID path int true "Model ID" // @Param configID path int true "Config ID"
// @Router /models/{modelID} [put] // @Router /configs/{configID} [put]
func updateSimulationModel(c *gin.Context) { func updateConfig(c *gin.Context) {
ok, oldSimulationModel := CheckPermissions(c, database.Update, "path", -1) ok, oldConfig := CheckPermissions(c, database.Update, "path", -1)
if !ok { if !ok {
return return
} }
var req updateSimulationModelRequest var req updateConfigRequest
err := c.BindJSON(&req) err := c.BindJSON(&req)
if err != nil { if err != nil {
helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error()) helper.BadRequestError(c, "Error binding form data to JSON: "+err.Error())
@ -144,59 +144,59 @@ func updateSimulationModel(c *gin.Context) {
} }
// Validate the request // Validate the request
if err := req.SimulationModel.validate(); err != nil { if err := req.Config.validate(); err != nil {
helper.BadRequestError(c, err.Error()) helper.BadRequestError(c, err.Error())
return return
} }
// Create the updatedSimulationModel from oldSimulationModel // Create the updateConfig from oldConfig
updatedSimulationModel := req.updatedSimulationModel(oldSimulationModel) updatedConfig := req.updateConfig(oldConfig)
// Finally, update the simulation model // Finally, update the Component Configuration
err = oldSimulationModel.Update(updatedSimulationModel) err = oldConfig.Update(updatedConfig)
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulationModel": updatedSimulationModel.SimulationModel}) c.JSON(http.StatusOK, gin.H{"config": updatedConfig.ComponentConfiguration})
} }
} }
// getSimulationModel godoc // getConfig godoc
// @Summary Get a simulation model // @Summary Get a component configuration
// @ID getSimulationModel // @ID getConfig
// @Tags simulationModels // @Tags component-configurations
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulationModel "simulation model that was requested" // @Success 200 {object} docs.ResponseConfig "component configuration that was requested"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param modelID path int true "Model ID" // @Param configID path int true "Config ID"
// @Router /models/{modelID} [get] // @Router /configs/{configID} [get]
func getSimulationModel(c *gin.Context) { func getConfig(c *gin.Context) {
ok, m := CheckPermissions(c, database.Read, "path", -1) ok, m := CheckPermissions(c, database.Read, "path", -1)
if !ok { if !ok {
return return
} }
c.JSON(http.StatusOK, gin.H{"simulationModel": m.SimulationModel}) c.JSON(http.StatusOK, gin.H{"config": m.ComponentConfiguration})
} }
// deleteSimulationModel godoc // deleteConfig godoc
// @Summary Delete a simulation model // @Summary Delete a component configuration
// @ID deleteSimulationModel // @ID deleteConfig
// @Tags simulationModels // @Tags component-configurations
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulationModel "simulation model that was deleted" // @Success 200 {object} docs.ResponseConfig "component configuration that was deleted"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param modelID path int true "Model ID" // @Param configID path int true "Config ID"
// @Router /models/{modelID} [delete] // @Router /configs/{configID} [delete]
func deleteSimulationModel(c *gin.Context) { func deleteConfig(c *gin.Context) {
ok, m := CheckPermissions(c, database.Delete, "path", -1) ok, m := CheckPermissions(c, database.Delete, "path", -1)
if !ok { if !ok {
@ -205,6 +205,6 @@ func deleteSimulationModel(c *gin.Context) {
err := m.delete() err := m.delete()
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"simulationModel": m.SimulationModel}) c.JSON(http.StatusOK, gin.H{"config": m.ComponentConfiguration})
} }
} }

View file

@ -1,4 +1,4 @@
/** Simulationmodel package, methods. /** component_configuration package, methods.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulationmodel package component_configuration
import ( import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
@ -27,17 +27,17 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
) )
type SimulationModel struct { type ComponentConfiguration struct {
database.SimulationModel database.ComponentConfiguration
} }
func (m *SimulationModel) save() error { func (m *ComponentConfiguration) save() error {
db := database.GetDB() db := database.GetDB()
err := db.Create(m).Error err := db.Create(m).Error
return err return err
} }
func (m *SimulationModel) ByID(id uint) error { func (m *ComponentConfiguration) ByID(id uint) error {
db := database.GetDB() db := database.GetDB()
err := db.Find(m, id).Error err := db.Find(m, id).Error
if err != nil { if err != nil {
@ -46,7 +46,7 @@ func (m *SimulationModel) ByID(id uint) error {
return nil return nil
} }
func (m *SimulationModel) addToScenario() error { func (m *ComponentConfiguration) addToScenario() error {
db := database.GetDB() db := database.GetDB()
var so scenario.Scenario var so scenario.Scenario
err := so.ByID(m.ScenarioID) err := so.ByID(m.ScenarioID)
@ -54,35 +54,35 @@ func (m *SimulationModel) addToScenario() error {
return err return err
} }
// save simulation model to DB // save component configuration to DB
err = m.save() err = m.save()
if err != nil { if err != nil {
return err return err
} }
// associate IC with simulation model // associate IC with component configuration
var ic infrastructure_component.InfrastructureComponent var ic infrastructure_component.InfrastructureComponent
err = ic.ByID(m.ICID) err = ic.ByID(m.ICID)
err = db.Model(&ic).Association("SimulationModels").Append(m).Error err = db.Model(&ic).Association("ComponentConfigurations").Append(m).Error
if err != nil { if err != nil {
return err return err
} }
// associate simulation model with scenario // associate component configuration with scenario
err = db.Model(&so).Association("SimulationModels").Append(m).Error err = db.Model(&so).Association("ComponentConfigurations").Append(m).Error
return err return err
} }
func (m *SimulationModel) Update(modifiedSimulationModel SimulationModel) error { func (m *ComponentConfiguration) Update(modifiedConfig ComponentConfiguration) error {
db := database.GetDB() db := database.GetDB()
// check if IC has been updated // check if IC has been updated
if m.ICID != modifiedSimulationModel.ICID { if m.ICID != modifiedConfig.ICID {
// update IC // update IC
var s infrastructure_component.InfrastructureComponent var s infrastructure_component.InfrastructureComponent
var s_old infrastructure_component.InfrastructureComponent var s_old infrastructure_component.InfrastructureComponent
err := s.ByID(modifiedSimulationModel.ICID) err := s.ByID(modifiedConfig.ICID)
if err != nil { if err != nil {
return err return err
} }
@ -90,29 +90,29 @@ func (m *SimulationModel) Update(modifiedSimulationModel SimulationModel) error
if err != nil { if err != nil {
return err return err
} }
// remove simulation model from old IC // remove component configuration from old IC
err = db.Model(&s_old).Association("SimulationModels").Delete(m).Error err = db.Model(&s_old).Association("ComponentConfigurations").Delete(m).Error
if err != nil { if err != nil {
return err return err
} }
// add simulation model to new IC // add component configuration to new IC
err = db.Model(&s).Association("SimulationModels").Append(m).Error err = db.Model(&s).Association("ComponentConfigurations").Append(m).Error
if err != nil { if err != nil {
return err return err
} }
} }
err := db.Model(m).Updates(map[string]interface{}{ err := db.Model(m).Updates(map[string]interface{}{
"Name": modifiedSimulationModel.Name, "Name": modifiedConfig.Name,
"StartParameters": modifiedSimulationModel.StartParameters, "StartParameters": modifiedConfig.StartParameters,
"ICID": modifiedSimulationModel.ICID, "ICID": modifiedConfig.ICID,
"SelectedModelFileID": modifiedSimulationModel.SelectedModelFileID, "SelectedFileID": modifiedConfig.SelectedFileID,
}).Error }).Error
return err return err
} }
func (m *SimulationModel) delete() error { func (m *ComponentConfiguration) delete() error {
db := database.GetDB() db := database.GetDB()
var so scenario.Scenario var so scenario.Scenario
@ -121,9 +121,9 @@ func (m *SimulationModel) delete() error {
return err return err
} }
// remove association between SimulationModel and Scenario // remove association between ComponentConfiguration and Scenario
// SimulationModel itself is not deleted from DB, it remains as "dangling" // ComponentConfiguration itself is not deleted from DB, it remains as "dangling"
err = db.Model(&so).Association("SimulationModels").Delete(m).Error err = db.Model(&so).Association("ComponentConfigurations").Delete(m).Error
return err return err
} }

View file

@ -1,4 +1,4 @@
/** Simulationmodel package, middleware. /** component_configuration package, middleware.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulationmodel package component_configuration
import ( import (
"fmt" "fmt"
@ -30,22 +30,22 @@ import (
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
) )
func CheckPermissions(c *gin.Context, operation database.CRUD, modelIDSource string, modelIDBody int) (bool, SimulationModel) { func CheckPermissions(c *gin.Context, operation database.CRUD, configIDSource string, configIDBody int) (bool, ComponentConfiguration) {
var m SimulationModel var m ComponentConfiguration
err := database.ValidateRole(c, database.ModelSimulationModel, operation) err := database.ValidateRole(c, database.ModelComponentConfiguration, operation)
if err != nil { if err != nil {
helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of simulation model failed): %v", err.Error())) helper.UnprocessableEntityError(c, fmt.Sprintf("Access denied (role validation of Component Configuration failed): %v", err.Error()))
return false, m return false, m
} }
modelID, err := helper.GetIDOfElement(c, "modelID", modelIDSource, modelIDBody) configID, err := helper.GetIDOfElement(c, "configID", configIDSource, configIDBody)
if err != nil { if err != nil {
return false, m return false, m
} }
err = m.ByID(uint(modelID)) err = m.ByID(uint(configID))
if helper.DBError(c, err) { if helper.DBError(c, err) {
return false, m return false, m
} }

View file

@ -1,4 +1,4 @@
/** Simulationmodel package, testing. /** component_configuration package, testing.
* *
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de> * @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC * @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
@ -19,7 +19,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/ *********************************************************************************/
package simulationmodel package component_configuration
import ( import (
"fmt" "fmt"
@ -39,13 +39,15 @@ import (
var router *gin.Engine var router *gin.Engine
var db *gorm.DB var db *gorm.DB
var base_api_configs = "/api/configs"
var base_api_auth = "/api/authenticate"
type SimulationModelRequest struct { type ConfigRequest struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
ScenarioID uint `json:"scenarioID,omitempty"` ScenarioID uint `json:"scenarioID,omitempty"`
ICID uint `json:"icID,omitempty"` ICID uint `json:"icID,omitempty"`
StartParameters postgres.Jsonb `json:"startParameters,omitempty"` StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
SelectedModelFileID uint `json:"selectedModelFileID,omitempty"` SelectedFileID uint `json:"selectedFileID,omitempty"`
} }
type ICRequest struct { type ICRequest struct {
@ -66,7 +68,7 @@ func addScenarioAndIC() (scenarioID uint, ICID uint) {
// authenticate as admin // authenticate as admin
token, _ := helper.AuthenticateForTest(router, token, _ := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.AdminCredentials) base_api_auth, "POST", helper.AdminCredentials)
// POST $newICA // POST $newICA
newICA := ICRequest{ newICA := ICRequest{
@ -95,7 +97,7 @@ func addScenarioAndIC() (scenarioID uint, ICID uint) {
// authenticate as normal user // authenticate as normal user
token, _ = helper.AuthenticateForTest(router, token, _ = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
// POST $newScenario // POST $newScenario
newScenario := ScenarioRequest{ newScenario := ScenarioRequest{
@ -133,18 +135,18 @@ func TestMain(m *testing.M) {
user.RegisterAuthenticate(api.Group("/authenticate")) user.RegisterAuthenticate(api.Group("/authenticate"))
api.Use(user.Authentication(true)) api.Use(user.Authentication(true))
RegisterSimulationModelEndpoints(api.Group("/models")) RegisterComponentConfigurationEndpoints(api.Group("/configs"))
// scenario endpoints required here to first add a scenario to the DB // scenario endpoints required here to first add a scenario to the DB
// that can be associated with a new simulation model // that can be associated with a new component configuration
scenario.RegisterScenarioEndpoints(api.Group("/scenarios")) scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
// IC endpoints required here to first add a IC to the DB // IC endpoints required here to first add a IC to the DB
// that can be associated with a new simulation model // that can be associated with a new component configuration
infrastructure_component.RegisterICEndpoints(api.Group("/ic")) infrastructure_component.RegisterICEndpoints(api.Group("/ic"))
os.Exit(m.Run()) os.Exit(m.Run())
} }
func TestAddSimulationModel(t *testing.T) { func TestAddConfig(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -154,92 +156,92 @@ func TestAddSimulationModel(t *testing.T) {
// using the respective endpoints of the API // using the respective endpoints of the API
scenarioID, ICID := addScenarioAndIC() scenarioID, ICID := addScenarioAndIC()
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: scenarioID, ScenarioID: scenarioID,
ICID: ICID, ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID, SelectedFileID: database.ConfigA.SelectedFileID,
} }
// 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, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to POST with no access // try to POST with no access
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user // authenticate as normal user
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to POST non JSON body // try to POST non JSON body
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/models", "POST", "this is not JSON") base_api_configs, "POST", "this is not JSON")
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)
// authenticate as normal user // authenticate as normal user
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST models/ $newSimulationModel // test POST newConfig
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare POST's response with the newSimulationModel // Compare POST's response with the newConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": newSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
// Read newSimulationModel's ID from the response // Read newConfig's ID from the response
newSimulationModelID, err := helper.GetResponseID(resp) newConfigID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
// Get the newSimulationModel // Get the newConfig
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "GET", nil) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare GET's response with the newSimulationModel // Compare GET's response with the newConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": newSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
// try to POST a malformed simulation model // try to POST a malformed component config
// Required fields are missing // Required fields are missing
malformedNewSimulationModel := SimulationModelRequest{ malformedNewConfig := ConfigRequest{
Name: "ThisIsAMalformedRequest", Name: "ThisIsAMalformedRequest",
} }
// this should NOT work and return a unprocessable entity 442 status code // this should NOT work and return a unprocessable entity 442 status code
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": malformedNewSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": malformedNewConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// 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, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Try to GET the newSimulationModel with no access // Try to GET the newConfig with no access
// Should result in unprocessable entity // Should result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "GET", nil) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
} }
func TestUpdateSimulationModel(t *testing.T) { func TestUpdateConfig(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
@ -252,107 +254,107 @@ func TestUpdateSimulationModel(t *testing.T) {
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST models/ $newSimulationModel // test POST newConfig
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: scenarioID, ScenarioID: scenarioID,
ICID: ICID, ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID, SelectedFileID: database.ConfigA.SelectedFileID,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newSimulationModel's ID from the response // Read newConfig's ID from the response
newSimulationModelID, err := helper.GetResponseID(resp) newConfigID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
updatedSimulationModel := SimulationModelRequest{ updatedConfig := ConfigRequest{
Name: database.SimulationModelB.Name, Name: database.ConfigB.Name,
StartParameters: database.SimulationModelB.StartParameters, StartParameters: database.ConfigB.StartParameters,
} }
// 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, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to PUT with no access // try to PUT with no access
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", helper.KeyModels{"simulationModel": updatedSimulationModel}) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "PUT", helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as guest user who has access to simulation model // authenticate as guest user who has access to component config
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.GuestCredentials) base_api_auth, "POST", helper.GuestCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to PUT as guest // try to PUT as guest
// should NOT work and result in unprocessable entity // should NOT work and result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", helper.KeyModels{"simulationModel": updatedSimulationModel}) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "PUT", helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user // authenticate as normal user
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to PUT a non JSON body // try to PUT a non JSON body
// should result in a bad request // should result in a bad request
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", "This is not JSON") fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "PUT", "This is not JSON")
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)
// test PUT // test PUT
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", helper.KeyModels{"simulationModel": updatedSimulationModel}) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "PUT", helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare PUT's response with the updatedSimulationModel // Compare PUT's response with the updateConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": updatedSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
//Change IC ID to use second IC available in DB //Change IC ID to use second IC available in DB
updatedSimulationModel.ICID = ICID + 1 updatedConfig.ICID = ICID + 1
// test PUT again // test PUT again
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "PUT", helper.KeyModels{"simulationModel": updatedSimulationModel}) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "PUT", helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare PUT's response with the updatedSimulationModel // Compare PUT's response with the updateConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": updatedSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
// Get the updatedSimulationModel // Get the updateConfig
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "GET", nil) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare GET's response with the updatedSimulationModel // Compare GET's response with the updateConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": updatedSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": updatedConfig})
assert.NoError(t, err) assert.NoError(t, err)
// try to update a simulation model that does not exist (should return not found 404 status code) // try to update a component config that does not exist (should return not found 404 status code)
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID+1), "PUT", helper.KeyModels{"simulationModel": updatedSimulationModel}) fmt.Sprintf("%v/%v", base_api_configs, newConfigID+1), "PUT", helper.KeyModels{"config": updatedConfig})
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)
} }
func TestDeleteSimulationModel(t *testing.T) { func TestDeleteConfig(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -362,70 +364,70 @@ func TestDeleteSimulationModel(t *testing.T) {
// using the respective endpoints of the API // using the respective endpoints of the API
scenarioID, ICID := addScenarioAndIC() scenarioID, ICID := addScenarioAndIC()
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: scenarioID, ScenarioID: scenarioID,
ICID: ICID, ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID, SelectedFileID: database.ConfigA.SelectedFileID,
} }
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST models/ $newSimulationModel // test POST newConfig
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Read newSimulationModel's ID from the response // Read newConfig's ID from the response
newSimulationModelID, err := helper.GetResponseID(resp) newConfigID, err := helper.GetResponseID(resp)
assert.NoError(t, err) assert.NoError(t, err)
// 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, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to DELETE with no access // try to DELETE with no access
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "DELETE", nil) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "DELETE", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as normal user // authenticate as normal user
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all the simulation models returned for scenario // Count the number of all the component config returned for scenario
initialNumber, err := helper.LengthOfResponse(router, token, initialNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil) fmt.Sprintf("%v?scenarioID=%v", base_api_configs, scenarioID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// Delete the added newSimulationModel // Delete the added newConfig
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models/%v", newSimulationModelID), "DELETE", nil) fmt.Sprintf("%v/%v", base_api_configs, newConfigID), "DELETE", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Compare DELETE's response with the newSimulationModel // Compare DELETE's response with the newConfig
err = helper.CompareResponse(resp, helper.KeyModels{"simulationModel": newSimulationModel}) err = helper.CompareResponse(resp, helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
// Again count the number of all the simulation models returned // Again count the number of all the component configs returned
finalNumber, err := helper.LengthOfResponse(router, token, finalNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil) fmt.Sprintf("%v?scenarioID=%v", base_api_configs, scenarioID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumber-1, finalNumber) assert.Equal(t, initialNumber-1, finalNumber)
} }
func TestGetAllSimulationModelsOfScenario(t *testing.T) { func TestGetAllConfigsOfScenario(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -437,38 +439,38 @@ func TestGetAllSimulationModelsOfScenario(t *testing.T) {
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) base_api_auth, "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// test POST models/ $newSimulationModel // test POST newConfig
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: scenarioID, ScenarioID: scenarioID,
ICID: ICID, ICID: ICID,
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
SelectedModelFileID: database.SimulationModelA.SelectedModelFileID, SelectedFileID: database.ConfigA.SelectedFileID,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) base_api_configs, "POST", helper.KeyModels{"config": newConfig})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Count the number of all the simulation models returned for scenario // Count the number of all the component config returned for scenario
NumberOfSimulationModels, err := helper.LengthOfResponse(router, token, NumberOfConfigs, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil) fmt.Sprintf("%v?scenarioID=%v", base_api_configs, scenarioID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 1, NumberOfSimulationModels) assert.Equal(t, 1, NumberOfConfigs)
// authenticate as normal userB who has no access to scenario // authenticate as normal userB who has no access to scenario
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) base_api_auth, "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to get models without access // try to get configs without access
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/models?scenarioID=%v", scenarioID), "GET", nil) fmt.Sprintf("%v?scenarioID=%v", base_api_configs, scenarioID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)

View file

@ -0,0 +1,108 @@
/** component_configuration package, validators.
*
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASweb-backend-go
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
package component_configuration
import (
"encoding/json"
"github.com/jinzhu/gorm/dialects/postgres"
"github.com/nsf/jsondiff"
"gopkg.in/go-playground/validator.v9"
)
var validate *validator.Validate
type validNewConfig struct {
Name string `form:"Name" validate:"required"`
ScenarioID uint `form:"ScenarioID" validate:"required"`
ICID uint `form:"ICID" validate:"required"`
StartParameters postgres.Jsonb `form:"StartParameters" validate:"required"`
SelectedFileID uint `form:"SelectedFileID" validate:"omitempty"`
}
type validUpdatedConfig struct {
Name string `form:"Name" validate:"omitempty"`
ICID uint `form:"ICID" validate:"omitempty"`
StartParameters postgres.Jsonb `form:"StartParameters" validate:"omitempty"`
SelectedFileID uint `form:"SelectedFileID" validate:"omitempty"`
}
type addConfigRequest struct {
Config validNewConfig `json:"config"`
}
type updateConfigRequest struct {
Config validUpdatedConfig `json:"config"`
}
func (r *addConfigRequest) validate() error {
validate = validator.New()
errs := validate.Struct(r)
return errs
}
func (r *validUpdatedConfig) validate() error {
validate = validator.New()
errs := validate.Struct(r)
return errs
}
func (r *addConfigRequest) createConfig() ComponentConfiguration {
var s ComponentConfiguration
s.Name = r.Config.Name
s.ScenarioID = r.Config.ScenarioID
s.ICID = r.Config.ICID
s.StartParameters = r.Config.StartParameters
s.SelectedFileID = r.Config.SelectedFileID
return s
}
func (r *updateConfigRequest) updateConfig(oldConfig ComponentConfiguration) ComponentConfiguration {
// Use the old ComponentConfiguration as a basis for the updated config
s := oldConfig
if r.Config.Name != "" {
s.Name = r.Config.Name
}
if r.Config.ICID != 0 {
s.ICID = r.Config.ICID
}
if r.Config.SelectedFileID != 0 {
s.SelectedFileID = r.Config.SelectedFileID
}
// only update Params if not empty
var emptyJson postgres.Jsonb
// Serialize empty json and params
emptyJson_ser, _ := json.Marshal(emptyJson)
startParams_ser, _ := json.Marshal(r.Config.StartParameters)
opts := jsondiff.DefaultConsoleOptions()
diff, _ := jsondiff.Compare(emptyJson_ser, startParams_ser, &opts)
if diff.String() != "FullMatch" {
s.StartParameters = r.Config.StartParameters
}
return s
}

View file

@ -30,7 +30,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
) )
@ -43,23 +43,23 @@ func RegisterFileEndpoints(r *gin.RouterGroup) {
} }
// getFiles godoc // getFiles godoc
// @Summary Get all files of a specific model or widget // @Summary Get all files of a specific component configuration or widget
// @ID getFiles // @ID getFiles
// @Tags files // @Tags files
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseFiles "Files which belong to simulation model or widget" // @Success 200 {object} docs.ResponseFiles "Files which belong to config or widget"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param objectType query string true "Set to model for files of model, set to widget for files of widget" // @Param objectType query string true "Set to config for files of component configuration, set to widget for files of widget"
// @Param objectID query int true "ID of either model or widget of which files are requested" // @Param objectID query int true "ID of either config or widget of which files are requested"
// @Router /files [get] // @Router /files [get]
func getFiles(c *gin.Context) { func getFiles(c *gin.Context) {
var err error var err error
objectType := c.Request.URL.Query().Get("objectType") objectType := c.Request.URL.Query().Get("objectType")
if objectType != "model" && objectType != "widget" { if objectType != "config" && objectType != "widget" {
helper.BadRequestError(c, fmt.Sprintf("Object type not supported for files: %s", objectType)) helper.BadRequestError(c, fmt.Sprintf("Object type not supported for files: %s", objectType))
return return
} }
@ -72,10 +72,10 @@ func getFiles(c *gin.Context) {
//Check access //Check access
var ok bool var ok bool
var m simulationmodel.SimulationModel var m component_configuration.ComponentConfiguration
var w widget.Widget var w widget.Widget
if objectType == "model" { if objectType == "config" {
ok, m = simulationmodel.CheckPermissions(c, database.Read, "body", objectID) ok, m = component_configuration.CheckPermissions(c, database.Read, "body", objectID)
} else { } else {
ok, w = widget.CheckPermissions(c, database.Read, objectID) ok, w = widget.CheckPermissions(c, database.Read, objectID)
} }
@ -88,7 +88,7 @@ func getFiles(c *gin.Context) {
var files []database.File var files []database.File
if objectType == "model" { if objectType == "config" {
err = db.Order("ID asc").Model(&m).Related(&files, "Files").Error err = db.Order("ID asc").Model(&m).Related(&files, "Files").Error
} else { } else {
err = db.Order("ID asc").Model(&w).Related(&files, "Files").Error err = db.Order("ID asc").Model(&w).Related(&files, "Files").Error
@ -101,7 +101,7 @@ func getFiles(c *gin.Context) {
} }
// addFile godoc // addFile godoc
// @Summary Add a file to a specific model or widget // @Summary Add a file to a specific component config or widget
// @ID addFile // @ID addFile
// @Tags files // @Tags files
// @Produce json // @Produce json
@ -118,13 +118,13 @@ func getFiles(c *gin.Context) {
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param inputFile formData file true "File to be uploaded" // @Param inputFile formData file true "File to be uploaded"
// @Param objectType query string true "Set to model for files of model, set to widget for files of widget" // @Param objectType query string true "Set to config for files of component config, set to widget for files of widget"
// @Param objectID query int true "ID of either model or widget of which files are requested" // @Param objectID query int true "ID of either config or widget of which files are requested"
// @Router /files [post] // @Router /files [post]
func addFile(c *gin.Context) { func addFile(c *gin.Context) {
objectType := c.Request.URL.Query().Get("objectType") objectType := c.Request.URL.Query().Get("objectType")
if objectType != "model" && objectType != "widget" { if objectType != "config" && objectType != "widget" {
helper.BadRequestError(c, fmt.Sprintf("Object type not supported for files: %s", objectType)) helper.BadRequestError(c, fmt.Sprintf("Object type not supported for files: %s", objectType))
return return
} }
@ -137,8 +137,8 @@ func addFile(c *gin.Context) {
// Check access // Check access
var ok bool var ok bool
if objectType == "model" { if objectType == "config" {
ok, _ = simulationmodel.CheckPermissions(c, database.Update, "body", objectID) ok, _ = component_configuration.CheckPermissions(c, database.Update, "body", objectID)
if !ok { if !ok {
return return
} }

View file

@ -31,7 +31,7 @@ import (
"time" "time"
"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/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
) )
@ -84,14 +84,14 @@ func (f *File) register(fileHeader *multipart.FileHeader, objectType string, obj
f.ImageWidth = 0 // TODO: do we need this? f.ImageWidth = 0 // TODO: do we need this?
f.ImageHeight = 0 // TODO: do we need this? f.ImageHeight = 0 // TODO: do we need this?
var m simulationmodel.SimulationModel var m component_configuration.ComponentConfiguration
var w widget.Widget var w widget.Widget
var err error var err error
if objectType == "model" { if objectType == "config" {
// check if model exists // check if config exists
err = m.ByID(objectID) err = m.ByID(objectID)
f.WidgetID = 0 f.WidgetID = 0
f.SimulationModelID = objectID f.ConfigID = objectID
if err != nil { if err != nil {
return err return err
} }
@ -99,7 +99,7 @@ func (f *File) register(fileHeader *multipart.FileHeader, objectType string, obj
} else { } else {
// check if widget exists // check if widget exists
f.WidgetID = objectID f.WidgetID = objectID
f.SimulationModelID = 0 f.ConfigID = 0
err = w.ByID(uint(objectID)) err = w.ByID(uint(objectID))
if err != nil { if err != nil {
return err return err
@ -122,8 +122,8 @@ func (f *File) register(fileHeader *multipart.FileHeader, objectType string, obj
return err return err
} }
// Create association to model or widget // Create association to config or widget
if objectType == "model" { if objectType == "config" {
db := database.GetDB() db := database.GetDB()
err := db.Model(&m).Association("Files").Append(f).Error err := db.Model(&m).Association("Files").Append(f).Error
if err != nil { if err != nil {
@ -174,9 +174,9 @@ func (f *File) delete() error {
return err return err
} }
} else { } else {
// remove association between file and simulation model // remove association between file and config
var m simulationmodel.SimulationModel var m component_configuration.ComponentConfiguration
err := m.ByID(f.SimulationModelID) err := m.ByID(f.ConfigID)
if err != nil { if err != nil {
return err return err
} }

View file

@ -25,7 +25,7 @@ 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"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -50,8 +50,8 @@ func checkPermissions(c *gin.Context, operation database.CRUD) (bool, File) {
return false, f return false, f
} }
if f.SimulationModelID > 0 { if f.ConfigID > 0 {
ok, _ := simulationmodel.CheckPermissions(c, operation, "body", int(f.SimulationModelID)) ok, _ := component_configuration.CheckPermissions(c, operation, "body", int(f.ConfigID))
if !ok { if !ok {
return false, f return false, f
} }

View file

@ -27,10 +27,10 @@ import (
"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"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -49,7 +49,7 @@ import (
var router *gin.Engine var router *gin.Engine
var db *gorm.DB var db *gorm.DB
type SimulationModelRequest struct { type ConfigRequest struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
ScenarioID uint `json:"scenarioID,omitempty"` ScenarioID uint `json:"scenarioID,omitempty"`
ICID uint `json:"icID,omitempty"` ICID uint `json:"icID,omitempty"`
@ -91,7 +91,7 @@ type WidgetRequest struct {
CustomProperties postgres.Jsonb `json:"customProperties,omitempty"` CustomProperties postgres.Jsonb `json:"customProperties,omitempty"`
} }
func addScenarioAndICAndSimulationModelAndDashboardAndWidget() (scenarioID uint, ICID uint, simulationModelID uint, dashboardID uint, widgetID uint) { func addScenarioAndICAndConfigAndDashboardAndWidget() (scenarioID uint, ICID uint, configID uint, dashboardID uint, widgetID uint) {
// authenticate as admin // authenticate as admin
token, _ := helper.AuthenticateForTest(router, token, _ := helper.AuthenticateForTest(router,
@ -127,18 +127,18 @@ func addScenarioAndICAndSimulationModelAndDashboardAndWidget() (scenarioID uint,
// Read newScenario's ID from the response // Read newScenario's ID from the response
newScenarioID, _ := helper.GetResponseID(resp) newScenarioID, _ := helper.GetResponseID(resp)
// POST new simulation model // POST new component config
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: uint(newScenarioID), ScenarioID: uint(newScenarioID),
ICID: uint(newICID), ICID: uint(newICID),
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
} }
_, resp, _ = helper.TestEndpoint(router, token, _, resp, _ = helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) "/api/configs", "POST", helper.KeyModels{"config": newConfig})
// Read newSimulationModel's ID from the response // Read newConfig's ID from the response
newSimulationModelID, _ := helper.GetResponseID(resp) newConfigID, _ := helper.GetResponseID(resp)
// POST new dashboard // POST new dashboard
newDashboard := DashboardRequest{ newDashboard := DashboardRequest{
@ -177,7 +177,7 @@ func addScenarioAndICAndSimulationModelAndDashboardAndWidget() (scenarioID uint,
_, resp, _ = helper.TestEndpoint(router, token, _, resp, _ = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil) fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
return uint(newScenarioID), uint(newICID), uint(newSimulationModelID), uint(newDashboardID), uint(newWidgetID) return uint(newScenarioID), uint(newICID), uint(newConfigID), uint(newDashboardID), uint(newWidgetID)
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -196,14 +196,14 @@ func TestMain(m *testing.M) {
user.RegisterAuthenticate(api.Group("/authenticate")) user.RegisterAuthenticate(api.Group("/authenticate"))
api.Use(user.Authentication(true)) api.Use(user.Authentication(true))
// simulationmodel endpoints required here to first add a simulation to the DB // component-configuration endpoints required here to first add a config to the DB
// that can be associated with a new file // that can be associated with a new file
simulationmodel.RegisterSimulationModelEndpoints(api.Group("/models")) component_configuration.RegisterComponentConfigurationEndpoints(api.Group("/configs"))
// scenario endpoints required here to first add a scenario to the DB // scenario endpoints required here to first add a scenario to the DB
// that can be associated with a new simulation model // that can be associated with a new component config
scenario.RegisterScenarioEndpoints(api.Group("/scenarios")) scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
// IC endpoints required here to first add a IC to the DB // IC endpoints required here to first add a IC to the DB
// that can be associated with a new simulation model // that can be associated with a new component config
infrastructure_component.RegisterICEndpoints(api.Group("/ic")) infrastructure_component.RegisterICEndpoints(api.Group("/ic"))
// dashboard endpoints required here to first add a dashboard to the DB // dashboard endpoints required here to first add a dashboard to the DB
// that can be associated with a new widget // that can be associated with a new widget
@ -224,7 +224,7 @@ func TestAddFile(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID, _, widgetID := addScenarioAndICAndSimulationModelAndDashboardAndWidget() _, _, configID, _, widgetID := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as userB who has no access to the elements in the DB // authenticate as userB who has no access to the elements in the DB
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -233,10 +233,10 @@ func TestAddFile(t *testing.T) {
emptyBuf := &bytes.Buffer{} emptyBuf := &bytes.Buffer{}
// try to POST to a simulation model to which UserB has no access // try to POST to a component config to which UserB has no access
// should return a 422 unprocessable entity error // should return a 422 unprocessable entity error
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "POST", emptyBuf) fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), "POST", emptyBuf)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
@ -262,14 +262,14 @@ func TestAddFile(t *testing.T) {
// try to POST without an object ID // try to POST without an object 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/files?objectType=model"), "POST", emptyBuf) fmt.Sprintf("/api/files?objectType=config"), "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)
// try to POST an invalid file // try to POST an invalid file
// should return a bad request // should return a bad request
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "POST", emptyBuf) fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), "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)
@ -299,7 +299,7 @@ func TestAddFile(t *testing.T) {
// Create the request // Create the request
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), bodyBuf) req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), bodyBuf)
assert.NoError(t, err, "create request") assert.NoError(t, err, "create request")
req.Header.Set("Content-Type", contentType) req.Header.Set("Content-Type", contentType)
@ -340,7 +340,7 @@ func TestUpdateFile(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID, _, _ := addScenarioAndICAndSimulationModelAndDashboardAndWidget() _, _, configID, _, _ := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -372,7 +372,7 @@ func TestUpdateFile(t *testing.T) {
// Create the POST request // Create the POST request
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), bodyBuf) req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), bodyBuf)
assert.NoError(t, err, "create request") assert.NoError(t, err, "create request")
req.Header.Set("Content-Type", contentType) req.Header.Set("Content-Type", contentType)
@ -474,7 +474,7 @@ func TestDeleteFile(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID, _, widgetID := addScenarioAndICAndSimulationModelAndDashboardAndWidget() _, _, configID, _, widgetID := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -504,7 +504,7 @@ func TestDeleteFile(t *testing.T) {
// Create the request // Create the request
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), bodyBuf) req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), bodyBuf)
assert.NoError(t, err, "create request") assert.NoError(t, err, "create request")
req.Header.Set("Content-Type", contentType) req.Header.Set("Content-Type", contentType)
req.Header.Add("Authorization", "Bearer "+token) req.Header.Add("Authorization", "Bearer "+token)
@ -542,7 +542,7 @@ func TestDeleteFile(t *testing.T) {
"/api/authenticate", "POST", helper.UserBCredentials) "/api/authenticate", "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to DELETE file of simulation model to which userB has no access // try to DELETE file of component config to which userB has no access
// should return an unprocessable entity error // should return an unprocessable entity error
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files/%v", newFileID), "DELETE", nil) fmt.Sprintf("/api/files/%v", newFileID), "DELETE", nil)
@ -561,9 +561,9 @@ func TestDeleteFile(t *testing.T) {
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all files returned for simulation model // Count the number of all files returned for component config
initialNumber, err := helper.LengthOfResponse(router, token, initialNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// try to DELETE non-existing fileID // try to DELETE non-existing fileID
@ -578,7 +578,7 @@ func TestDeleteFile(t *testing.T) {
"/api/authenticate", "POST", helper.GuestCredentials) "/api/authenticate", "POST", helper.GuestCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to DELETE file of simulation model as guest // try to DELETE file of component config as guest
// should return an unprocessable entity error // should return an unprocessable entity error
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files/%v", newFileID), "DELETE", nil) fmt.Sprintf("/api/files/%v", newFileID), "DELETE", nil)
@ -609,15 +609,15 @@ func TestDeleteFile(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Again count the number of all the files returned for simulation model // Again count the number of all the files returned for component config
finalNumber, err := helper.LengthOfResponse(router, token, finalNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=config", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumber-1, finalNumber) assert.Equal(t, initialNumber-1, finalNumber)
} }
func TestGetAllFilesOfSimulationModel(t *testing.T) { func TestGetAllFilesOfConfig(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
@ -625,17 +625,17 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID, _, widgetID := addScenarioAndICAndSimulationModelAndDashboardAndWidget() _, _, ConfigID, _, widgetID := addScenarioAndICAndConfigAndDashboardAndWidget()
// authenticate as userB who has no access to the elements in the DB // authenticate as userB who has no access to the elements in the DB
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserBCredentials) "/api/authenticate", "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to get all files for simulation model to which userB has not access // try to get all files for component config to which userB has not access
// should return unprocessable entity error // should return unprocessable entity error
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
@ -653,19 +653,19 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
//try to get all files for unsupported object type; should return a bad request error //try to get all files for unsupported object type; should return a bad request error
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=wrongtype", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=wrongtype", ConfigID), "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)
//try to get all files with missing object ID; should return a bad request error //try to get all files with missing object ID; should return a bad request error
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/files?objectType=model"), "GET", nil) fmt.Sprintf("/api/files?objectType=config"), "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)
// Count the number of all files returned for simulation model // Count the number of all files returned for component config
initialNumberModel, err := helper.LengthOfResponse(router, token, initialNumberConfig, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all files returned for widget // Count the number of all files returned for widget
@ -683,30 +683,30 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
assert.NoError(t, err, "opening file") assert.NoError(t, err, "opening file")
defer fh.Close() defer fh.Close()
// test POST a file to simulation model and widget // test POST a file to component config and widget
bodyBufModel1 := &bytes.Buffer{} bodyBufConfig1 := &bytes.Buffer{}
bodyBufWidget1 := &bytes.Buffer{} bodyBufWidget1 := &bytes.Buffer{}
bodyWriterModel1 := multipart.NewWriter(bodyBufModel1) bodyWriterConfig1 := multipart.NewWriter(bodyBufConfig1)
bodyWriterWidget1 := multipart.NewWriter(bodyBufWidget1) bodyWriterWidget1 := multipart.NewWriter(bodyBufWidget1)
fileWriterModel1, err := bodyWriterModel1.CreateFormFile("file", "testuploadfile.txt") fileWriterConfig1, err := bodyWriterConfig1.CreateFormFile("file", "testuploadfile.txt")
assert.NoError(t, err, "writing to buffer") assert.NoError(t, err, "writing to buffer")
fileWriterWidget1, err := bodyWriterWidget1.CreateFormFile("file", "testuploadfile.txt") fileWriterWidget1, err := bodyWriterWidget1.CreateFormFile("file", "testuploadfile.txt")
assert.NoError(t, err, "writing to buffer") assert.NoError(t, err, "writing to buffer")
// io copy // io copy
_, err = io.Copy(fileWriterModel1, fh) _, err = io.Copy(fileWriterConfig1, fh)
assert.NoError(t, err, "IO copy") assert.NoError(t, err, "IO copy")
_, err = io.Copy(fileWriterWidget1, fh) _, err = io.Copy(fileWriterWidget1, fh)
assert.NoError(t, err, "IO copy") assert.NoError(t, err, "IO copy")
contentTypeModel1 := bodyWriterModel1.FormDataContentType() contentTypeConfig1 := bodyWriterConfig1.FormDataContentType()
contentTypeWidget1 := bodyWriterWidget1.FormDataContentType() contentTypeWidget1 := bodyWriterWidget1.FormDataContentType()
bodyWriterModel1.Close() bodyWriterConfig1.Close()
bodyWriterWidget1.Close() bodyWriterWidget1.Close()
// Create the request for simulation model // Create the request for component config
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), bodyBufModel1) req, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), bodyBufConfig1)
assert.NoError(t, err, "create request") assert.NoError(t, err, "create request")
req.Header.Set("Content-Type", contentTypeModel1) req.Header.Set("Content-Type", contentTypeConfig1)
req.Header.Add("Authorization", "Bearer "+token) req.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w, req) router.ServeHTTP(w, req)
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)
@ -720,36 +720,36 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
router.ServeHTTP(w2, req2) router.ServeHTTP(w2, req2)
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)
// POST a second file to simulation model and widget // POST a second file to component config and widget
// open a second file handle // open a second file handle
fh2, err := os.Open("testfile.txt") fh2, err := os.Open("testfile.txt")
assert.NoError(t, err, "opening file") assert.NoError(t, err, "opening file")
defer fh2.Close() defer fh2.Close()
bodyBufModel2 := &bytes.Buffer{} bodyBufConfig2 := &bytes.Buffer{}
bodyBufWidget2 := &bytes.Buffer{} bodyBufWidget2 := &bytes.Buffer{}
bodyWriterModel2 := multipart.NewWriter(bodyBufModel2) bodyWriterConfig2 := multipart.NewWriter(bodyBufConfig2)
bodyWriterWidget2 := multipart.NewWriter(bodyBufWidget2) bodyWriterWidget2 := multipart.NewWriter(bodyBufWidget2)
fileWriterModel2, err := bodyWriterModel2.CreateFormFile("file", "testuploadfile2.txt") fileWriterConfig2, err := bodyWriterConfig2.CreateFormFile("file", "testuploadfile2.txt")
assert.NoError(t, err, "writing to buffer") assert.NoError(t, err, "writing to buffer")
fileWriterWidget2, err := bodyWriterWidget2.CreateFormFile("file", "testuploadfile2.txt") fileWriterWidget2, err := bodyWriterWidget2.CreateFormFile("file", "testuploadfile2.txt")
assert.NoError(t, err, "writing to buffer") assert.NoError(t, err, "writing to buffer")
// io copy // io copy
_, err = io.Copy(fileWriterModel2, fh2) _, err = io.Copy(fileWriterConfig2, fh2)
assert.NoError(t, err, "IO copy") assert.NoError(t, err, "IO copy")
_, err = io.Copy(fileWriterWidget2, fh2) _, err = io.Copy(fileWriterWidget2, fh2)
assert.NoError(t, err, "IO copy") assert.NoError(t, err, "IO copy")
contentTypeModel2 := bodyWriterModel2.FormDataContentType() contentTypeConfig2 := bodyWriterConfig2.FormDataContentType()
contentTypeWidget2 := bodyWriterWidget2.FormDataContentType() contentTypeWidget2 := bodyWriterWidget2.FormDataContentType()
bodyWriterModel2.Close() bodyWriterConfig2.Close()
bodyWriterWidget2.Close() bodyWriterWidget2.Close()
w3 := httptest.NewRecorder() w3 := httptest.NewRecorder()
req3, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), bodyBufModel2) req3, err := http.NewRequest("POST", fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), bodyBufConfig2)
assert.NoError(t, err, "create request") assert.NoError(t, err, "create request")
req3.Header.Set("Content-Type", contentTypeModel2) req3.Header.Set("Content-Type", contentTypeConfig2)
req3.Header.Add("Authorization", "Bearer "+token) req3.Header.Add("Authorization", "Bearer "+token)
router.ServeHTTP(w3, req3) router.ServeHTTP(w3, req3)
assert.Equalf(t, 200, w3.Code, "Response body: \n%v\n", w3.Body) assert.Equalf(t, 200, w3.Code, "Response body: \n%v\n", w3.Body)
@ -762,11 +762,11 @@ func TestGetAllFilesOfSimulationModel(t *testing.T) {
router.ServeHTTP(w4, req4) router.ServeHTTP(w4, req4)
assert.Equalf(t, 200, w4.Code, "Response body: \n%v\n", w4.Body) assert.Equalf(t, 200, w4.Code, "Response body: \n%v\n", w4.Body)
// Again count the number of all the files returned for simulation model // Again count the number of all the files returned for component config
finalNumberModel, err := helper.LengthOfResponse(router, token, finalNumberConfig, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/files?objectID=%v&objectType=model", simulationModelID), "GET", nil) fmt.Sprintf("/api/files?objectID=%v&objectType=config", ConfigID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumberModel+2, finalNumberModel) assert.Equal(t, initialNumberConfig+2, finalNumberConfig)
// Again count the number of all the files returned for widget // Again count the number of all the files returned for widget
finalNumberWidget, err := helper.LengthOfResponse(router, token, finalNumberWidget, err := helper.LengthOfResponse(router, token,

View file

@ -209,7 +209,7 @@ func deleteIC(c *gin.Context) {
// @ID getConfigsOfIC // @ID getConfigsOfIC
// @Tags infrastructure-components // @Tags infrastructure-components
// @Produce json // @Produce json
// @Success 200 {object} docs.ResponseSimulationModels "Configs requested by user" // @Success 200 {object} docs.ResponseConfigs "Configs requested by user"
// @Failure 400 {object} docs.ResponseError "Bad request" // @Failure 400 {object} docs.ResponseError "Bad request"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"

View file

@ -54,10 +54,10 @@ func (s *InfrastructureComponent) update(updatedIC InfrastructureComponent) erro
func (s *InfrastructureComponent) delete() error { func (s *InfrastructureComponent) delete() error {
db := database.GetDB() db := database.GetDB()
no_configs := db.Model(s).Association("SimulationModels").Count() no_configs := db.Model(s).Association("ComponentConfigurations").Count()
if no_configs > 0 { if no_configs > 0 {
return fmt.Errorf("InfrastructureComponent cannot be deleted as it is still used in configurations (active or dangling)") return fmt.Errorf("Infrastructure Component cannot be deleted as it is still used in configurations (active or dangling)")
} }
// delete InfrastructureComponent from DB (does NOT remain as dangling) // delete InfrastructureComponent from DB (does NOT remain as dangling)
@ -65,9 +65,9 @@ func (s *InfrastructureComponent) delete() error {
return err return err
} }
func (s *InfrastructureComponent) getConfigs() ([]database.SimulationModel, int, error) { func (s *InfrastructureComponent) getConfigs() ([]database.ComponentConfiguration, int, error) {
db := database.GetDB() db := database.GetDB()
var configs []database.SimulationModel var configs []database.ComponentConfiguration
err := db.Order("ID asc").Model(s).Related(&configs, "SimulationModels").Error err := db.Order("ID asc").Model(s).Related(&configs, "ComponentConfigurations").Error
return configs, len(configs), err return configs, len(configs), err
} }

View file

@ -448,7 +448,7 @@ func TestGetConfigsOfIC(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
// test GET ic/ID/confis // test GET ic/ID/confis
// TODO how to properly test this without using simulation model endpoints? // TODO how to properly test this without using component configuration endpoints?
numberOfConfigs, err := helper.LengthOfResponse(router, token, numberOfConfigs, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/ic/%v/configs", newICID), "GET", nil) fmt.Sprintf("/api/ic/%v/configs", newICID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
@ -462,7 +462,7 @@ func TestGetConfigsOfIC(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
// test GET ic/ID/configs // test GET ic/ID/configs
// TODO how to properly test this without using simulation model endpoints? // TODO how to properly test this without using component configuration endpoints?
numberOfConfigs, err = helper.LengthOfResponse(router, token, numberOfConfigs, err = helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/ic/%v/configs", newICID), "GET", nil) fmt.Sprintf("/api/ic/%v/configs", newICID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)

View file

@ -37,10 +37,10 @@ var (
}, },
) )
SimulationModelCounter = prometheus.NewCounter( ComponentConfigurationCounter = prometheus.NewCounter(
prometheus.CounterOpts{ prometheus.CounterOpts{
Name: "simulation_models", Name: "component_configurations",
Help: "A counter for the total number of simulation models", Help: "A counter for the total number of component configurations",
}, },
) )
@ -103,7 +103,7 @@ func RegisterMetricsEndpoint(rg *gin.RouterGroup) {
// Register metrics // Register metrics
prometheus.MustRegister( prometheus.MustRegister(
ICCounter, ICCounter,
SimulationModelCounter, ComponentConfigurationCounter,
FileCounter, FileCounter,
ScenarioCounter, ScenarioCounter,
UserCounter, UserCounter,
@ -112,17 +112,17 @@ func RegisterMetricsEndpoint(rg *gin.RouterGroup) {
} }
func InitCounters(db *gorm.DB) { func InitCounters(db *gorm.DB) {
var infrastructure_components, simulation_models, files, scenarios, users, dashboards float64 var infrastructure_components, component_configurations, files, scenarios, users, dashboards float64
db.Table("infrastructure_components").Count(&infrastructure_components) db.Table("infrastructure_components").Count(&infrastructure_components)
db.Table("simulation_models").Count(&simulation_models) db.Table("component_configurations").Count(&component_configurations)
db.Table("files").Count(&files) db.Table("files").Count(&files)
db.Table("scenarios").Count(&scenarios) db.Table("scenarios").Count(&scenarios)
db.Table("users").Count(&users) db.Table("users").Count(&users)
db.Table("dashboards").Count(&dashboards) db.Table("dashboards").Count(&dashboards)
ICCounter.Add(infrastructure_components) ICCounter.Add(infrastructure_components)
SimulationModelCounter.Add(simulation_models) ComponentConfigurationCounter.Add(component_configurations)
FileCounter.Add(files) FileCounter.Add(files)
ScenarioCounter.Add(scenarios) ScenarioCounter.Add(scenarios)
UserCounter.Add(users) UserCounter.Add(users)

View file

@ -82,7 +82,7 @@ func getScenarios(c *gin.Context) {
return return
} }
} }
// TODO return list of simulationModelIDs, dashboardIDs and userIDs per scenario // TODO return list of configIDs, dashboardIDs and userIDs per scenario
c.JSON(http.StatusOK, gin.H{"scenarios": scenarios}) c.JSON(http.StatusOK, gin.H{"scenarios": scenarios})
} }
@ -211,7 +211,7 @@ func getScenario(c *gin.Context) {
return return
} }
// TODO return list of simulationModelIDs, dashboardIDs and userIDs per scenario // TODO return list of configIDs, dashboardIDs and userIDs per scenario
c.JSON(http.StatusOK, gin.H{"scenario": so.Scenario}) c.JSON(http.StatusOK, gin.H{"scenario": so.Scenario})
} }

View file

@ -28,7 +28,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
) )
func RegisterSignalEndpoints(r *gin.RouterGroup) { func RegisterSignalEndpoints(r *gin.RouterGroup) {
@ -45,8 +45,8 @@ func RegisterSignalEndpoints(r *gin.RouterGroup) {
// @Produce json // @Produce json
// @Tags signals // @Tags signals
// @Param direction query string true "Direction of signal (in or out)" // @Param direction query string true "Direction of signal (in or out)"
// @Param modelID query string true "Model ID of signals to be obtained" // @Param configID query string true "Config ID of signals to be obtained"
// @Success 200 {object} docs.ResponseSignals "Signals which belong to simulation model" // @Success 200 {object} docs.ResponseSignals "Signals which belong to component configuration"
// @Failure 404 {object} docs.ResponseError "Not found" // @Failure 404 {object} docs.ResponseError "Not found"
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
@ -54,7 +54,7 @@ func RegisterSignalEndpoints(r *gin.RouterGroup) {
// @Router /signals [get] // @Router /signals [get]
func getSignals(c *gin.Context) { func getSignals(c *gin.Context) {
ok, m := simulationmodel.CheckPermissions(c, database.Read, "query", -1) ok, m := component_configuration.CheckPermissions(c, database.Read, "query", -1)
if !ok { if !ok {
return return
} }
@ -80,7 +80,7 @@ func getSignals(c *gin.Context) {
} }
// AddSignal godoc // AddSignal godoc
// @Summary Add a signal to a signal mapping of a model // @Summary Add a signal to a signal mapping of a component configuration
// @ID AddSignal // @ID AddSignal
// @Accept json // @Accept json
// @Produce json // @Produce json
@ -91,7 +91,7 @@ func getSignals(c *gin.Context) {
// @Failure 422 {object} docs.ResponseError "Unprocessable entity" // @Failure 422 {object} docs.ResponseError "Unprocessable entity"
// @Failure 500 {object} docs.ResponseError "Internal server error" // @Failure 500 {object} docs.ResponseError "Internal server error"
// @Param Authorization header string true "Authorization token" // @Param Authorization header string true "Authorization token"
// @Param inputSignal body signal.addSignalRequest true "A signal to be added to the model incl. direction and model ID to which signal shall be added" // @Param inputSignal body signal.addSignalRequest true "A signal to be added to the component configuration incl. direction and config ID to which signal shall be added"
// @Router /signals [post] // @Router /signals [post]
func addSignal(c *gin.Context) { func addSignal(c *gin.Context) {
@ -110,13 +110,13 @@ func addSignal(c *gin.Context) {
// Create the new signal from the request // Create the new signal from the request
newSignal := req.createSignal() newSignal := req.createSignal()
ok, _ := simulationmodel.CheckPermissions(c, database.Update, "body", int(newSignal.SimulationModelID)) ok, _ := component_configuration.CheckPermissions(c, database.Update, "body", int(newSignal.ConfigID))
if !ok { if !ok {
return return
} }
// Add signal to model // Add signal to component configuration
err := newSignal.addToSimulationModel() err := newSignal.addToConfig()
if !helper.DBError(c, err) { if !helper.DBError(c, err) {
c.JSON(http.StatusOK, gin.H{"signal": newSignal.Signal}) c.JSON(http.StatusOK, gin.H{"signal": newSignal.Signal})
} }

View file

@ -23,7 +23,7 @@ package signal
import ( import (
"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/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
) )
type Signal struct { type Signal struct {
@ -45,10 +45,10 @@ func (s *Signal) byID(id uint) error {
return nil return nil
} }
func (s *Signal) addToSimulationModel() error { func (s *Signal) addToConfig() error {
db := database.GetDB() db := database.GetDB()
var m simulationmodel.SimulationModel var m component_configuration.ComponentConfiguration
err := m.ByID(s.SimulationModelID) err := m.ByID(s.ConfigID)
if err != nil { if err != nil {
return err return err
} }
@ -59,7 +59,7 @@ func (s *Signal) addToSimulationModel() error {
return err return err
} }
// associate signal with simulation model in correct direction // associate signal with component configuration in correct direction
if s.Direction == "in" { if s.Direction == "in" {
err = db.Model(&m).Association("InputMapping").Append(s).Error err = db.Model(&m).Association("InputMapping").Append(s).Error
if err != nil { if err != nil {
@ -99,13 +99,13 @@ func (s *Signal) update(modifiedSignal Signal) error {
func (s *Signal) delete() error { func (s *Signal) delete() error {
db := database.GetDB() db := database.GetDB()
var m simulationmodel.SimulationModel var m component_configuration.ComponentConfiguration
err := m.ByID(s.SimulationModelID) err := m.ByID(s.ConfigID)
if err != nil { if err != nil {
return err return err
} }
// remove association between Signal and SimulationModel // remove association between Signal and ComponentConfiguration
// Signal itself is not deleted from DB, it remains as "dangling" // Signal itself is not deleted from DB, it remains as "dangling"
if s.Direction == "in" { if s.Direction == "in" {
err = db.Model(&m).Association("InputMapping").Delete(s).Error err = db.Model(&m).Association("InputMapping").Delete(s).Error

View file

@ -27,7 +27,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database" "git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
) )
func checkPermissions(c *gin.Context, operation database.CRUD) (bool, Signal) { func checkPermissions(c *gin.Context, operation database.CRUD) (bool, Signal) {
@ -50,7 +50,7 @@ func checkPermissions(c *gin.Context, operation database.CRUD) (bool, Signal) {
return false, sig return false, sig
} }
ok, _ := simulationmodel.CheckPermissions(c, operation, "body", int(sig.SimulationModelID)) ok, _ := component_configuration.CheckPermissions(c, operation, "body", int(sig.ConfigID))
if !ok { if !ok {
return false, sig return false, sig
} }

View file

@ -26,9 +26,9 @@ import (
"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"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper" "git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
@ -46,10 +46,10 @@ type SignalRequest struct {
Unit string `json:"unit,omitempty"` Unit string `json:"unit,omitempty"`
Index uint `json:"index,omitempty"` Index uint `json:"index,omitempty"`
Direction string `json:"direction,omitempty"` Direction string `json:"direction,omitempty"`
SimulationModelID uint `json:"simulationModelID,omitempty"` ConfigID uint `json:"configID,omitempty"`
} }
type SimulationModelRequest struct { type ConfigRequest struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
ScenarioID uint `json:"scenarioID,omitempty"` ScenarioID uint `json:"scenarioID,omitempty"`
ICID uint `json:"icID,omitempty"` ICID uint `json:"icID,omitempty"`
@ -70,7 +70,7 @@ type ScenarioRequest struct {
StartParameters postgres.Jsonb `json:"startParameters,omitempty"` StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
} }
func addScenarioAndICAndSimulationModel() (scenarioID uint, ICID uint, simulationModelID uint) { func addScenarioAndICAndConfig() (scenarioID uint, ICID uint, configID uint) {
// authenticate as admin // authenticate as admin
token, _ := helper.AuthenticateForTest(router, token, _ := helper.AuthenticateForTest(router,
@ -106,24 +106,24 @@ func addScenarioAndICAndSimulationModel() (scenarioID uint, ICID uint, simulatio
// Read newScenario's ID from the response // Read newScenario's ID from the response
newScenarioID, _ := helper.GetResponseID(resp) newScenarioID, _ := helper.GetResponseID(resp)
// test POST models/ $newSimulationModel // test POST newConfig
newSimulationModel := SimulationModelRequest{ newConfig := ConfigRequest{
Name: database.SimulationModelA.Name, Name: database.ConfigA.Name,
ScenarioID: uint(newScenarioID), ScenarioID: uint(newScenarioID),
ICID: uint(newICID), ICID: uint(newICID),
StartParameters: database.SimulationModelA.StartParameters, StartParameters: database.ConfigA.StartParameters,
} }
_, resp, _ = helper.TestEndpoint(router, token, _, resp, _ = helper.TestEndpoint(router, token,
"/api/models", "POST", helper.KeyModels{"simulationModel": newSimulationModel}) "/api/configs", "POST", helper.KeyModels{"config": newConfig})
// Read newSimulationModel's ID from the response // Read newConfig's ID from the response
newSimulationModelID, _ := 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, _, resp, _ = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil) fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
return uint(newScenarioID), uint(newICID), uint(newSimulationModelID) return uint(newScenarioID), uint(newICID), uint(newConfigID)
} }
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -143,14 +143,14 @@ func TestMain(m *testing.M) {
user.RegisterAuthenticate(api.Group("/authenticate")) user.RegisterAuthenticate(api.Group("/authenticate"))
api.Use(user.Authentication(true)) api.Use(user.Authentication(true))
// simulationmodel endpoints required here to first add a simulation to the DB // component-configuration endpoints required here to first add a component config to the DB
// that can be associated with a new signal model // that can be associated with a new signal
simulationmodel.RegisterSimulationModelEndpoints(api.Group("/models")) component_configuration.RegisterComponentConfigurationEndpoints(api.Group("/configs"))
// scenario endpoints required here to first add a scenario to the DB // scenario endpoints required here to first add a scenario to the DB
// that can be associated with a new simulation model // that can be associated with a new component config
scenario.RegisterScenarioEndpoints(api.Group("/scenarios")) scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
// IC endpoints required here to first add a IC to the DB // IC endpoints required here to first add a IC to the DB
// that can be associated with a new simulation model // that can be associated with a new component config
infrastructure_component.RegisterICEndpoints(api.Group("/ic")) infrastructure_component.RegisterICEndpoints(api.Group("/ic"))
RegisterSignalEndpoints(api.Group("/signals")) RegisterSignalEndpoints(api.Group("/signals"))
@ -165,7 +165,7 @@ func TestAddSignal(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a IC to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndICAndSimulationModel() _, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -177,7 +177,7 @@ func TestAddSignal(t *testing.T) {
Unit: database.InSignalA.Unit, Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction, Direction: database.InSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
// authenticate as normal userB who has no access to new scenario // authenticate as normal userB who has no access to new scenario
@ -185,7 +185,7 @@ func TestAddSignal(t *testing.T) {
"/api/authenticate", "POST", helper.UserBCredentials) "/api/authenticate", "POST", helper.UserBCredentials)
assert.NoError(t, err) assert.NoError(t, err)
// try to POST to simulation model without access // try to POST to component config without access
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignal}) "/api/signals", "POST", helper.KeyModels{"signal": newSignal})
@ -260,7 +260,7 @@ func TestUpdateSignal(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a IC to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndICAndSimulationModel() _, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -273,7 +273,7 @@ func TestUpdateSignal(t *testing.T) {
Unit: database.InSignalA.Unit, Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction, Direction: database.InSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignal}) "/api/signals", "POST", helper.KeyModels{"signal": newSignal})
@ -362,7 +362,7 @@ func TestDeleteSignal(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a IC to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndICAndSimulationModel() _, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
@ -375,7 +375,7 @@ func TestDeleteSignal(t *testing.T) {
Unit: database.InSignalA.Unit, Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction, Direction: database.InSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignal}) "/api/signals", "POST", helper.KeyModels{"signal": newSignal})
@ -403,9 +403,9 @@ func TestDeleteSignal(t *testing.T) {
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all the input signals returned for simulation model // Count the number of all the input signals returned for component config
initialNumber, err := helper.LengthOfResponse(router, token, initialNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=in", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=in", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// add an output signal to make sure that counting of input signals works // add an output signal to make sure that counting of input signals works
@ -414,7 +414,7 @@ func TestDeleteSignal(t *testing.T) {
Unit: database.OutSignalA.Unit, Unit: database.OutSignalA.Unit,
Direction: database.OutSignalA.Direction, Direction: database.OutSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalout}) "/api/signals", "POST", helper.KeyModels{"signal": newSignalout})
@ -435,9 +435,9 @@ func TestDeleteSignal(t *testing.T) {
err = helper.CompareResponse(resp, helper.KeyModels{"signal": newSignal}) err = helper.CompareResponse(resp, helper.KeyModels{"signal": newSignal})
assert.NoError(t, err) assert.NoError(t, err)
// Again count the number of all the input signals returned for simulation model // Again count the number of all the input signals returned for component config
finalNumber, err := helper.LengthOfResponse(router, token, finalNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=in", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=in", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumber-1, finalNumber) assert.Equal(t, initialNumber-1, finalNumber)
@ -449,7 +449,7 @@ func TestDeleteSignal(t *testing.T) {
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
} }
func TestGetAllInputSignalsOfSimulationModel(t *testing.T) { func TestGetAllInputSignalsOfConfig(t *testing.T) {
database.DropTables(db) database.DropTables(db)
database.MigrateModels(db) database.MigrateModels(db)
assert.NoError(t, database.DBAddAdminAndUserAndGuest(db)) assert.NoError(t, database.DBAddAdminAndUserAndGuest(db))
@ -457,16 +457,16 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
// prepare the content of the DB for testing // prepare the content of the DB for testing
// by adding a scenario and a IC to the DB // by adding a scenario and a IC to the DB
// using the respective endpoints of the API // using the respective endpoints of the API
_, _, simulationModelID := addScenarioAndICAndSimulationModel() _, _, configID := addScenarioAndICAndConfig()
// authenticate as normal user // authenticate as normal user
token, err := helper.AuthenticateForTest(router, token, err := helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.UserACredentials) "/api/authenticate", "POST", helper.UserACredentials)
assert.NoError(t, err) assert.NoError(t, err)
// Count the number of all the input signals returned for simulation model // Count the number of all the input signals returned for component config
initialNumber, err := helper.LengthOfResponse(router, token, initialNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=in", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=in", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
// test POST signals/ $newSignal // test POST signals/ $newSignal
@ -475,7 +475,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.InSignalA.Unit, Unit: database.InSignalA.Unit,
Direction: database.InSignalA.Direction, Direction: database.InSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err := helper.TestEndpoint(router, token, code, resp, err := helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalA}) "/api/signals", "POST", helper.KeyModels{"signal": newSignalA})
@ -488,7 +488,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.InSignalB.Unit, Unit: database.InSignalB.Unit,
Direction: database.InSignalB.Direction, Direction: database.InSignalB.Direction,
Index: 2, Index: 2,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalB}) "/api/signals", "POST", helper.KeyModels{"signal": newSignalB})
@ -501,7 +501,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.OutSignalA.Unit, Unit: database.OutSignalA.Unit,
Direction: database.OutSignalA.Direction, Direction: database.OutSignalA.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalAout}) "/api/signals", "POST", helper.KeyModels{"signal": newSignalAout})
@ -514,30 +514,30 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
Unit: database.OutSignalB.Unit, Unit: database.OutSignalB.Unit,
Direction: database.OutSignalB.Direction, Direction: database.OutSignalB.Direction,
Index: 1, Index: 1,
SimulationModelID: simulationModelID, ConfigID: configID,
} }
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
"/api/signals", "POST", helper.KeyModels{"signal": newSignalBout}) "/api/signals", "POST", helper.KeyModels{"signal": newSignalBout})
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 200, code, "Response body: \n%v\n", resp) assert.Equalf(t, 200, code, "Response body: \n%v\n", resp)
// Again count the number of all the input signals returned for simulation model // Again count the number of all the input signals returned for component config
finalNumber, err := helper.LengthOfResponse(router, token, finalNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=in", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=in", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumber+2, finalNumber) assert.Equal(t, initialNumber+2, finalNumber)
// Get the number of output signals // Get the number of output signals
outputNumber, err := helper.LengthOfResponse(router, token, outputNumber, err := helper.LengthOfResponse(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=out", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=out", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, initialNumber+2, outputNumber) assert.Equal(t, initialNumber+2, outputNumber)
// Try to get all signals for non-existing direction // Try to get all signals for non-existing direction
// 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/signals?modelID=%v&direction=thisiswrong", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=thisiswrong", configID), "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)
@ -549,7 +549,7 @@ func TestGetAllInputSignalsOfSimulationModel(t *testing.T) {
// try to get all input signals // try to get all input signals
// should result in unprocessable entity // should result in unprocessable entity
code, resp, err = helper.TestEndpoint(router, token, code, resp, err = helper.TestEndpoint(router, token,
fmt.Sprintf("/api/signals?modelID=%v&direction=in", simulationModelID), "GET", nil) fmt.Sprintf("/api/signals?configID=%v&direction=in", configID), "GET", nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)

View file

@ -32,7 +32,7 @@ type validNewSignal struct {
Unit string `form:"unit" validate:"omitempty"` Unit string `form:"unit" validate:"omitempty"`
Index uint `form:"index" validate:"required"` Index uint `form:"index" validate:"required"`
Direction string `form:"direction" validate:"required,oneof=in out"` Direction string `form:"direction" validate:"required,oneof=in out"`
SimulationModelID uint `form:"simulationModelID" validate:"required"` ConfigID uint `form:"configID" validate:"required"`
} }
type validUpdatedSignal struct { type validUpdatedSignal struct {
@ -68,7 +68,7 @@ func (r *addSignalRequest) createSignal() Signal {
s.Unit = r.Signal.Unit s.Unit = r.Signal.Unit
s.Index = r.Signal.Index s.Index = r.Signal.Index
s.Direction = r.Signal.Direction s.Direction = r.Signal.Direction
s.SimulationModelID = r.Signal.SimulationModelID s.ConfigID = r.Signal.ConfigID
return s return s
} }

View file

@ -1,108 +0,0 @@
/** Simulationmodel package, validators.
*
* @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 simulationmodel
import (
"encoding/json"
"github.com/jinzhu/gorm/dialects/postgres"
"github.com/nsf/jsondiff"
"gopkg.in/go-playground/validator.v9"
)
var validate *validator.Validate
type validNewSimulationModel struct {
Name string `form:"Name" validate:"required"`
ScenarioID uint `form:"ScenarioID" validate:"required"`
ICID uint `form:"ICID" validate:"required"`
StartParameters postgres.Jsonb `form:"StartParameters" validate:"required"`
SelectedModelFileID uint `form:"SelectedModelFilID" validate:"omitempty"`
}
type validUpdatedSimulationModel struct {
Name string `form:"Name" validate:"omitempty"`
ICID uint `form:"ICID" validate:"omitempty"`
StartParameters postgres.Jsonb `form:"StartParameters" validate:"omitempty"`
SelectedModelFileID uint `form:"SelectedModelFileID" validate:"omitempty"`
}
type addSimulationModelRequest struct {
SimulationModel validNewSimulationModel `json:"simulationModel"`
}
type updateSimulationModelRequest struct {
SimulationModel validUpdatedSimulationModel `json:"simulationModel"`
}
func (r *addSimulationModelRequest) validate() error {
validate = validator.New()
errs := validate.Struct(r)
return errs
}
func (r *validUpdatedSimulationModel) validate() error {
validate = validator.New()
errs := validate.Struct(r)
return errs
}
func (r *addSimulationModelRequest) createSimulationModel() SimulationModel {
var s SimulationModel
s.Name = r.SimulationModel.Name
s.ScenarioID = r.SimulationModel.ScenarioID
s.ICID = r.SimulationModel.ICID
s.StartParameters = r.SimulationModel.StartParameters
s.SelectedModelFileID = r.SimulationModel.SelectedModelFileID
return s
}
func (r *updateSimulationModelRequest) updatedSimulationModel(oldSimulationModel SimulationModel) SimulationModel {
// Use the old SimulationModel as a basis for the updated Simulation model
s := oldSimulationModel
if r.SimulationModel.Name != "" {
s.Name = r.SimulationModel.Name
}
if r.SimulationModel.ICID != 0 {
s.ICID = r.SimulationModel.ICID
}
if r.SimulationModel.SelectedModelFileID != 0 {
s.SelectedModelFileID = r.SimulationModel.SelectedModelFileID
}
// only update Params if not empty
var emptyJson postgres.Jsonb
// Serialize empty json and params
emptyJson_ser, _ := json.Marshal(emptyJson)
startParams_ser, _ := json.Marshal(r.SimulationModel.StartParameters)
opts := jsondiff.DefaultConsoleOptions()
diff, _ := jsondiff.Compare(emptyJson_ser, startParams_ser, &opts)
if diff.String() != "FullMatch" {
s.StartParameters = r.SimulationModel.StartParameters
}
return s
}

View file

@ -289,7 +289,7 @@ func TestUpdateWidget(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equalf(t, 422, code, "Response body: \n%v\n", resp) assert.Equalf(t, 422, code, "Response body: \n%v\n", resp)
// authenticate as guest user who has access to simulation model // authenticate as guest user who has access to scenario
token, err = helper.AuthenticateForTest(router, token, err = helper.AuthenticateForTest(router,
"/api/authenticate", "POST", helper.GuestCredentials) "/api/authenticate", "POST", helper.GuestCredentials)
assert.NoError(t, err) assert.NoError(t, err)

View file

@ -34,13 +34,13 @@ import (
"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"
apidocs "git.rwth-aachen.de/acs/public/villas/web-backend-go/doc/api" // doc/api folder is used by Swag CLI, you have to import it apidocs "git.rwth-aachen.de/acs/public/villas/web-backend-go/doc/api" // doc/api folder is used by Swag CLI, you have to import it
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/component-configuration"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/dashboard"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/file" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/file"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/infrastructure-component"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/metrics" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/metrics"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/signal" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/signal"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/simulationmodel"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget" "git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/widget"
) )
@ -114,7 +114,7 @@ func main() {
api.Use(user.Authentication(true)) api.Use(user.Authentication(true))
scenario.RegisterScenarioEndpoints(api.Group("/scenarios")) scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
simulationmodel.RegisterSimulationModelEndpoints(api.Group("/models")) component_configuration.RegisterComponentConfigurationEndpoints(api.Group("/configs"))
signal.RegisterSignalEndpoints(api.Group("/signals")) signal.RegisterSignalEndpoints(api.Group("/signals"))
dashboard.RegisterDashboardEndpoints(api.Group("/dashboards")) dashboard.RegisterDashboardEndpoints(api.Group("/dashboards"))
widget.RegisterWidgetEndpoints(api.Group("/widgets")) widget.RegisterWidgetEndpoints(api.Group("/widgets"))