Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve old commands #498

Merged
merged 14 commits into from
Jul 23, 2024
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
Loading