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:
Sonja Happ 2020-11-20 14:04:57 +01:00
parent 6689c858d6
commit 3f45e286f9
5 changed files with 323 additions and 48 deletions

View file

@ -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})
}
}

View file

@ -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
}

View file

@ -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

View file

@ -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) {
}

View file

@ -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 (