From ff16acc81606422d8faee24f6ead52c5f9b5b1e8 Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Wed, 3 Apr 2024 10:42:11 +1100 Subject: [PATCH] add support to update permissions --- README.md | 20 +++++++- controllers/controlPermissions.go | 78 +++++++++++++++++++++++++++++++ main.go | 1 + models/permission.go | 26 +++++++++++ utils/structOperations.go | 17 +++++++ 5 files changed, 140 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 87622eb..58f9d9c 100644 --- a/README.md +++ b/README.md @@ -224,7 +224,7 @@ Delete permission by specifying description Body ``` { - "Description":"Readonly access to default safe" + "Description": "Readonly access to default safe" } ``` @@ -234,7 +234,7 @@ Delete permission by specifying permission id Body ``` { - "permissionId":2 + "permissionId": 2 } ``` @@ -243,6 +243,22 @@ Deletes a permission mapping either a user or a group to a safe. Either the perm Deleting a permission should be performed prior to deleting any groups specified in that permission. +#### Update Permission +**POST** `/api/admin/permission/update` + +Change description of permission + +Body +``` +{ + "permissionId": 2 + "Description": "New Permission Description" + +} +``` + +Updates an existing permission. The permissionId must be specified. This operation can only be performed by a user that is admin enabled. + ### Group Operations #### List Groups diff --git a/controllers/controlPermissions.go b/controllers/controlPermissions.go index e2d4c5e..715da32 100644 --- a/controllers/controlPermissions.go +++ b/controllers/controlPermissions.go @@ -6,6 +6,7 @@ import ( "log" "net/http" "smt/models" + "smt/utils" "strings" "github.com/gin-gonic/gin" @@ -173,3 +174,80 @@ func DeletePermissionHandler(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "permission deletion success"}) } } + +func UpdatePermissionHandler(c *gin.Context) { + var input PermissionInput + var RequestingUserId int + + if err := c.ShouldBindJSON(&input); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + // Input validation + if input.PermissionId == 0 { + errString := "must specify permission id" + log.Printf("UpdatePermissionHandler %s\n", errString) + c.JSON(http.StatusBadRequest, gin.H{"error": errString}) + return + } + + if val, ok := c.Get("user-id"); !ok { + c.JSON(http.StatusBadRequest, gin.H{"error": "error determining user"}) + return + } else { + RequestingUserId = val.(int) + } + + // Check specified permission currently exists + currentPermission, err := models.PermissionGetById(input.PermissionId) + + if err != nil { + errString := fmt.Sprintf("error querying existing permission : '%s'", err) + log.Printf("UpdatePermissionHandler %s\n", errString) + c.JSON(http.StatusBadRequest, gin.H{"error": errString}) + return + } + if (models.Permission{} == currentPermission) { + errString := fmt.Sprintf("no permission id '%d' found", input.PermissionId) + log.Printf("UpdatePermissionHandler %s\n", errString) + c.JSON(http.StatusBadRequest, gin.H{"error": errString}) + return + } + + // create new struct with values supplied by user + newPermission := models.Permission{ + PermissionId: input.PermissionId, + Description: input.Description, + ReadOnly: input.ReadOnly, + SafeId: input.SafeId, + UserId: input.UserId, + GroupId: input.GroupId, + } + + //remove leading/trailing spaces in permission description + newPermission.Description = html.EscapeString(strings.TrimSpace(newPermission.Description)) + + // Copy newPermission into currentPermission + utils.UpdateStruct(¤tPermission, &newPermission) + + // run the database update + _, err = currentPermission.PermissionUpdate() + + if err != nil { + errString := fmt.Sprintf("error updating permission : '%s'", err) + log.Printf("UpdatePermissionHandler %s\n", errString) + c.JSON(http.StatusBadRequest, gin.H{"error": errString}) + return + } + + //create audit record + a := models.Audit{ + UserId: RequestingUserId, + IpAddress: c.ClientIP(), + EventText: fmt.Sprintf("Updated Permission '%s' with id %d", currentPermission.Description, currentPermission.PermissionId), + } + a.AuditLogAdd() + + c.JSON(http.StatusOK, gin.H{"message": "permission update success"}) +} diff --git a/main.go b/main.go index 97245de..5ec80cc 100644 --- a/main.go +++ b/main.go @@ -263,6 +263,7 @@ func main() { adminOnly.GET("/permissions", controllers.GetPermissionsHandler) adminOnly.POST("/permission/add", controllers.AddPermissionHandler) adminOnly.POST("/permission/delete", controllers.DeletePermissionHandler) + adminOnly.POST("/permission/update", controllers.UpdatePermissionHandler) // Safe functions for admin adminOnly.GET("/safe/listall", controllers.GetAllSafesHandler) diff --git a/models/permission.go b/models/permission.go index 21d83d8..6a5b332 100644 --- a/models/permission.go +++ b/models/permission.go @@ -142,3 +142,29 @@ func (p *Permission) PermissionDelete() error { return nil } + +// PermissionUpdate updates an existing permission definition in the database +func (p *Permission) PermissionUpdate() (*Permission, error) { + + var err error + + log.Printf("PermissionUpdate storing values '%v'\n", p) + + if p.PermissionId == 0 { + err = errors.New("PermissionUpdate unable to update permission with empty PermissionId field") + log.Printf("PermissionUpdate error in pre-check : '%s'\n", err) + return p, err + } + + result, err := db.NamedExec((`UPDATE permissions SET Description = :Description, ReadOnly = :ReadOnly, SafeId = :SafeId, UserId = :UserId, GroupId = :GroupId WHERE PermissionId = :PermissionId`), p) + if err != nil { + log.Printf("PermissionUpdate error executing sql record : '%s'\n", err) + return &Permission{}, err + } else { + affected, _ := result.RowsAffected() + id, _ := result.LastInsertId() + log.Printf("PermissionUpdate returned result id '%d' affecting %d row(s).\n", id, affected) + } + + return p, nil +} diff --git a/utils/structOperations.go b/utils/structOperations.go index ab93c56..3f2edb4 100644 --- a/utils/structOperations.go +++ b/utils/structOperations.go @@ -102,3 +102,20 @@ func AppendIfNotExists[T Identifiable](slice []T, element T) []T { // Element with the same Id does not exist, append the new element return append(slice, element) } + +// UpdateStruct updates the values in the destination struct with values from the source struct +func UpdateStruct(dest interface{}, src interface{}) { + destValue := reflect.ValueOf(dest).Elem() + srcValue := reflect.ValueOf(src).Elem() + + destType := destValue.Type() + + for i := 0; i < srcValue.NumField(); i++ { + srcField := srcValue.Field(i) + + destField := destValue.FieldByName(destType.Field(i).Name) + if destField.IsValid() && destField.Type() == srcField.Type() && destField.CanSet() { + destField.Set(srcField) + } + } +}