Skip to content

Commit

Permalink
Improve old commands (#498)
Browse files Browse the repository at this point in the history
* fix(cli,api) complex filter with typed attrs

* fix(cli) tests and doc

* fix(api) mongo not operator needs regex

* fix(api) add trim and tes

* refactor(api) adjust pattern

* refactor(api) extract cursor

* refactor(api) get many objects

* refacto(api) get hierarchy

* refactor(api) get hierarchy

* refactor(api) update

* refactor(api) fill hierarchy

* refactor(api) get hierarchy

* refactor(api) refactor propagate

* refactor(api) lastupdated filter
  • Loading branch information
helderbetiol authored Jul 23, 2024
1 parent 276764e commit 60fa4fa
Show file tree
Hide file tree
Showing 39 changed files with 1,502 additions and 1,479 deletions.
21 changes: 4 additions & 17 deletions API/controllers/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -788,20 +788,7 @@ func GetEntity(w http.ResponseWriter, r *http.Request) {

// Get entity
if id, canParse = mux.Vars(r)["id"]; canParse {
var req primitive.M
if entityStr == u.HIERARCHYOBJS_ENT {
data, modelErr = models.GetHierarchyObjectById(id, filters, user.Roles)
} else {
if u.IsEntityNonHierarchical(u.EntityStrToInt(entityStr)) {
// Get by slug
req = bson.M{"slug": id}

} else {
req = bson.M{"id": id}
}

data, modelErr = models.GetObject(req, entityStr, filters, user.Roles)
}
data, modelErr = models.GetObjectById(id, entityStr, filters, user.Roles)
} else {
w.WriteHeader(http.StatusBadRequest)
u.Respond(w, u.Message("Error while parsing path parameters"))
Expand Down Expand Up @@ -1108,7 +1095,7 @@ func DeleteEntity(w http.ResponseWriter, r *http.Request) {
u.ErrLog("Error while parsing path parameters", "DELETE ENTITY", "", r)
} else {
if entityStr == u.HIERARCHYOBJS_ENT {
obj, err := models.GetHierarchyObjectById(id, u.RequestFilters{}, user.Roles)
obj, err := models.GetHierarchicalObjectById(id, u.RequestFilters{}, user.Roles)
if err != nil {
u.ErrLog("Error finding hierarchy obj to delete", "DELETE ENTITY", err.Message, r)
u.RespondWithError(w, err)
Expand Down Expand Up @@ -1639,7 +1626,7 @@ func GetHierarchyByName(w http.ResponseWriter, r *http.Request) {
var data map[string]interface{}
if entity == u.HIERARCHYOBJS_ENT {
// Generic endpoint only for physical objs
data, modelErr = models.GetHierarchyObjectById(id, filters, user.Roles)
data, modelErr = models.GetHierarchicalObjectById(id, filters, user.Roles)
if modelErr == nil {
entity = data["category"].(string)
}
Expand Down Expand Up @@ -1879,7 +1866,7 @@ func LinkEntity(w http.ResponseWriter, r *http.Request) {
// Get entity
if id, canParse = mux.Vars(r)["id"]; canParse {
if entityStr == u.HIERARCHYOBJS_ENT {
data, modelErr = models.GetHierarchyObjectById(id, u.RequestFilters{}, user.Roles)
data, modelErr = models.GetHierarchicalObjectById(id, u.RequestFilters{}, user.Roles)
} else {
data, modelErr = models.GetObject(bson.M{"id": id}, entityStr, u.RequestFilters{}, user.Roles)
}
Expand Down
119 changes: 119 additions & 0 deletions API/models/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package models

import (
"context"
"fmt"
"p3/repository"
u "p3/utils"
"strings"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)

func CommandRunner(cmd interface{}) *mongo.SingleResult {
ctx, cancel := u.Connect()
result := repository.GetDB().RunCommand(ctx, cmd, nil)
defer cancel()
return result
}

func GetDBName() string {
name := repository.GetDB().Name()

//Remove the preceding 'ogree' at beginning of name
if strings.Index(name, "ogree") == 0 {
name = name[5:] //5=len('ogree')
}
return name
}

func ExtractCursor(c *mongo.Cursor, ctx context.Context, entity int, userRoles map[string]Role) ([]map[string]interface{}, error) {
ans := []map[string]interface{}{}
for c.Next(ctx) {
x := map[string]interface{}{}
err := c.Decode(x)
if err != nil {
fmt.Println(err.Error())
return nil, err
}
// Remove _id
x = fixID(x)
// Check permissions
if u.IsEntityHierarchical(entity) && userRoles != nil {
permission := CheckUserPermissionsWithObject(userRoles, entity, x)
if permission == READONLYNAME {
x = FixReadOnlyName(x)
}
if permission >= READONLYNAME {
ans = append(ans, x)
}
} else {
ans = append(ans, x)
}
}
return ans, nil
}

func WithTransaction[T any](callback func(mongo.SessionContext) (T, error)) (T, *u.Error) {
ctx, cancel := u.Connect()
defer cancel()

var nilT T

// Start a session and run the callback to update db
session, err := repository.GetClient().StartSession()
if err != nil {
return nilT, &u.Error{Type: u.ErrDBError, Message: "Unable to start session: " + err.Error()}
}
defer session.EndSession(ctx)

callbackWrapper := func(ctx mongo.SessionContext) (any, error) {
result, err := callback(ctx)
if err != nil {
// support returning u.Error even if nil
if errCasted, ok := err.(*u.Error); ok {
if errCasted != nil {
return nilT, errCasted // u.Error not nil -> return u.Error not nil
}

return result, nil // u.Error nil -> return error nil
}

return result, err // error not nil -> return error not nil
}

return result, nil // error nil -> return error nil
}

result, err := session.WithTransaction(ctx, callbackWrapper)
if err != nil {
if errCasted, ok := err.(*u.Error); ok {
return nilT, errCasted
}

return nilT, &u.Error{Type: u.ErrDBError, Message: "Unable to complete transaction: " + err.Error()}
}

return castResult[T](result), nil
}

func castResult[T any](result any) T {
if result == nil {
var nilT T
return nilT
}

return result.(T)
}

func GetIdReqByEntity(entityStr, id string) primitive.M {
var idFilter primitive.M
if u.IsEntityNonHierarchical(u.EntityStrToInt(entityStr)) {
idFilter = bson.M{"slug": id}
} else {
idFilter = bson.M{"id": id}
}
return idFilter
}
16 changes: 0 additions & 16 deletions API/models/delete.go

This file was deleted.

File renamed without changes.
59 changes: 59 additions & 0 deletions API/models/entity_create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package models

import (
"p3/repository"
u "p3/utils"

"go.mongodb.org/mongo-driver/mongo"
)

func CreateEntity(entity int, t map[string]interface{}, userRoles map[string]Role) (map[string]interface{}, *u.Error) {
tags, tagsPresent := getTags(t)
if tagsPresent {
err := verifyTagList(tags)
if err != nil {
return nil, err
}
}

if err := prepareCreateEntity(entity, t, userRoles); err != nil {
return nil, err
}

return WithTransaction(func(ctx mongo.SessionContext) (map[string]any, error) {
if entity == u.TAG {
err := createTagImage(ctx, t)
if err != nil {
return nil, err
}
}

entStr := u.EntityToString(entity)

_, err := repository.CreateObject(ctx, entStr, t)
if err != nil {
return nil, err
}

fixID(t)
return t, nil
})
}

func prepareCreateEntity(entity int, t map[string]interface{}, userRoles map[string]Role) *u.Error {
if err := ValidateEntity(entity, t); err != nil {
return err
}

// Check user permissions
if u.IsEntityHierarchical(entity) {
if permission := CheckUserPermissionsWithObject(userRoles, entity, t); permission < WRITE {
return &u.Error{Type: u.ErrUnauthorized,
Message: "User does not have permission to create this object"}
}
}

delete(t, "parentId")

return nil
}
File renamed without changes.
97 changes: 97 additions & 0 deletions API/models/entity_delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package models

import (
"os"
"p3/repository"
u "p3/utils"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)

func DeleteObject(entityStr string, id string, userRoles map[string]Role) *u.Error {
entity := u.EntityStrToInt(entityStr)
if entity == u.TAG {
return DeleteTag(id)
} else if u.IsEntityNonHierarchical(entity) {
return DeleteNonHierarchicalObject(entityStr, id)
} else {
return DeleteHierarchicalObject(entityStr, id, userRoles)
}
}

// DeleteHierarchicalObject: delete object of given hierarchyName
// search for all its children and delete them too, return:
// - success or fail message map
func DeleteHierarchicalObject(entity string, id string, userRoles map[string]Role) *u.Error {
// Special check for delete domain
if entity == "domain" {
if id == os.Getenv("db") {
return &u.Error{Type: u.ErrForbidden, Message: "Cannot delete tenant's default domain"}
}
if domainHasObjects(id) {
return &u.Error{Type: u.ErrForbidden, Message: "Cannot delete domain if it has at least one object"}
}
}

// Delete with given id
req, ok := GetRequestFilterByDomain(userRoles)
if !ok {
return &u.Error{Type: u.ErrUnauthorized, Message: "User does not have permission to delete"}
}

req["id"] = id

_, err := WithTransaction(func(ctx mongo.SessionContext) (any, error) {
err := repository.DeleteObject(ctx, entity, req)
if err != nil {
// Unable to delete given id
return nil, err
}

// Delete possible children
rangeEntities := getChildrenCollections(u.GROUP, entity)
for _, childEnt := range rangeEntities {
childEntName := u.EntityToString(childEnt)
pattern := primitive.Regex{Pattern: "^" + id + u.HN_DELIMETER, Options: ""}

repository.GetDB().Collection(childEntName).DeleteMany(ctx,
bson.M{"id": pattern})
}

return nil, nil
})

return err
}

func DeleteNonHierarchicalObject(entity, slug string) *u.Error {
req := bson.M{"slug": slug}
ctx, cancel := u.Connect()
defer cancel()
return repository.DeleteObject(ctx, entity, req)
}

// Helper functions

func domainHasObjects(domain string) bool {
data := map[string]interface{}{}
// Get all collections names
ctx, cancel := u.Connect()
db := repository.GetDB()
collNames, _ := db.ListCollectionNames(ctx, bson.D{})

// Check if at least one object belongs to domain
for _, collName := range collNames {
pattern := primitive.Regex{Pattern: "^" + domain, Options: ""}
e := db.Collection(collName).FindOne(ctx, bson.M{"domain": pattern}).Decode(&data)
if e == nil {
// Found one!
return true
}
}

defer cancel()
return false
}
Loading

0 comments on commit 60fa4fa

Please sign in to comment.