mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-30 00:00:12 +01:00
WIP: add license statement to new files, implement addResultFile and deleteResultFile endpoints, implement delete method for Result; first draft for test
This commit is contained in:
parent
6689c858d6
commit
3f45e286f9
5 changed files with 323 additions and 48 deletions
|
@ -1,8 +1,32 @@
|
|||
/** Result package, endpoints.
|
||||
*
|
||||
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
|
||||
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASweb-backend-go
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
package result
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/file"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
|
@ -15,7 +39,6 @@ func RegisterResultEndpoints(r *gin.RouterGroup) {
|
|||
r.GET("/:resultID", getResult)
|
||||
r.DELETE("/:resultID", deleteResult)
|
||||
r.POST("/:resultID/file", addResultFile)
|
||||
r.GET("/:resultID/file/:fileID", getResultFile)
|
||||
r.DELETE("/:resultID/file/:fileID", deleteResultFile)
|
||||
}
|
||||
|
||||
|
@ -33,16 +56,16 @@ func RegisterResultEndpoints(r *gin.RouterGroup) {
|
|||
// @Security Bearer
|
||||
func getResults(c *gin.Context) {
|
||||
|
||||
ok, scenario := scenario.CheckPermissions(c, database.Read, "query", -1)
|
||||
ok, sco := scenario.CheckPermissions(c, database.Read, "query", -1)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
db := database.GetDB()
|
||||
var result []database.Result
|
||||
err := db.Order("ID asc").Model(scenario).Related(&result, "Results").Error
|
||||
var results []database.Result
|
||||
err := db.Order("ID asc").Model(sco).Related(&results, "Results").Error
|
||||
if !helper.DBError(c, err) {
|
||||
c.JSON(http.StatusOK, gin.H{"result": result})
|
||||
c.JSON(http.StatusOK, gin.H{"results": results})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +132,7 @@ func addResult(c *gin.Context) {
|
|||
// @Security Bearer
|
||||
func updateResult(c *gin.Context) {
|
||||
|
||||
ok, oldResult := CheckPermissions(c, database.Update, "path", -1)
|
||||
ok, oldResult := checkPermissions(c, database.Update, "path", -1)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -151,7 +174,7 @@ func updateResult(c *gin.Context) {
|
|||
// @Security Bearer
|
||||
func getResult(c *gin.Context) {
|
||||
|
||||
ok, result := CheckPermissions(c, database.Read, "path", -1)
|
||||
ok, result := checkPermissions(c, database.Read, "path", -1)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -160,7 +183,7 @@ func getResult(c *gin.Context) {
|
|||
}
|
||||
|
||||
// deleteResult godoc
|
||||
// @Summary Delete a Result
|
||||
// @Summary Delete a Result incl. all result files
|
||||
// @ID deleteResult
|
||||
// @Tags results
|
||||
// @Produce json
|
||||
|
@ -173,7 +196,13 @@ func getResult(c *gin.Context) {
|
|||
// @Router /results/{resultID} [delete]
|
||||
// @Security Bearer
|
||||
func deleteResult(c *gin.Context) {
|
||||
ok, result := CheckPermissions(c, database.Delete, "path", -1)
|
||||
ok, result := checkPermissions(c, database.Delete, "path", -1)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if user is allowed to modify scenario associated with result
|
||||
ok, _ = scenario.CheckPermissions(c, database.Update, "body", int(result.ScenarioID))
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
@ -210,49 +239,37 @@ func deleteResult(c *gin.Context) {
|
|||
// @Router /results/{resultID}/file [post]
|
||||
// @Security Bearer
|
||||
func addResultFile(c *gin.Context) {
|
||||
ok, _ := CheckPermissions(c, database.Update, "path", -1)
|
||||
ok, result := checkPermissions(c, database.Update, "path", -1)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO check permissions of scenario first (file will be added to scenario)
|
||||
|
||||
// TODO add file to DB, associate with scenario and add file ID to result
|
||||
|
||||
}
|
||||
|
||||
// getResultFile godoc
|
||||
// @Summary Download a result file
|
||||
// @ID getResultFile
|
||||
// @Tags results
|
||||
// @Produce text/plain
|
||||
// @Produce text/csv
|
||||
// @Produce application/gzip
|
||||
// @Produce application/x-gtar
|
||||
// @Produce application/x-tar
|
||||
// @Produce application/x-ustar
|
||||
// @Produce application/zip
|
||||
// @Produce application/msexcel
|
||||
// @Produce application/xml
|
||||
// @Produce application/x-bag
|
||||
// @Success 200 {object} docs.ResponseFile "File that was requested"
|
||||
// @Failure 400 {object} docs.ResponseError "Bad request"
|
||||
// @Failure 404 {object} docs.ResponseError "Not found"
|
||||
// @Failure 422 {object} docs.ResponseError "Unprocessable entity"
|
||||
// @Failure 500 {object} docs.ResponseError "Internal server error"
|
||||
// @Param resultID path int true "Result ID"
|
||||
// @Param fileID path int true "ID of the file to download"
|
||||
// @Router /results/{resultID}/file/{fileID} [get]
|
||||
// @Security Bearer
|
||||
func getResultFile(c *gin.Context) {
|
||||
|
||||
// check access
|
||||
ok, _ := CheckPermissions(c, database.Read, "path", -1)
|
||||
// Check if user is allowed to modify scenario associated with result
|
||||
ok, sco := scenario.CheckPermissions(c, database.Update, "body", int(result.ScenarioID))
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO download result file
|
||||
// Extract file from POST request form
|
||||
file_header, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
helper.BadRequestError(c, fmt.Sprintf("Get form error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// save result file to DB and associate it with scenario
|
||||
var newFile file.File
|
||||
err = newFile.Register(file_header, sco.ID)
|
||||
if helper.DBError(c, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// add file ID to ResultFileIDs of Result
|
||||
err = result.addResultFileID(newFile.File.ID)
|
||||
if !helper.DBError(c, err) {
|
||||
c.JSON(http.StatusOK, gin.H{"result": result.Result})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// deleteResultFile godoc
|
||||
|
@ -270,12 +287,34 @@ func getResultFile(c *gin.Context) {
|
|||
// @Router /results/{resultID}/file/{fileID} [delete]
|
||||
// @Security Bearer
|
||||
func deleteResultFile(c *gin.Context) {
|
||||
// TODO check access to scenario (file deletion) first
|
||||
|
||||
// check access
|
||||
ok, _ := CheckPermissions(c, database.Update, "path", -1)
|
||||
ok, result := checkPermissions(c, database.Update, "path", -1)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
ok, f := file.CheckPermissions(c, database.Delete)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if user is allowed to modify scenario associated with result
|
||||
ok, _ = scenario.CheckPermissions(c, database.Update, "body", int(result.ScenarioID))
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// remove file ID from ResultFileIDs of Result
|
||||
err := result.removeResultFileID(f.ID)
|
||||
if helper.DBError(c, err) {
|
||||
return
|
||||
}
|
||||
|
||||
// Delete the file
|
||||
err = f.Delete()
|
||||
if !helper.DBError(c, err) {
|
||||
c.JSON(http.StatusOK, gin.H{"result": result.Result})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,32 @@
|
|||
/** Result package, methods.
|
||||
*
|
||||
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
|
||||
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASweb-backend-go
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
package result
|
||||
|
||||
import (
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/file"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Result struct {
|
||||
|
@ -69,7 +93,56 @@ func (r *Result) delete() error {
|
|||
// remove association between Result and Scenario
|
||||
err = db.Model(&sco).Association("Results").Delete(r).Error
|
||||
|
||||
// TODO delete Result + files (if any)
|
||||
// Delete result files
|
||||
for id, _ := range r.ResultFileIDs {
|
||||
var f file.File
|
||||
err := f.ByID(uint(id))
|
||||
if err != nil {
|
||||
log.Println("Unable to delete file with ID ", id, err)
|
||||
continue
|
||||
}
|
||||
err = f.Delete()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Delete result
|
||||
err = db.Delete(r).Error
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Result) addResultFileID(fileID uint) error {
|
||||
|
||||
oldResultFileIDs := r.ResultFileIDs
|
||||
newResultFileIDs := append(oldResultFileIDs, int64(fileID))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
err := db.Model(r).Updates(map[string]interface{}{
|
||||
"ResultFileIDs": newResultFileIDs,
|
||||
}).Error
|
||||
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
func (r *Result) removeResultFileID(fileID uint) error {
|
||||
oldResultFileIDs := r.ResultFileIDs
|
||||
var newResultFileIDs []int64
|
||||
|
||||
for _, id := range oldResultFileIDs {
|
||||
if id != int64(fileID) {
|
||||
newResultFileIDs = append(newResultFileIDs, id)
|
||||
}
|
||||
}
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
err := db.Model(r).Updates(map[string]interface{}{
|
||||
"ResultFileIDs": newResultFileIDs,
|
||||
}).Error
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
/** Result package, middleware.
|
||||
*
|
||||
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
|
||||
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASweb-backend-go
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
package result
|
||||
|
||||
import (
|
||||
|
@ -8,7 +30,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func CheckPermissions(c *gin.Context, operation database.CRUD, resultIDSource string, resultIDBody int) (bool, Result) {
|
||||
func checkPermissions(c *gin.Context, operation database.CRUD, resultIDSource string, resultIDBody int) (bool, Result) {
|
||||
|
||||
var result Result
|
||||
|
||||
|
|
|
@ -1 +1,120 @@
|
|||
/** Result package, testing.
|
||||
*
|
||||
* @author Sonja Happ <sonja.happ@eonerc.rwth-aachen.de>
|
||||
* @copyright 2014-2019, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASweb-backend-go
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
package result
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/file"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/scenario"
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/routes/user"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/jinzhu/gorm/dialects/postgres"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var router *gin.Engine
|
||||
|
||||
type ScenarioRequest struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Running bool `json:"running,omitempty"`
|
||||
StartParameters postgres.Jsonb `json:"startParameters,omitempty"`
|
||||
}
|
||||
|
||||
func addScenario() (scenarioID uint) {
|
||||
|
||||
// authenticate as admin
|
||||
token, _ := helper.AuthenticateForTest(router,
|
||||
"/api/authenticate", "POST", helper.AdminCredentials)
|
||||
|
||||
// authenticate as normal user
|
||||
token, _ = helper.AuthenticateForTest(router,
|
||||
"/api/authenticate", "POST", helper.UserACredentials)
|
||||
|
||||
// POST $newScenario
|
||||
newScenario := ScenarioRequest{
|
||||
Name: helper.ScenarioA.Name,
|
||||
Running: helper.ScenarioA.Running,
|
||||
StartParameters: helper.ScenarioA.StartParameters,
|
||||
}
|
||||
_, resp, _ := helper.TestEndpoint(router, token,
|
||||
"/api/scenarios", "POST", helper.KeyModels{"scenario": newScenario})
|
||||
|
||||
// Read newScenario's ID from the response
|
||||
newScenarioID, _ := helper.GetResponseID(resp)
|
||||
|
||||
// add the guest user to the new scenario
|
||||
_, resp, _ = helper.TestEndpoint(router, token,
|
||||
fmt.Sprintf("/api/scenarios/%v/user?username=User_C", newScenarioID), "PUT", nil)
|
||||
|
||||
return uint(newScenarioID)
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
err := configuration.InitConfig()
|
||||
if err != nil {
|
||||
panic(m)
|
||||
}
|
||||
err = database.InitDB(configuration.GolbalConfig)
|
||||
if err != nil {
|
||||
panic(m)
|
||||
}
|
||||
defer database.DBpool.Close()
|
||||
|
||||
router = gin.Default()
|
||||
api := router.Group("/api")
|
||||
|
||||
user.RegisterAuthenticate(api.Group("/authenticate"))
|
||||
api.Use(user.Authentication(true))
|
||||
// scenario endpoints required here to first add a scenario to the DB
|
||||
scenario.RegisterScenarioEndpoints(api.Group("/scenarios"))
|
||||
// file endpoints required to download result file
|
||||
file.RegisterFileEndpoints(api.Group("/files"))
|
||||
|
||||
RegisterResultEndpoints(api.Group("/results"))
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestGetAllResultsOfScenario(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestAddGetUpdateResult(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestDeleteResult(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestAddResultFile(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestDeleteResultFile(t *testing.T) {
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,25 @@
|
|||
/** Result 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 result
|
||||
|
||||
import (
|
||||
|
|
Loading…
Add table
Reference in a new issue