Added Singleton and Field to simplify GQL definitions

graph-rework-2
noah metz 2023-07-21 17:49:19 -06:00
parent 551370e541
commit d4fcd80ff8
7 changed files with 636 additions and 663 deletions

@ -120,6 +120,10 @@ type GQLContext struct {
ValidLockables ObjTypeMap
ValidThreads ObjTypeMap
BaseNodeType *graphql.Object
BaseLockableType *graphql.Object
BaseThreadType *graphql.Object
Query *graphql.Object
Mutation *graphql.Object
Subscription *graphql.Object
@ -154,6 +158,7 @@ func NewGQLContext() GQLContext {
Query: query,
Mutation: mutation,
Subscription: subscription,
BaseNodeType: GQLTypeGraphNode.Type,
}
return ctx
@ -168,48 +173,49 @@ func NewContext(db * badger.DB, log Logger) * Context {
Types: map[uint64]NodeDef{},
}
err := ctx.RegisterNodeType(NewNodeDef((*GraphNode)(nil), LoadGraphNode, GQLTypeGraphNode()))
err := ctx.RegisterNodeType(NewNodeDef((*GraphNode)(nil), LoadGraphNode, GQLTypeGraphNode.Type))
if err != nil {
panic(err)
}
err = ctx.RegisterNodeType(NewNodeDef((*SimpleLockable)(nil), LoadSimpleLockable, GQLTypeSimpleLockable()))
err = ctx.RegisterNodeType(NewNodeDef((*SimpleLockable)(nil), LoadSimpleLockable, GQLTypeSimpleLockable.Type))
if err != nil {
panic(err)
}
err = ctx.RegisterNodeType(NewNodeDef((*SimpleThread)(nil), LoadSimpleThread, GQLTypeSimpleThread()))
err = ctx.RegisterNodeType(NewNodeDef((*SimpleThread)(nil), LoadSimpleThread, GQLTypeSimpleThread.Type))
if err != nil {
panic(err)
}
err = ctx.RegisterNodeType(NewNodeDef((*GQLThread)(nil), LoadGQLThread, GQLTypeGQLThread()))
err = ctx.RegisterNodeType(NewNodeDef((*GQLThread)(nil), LoadGQLThread, GQLTypeGQLThread.Type))
if err != nil {
panic(err)
}
err = ctx.RegisterNodeType(NewNodeDef((*User)(nil), LoadUser, GQLTypeUser()))
err = ctx.RegisterNodeType(NewNodeDef((*User)(nil), LoadUser, GQLTypeUser.Type))
if err != nil {
panic(err)
}
err = ctx.RegisterNodeType(NewNodeDef((*PerNodePolicy)(nil), LoadPerNodePolicy, GQLTypeGraphNode()))
err = ctx.RegisterNodeType(NewNodeDef((*PerNodePolicy)(nil), LoadPerNodePolicy, GQLTypeGraphNode.Type))
if err != nil {
panic(err)
}
err = ctx.RegisterNodeType(NewNodeDef((*SimplePolicy)(nil), LoadSimplePolicy, GQLTypeGraphNode()))
err = ctx.RegisterNodeType(NewNodeDef((*SimplePolicy)(nil), LoadSimplePolicy, GQLTypeGraphNode.Type))
if err != nil {
panic(err)
}
err = ctx.RegisterNodeType(NewNodeDef((*PerTagPolicy)(nil), LoadPerTagPolicy, GQLTypeGraphNode()))
err = ctx.RegisterNodeType(NewNodeDef((*PerTagPolicy)(nil), LoadPerTagPolicy, GQLTypeGraphNode.Type))
if err != nil {
panic(err)
}
ctx.AddGQLType(GQLTypeSignal())
ctx.AddGQLType(GQLTypeSignal.Type)
ctx.GQL.Query.AddFieldConfig("Self", GQLQuerySelf())
ctx.GQL.Query.AddFieldConfig("Self", GQLQuerySelf)
ctx.GQL.Query.AddFieldConfig("User", GQLQueryUser)
ctx.GQL.Subscription.AddFieldConfig("Update", GQLSubscriptionUpdate())
ctx.GQL.Subscription.AddFieldConfig("Self", GQLSubscriptionSelf())
ctx.GQL.Subscription.AddFieldConfig("Update", GQLSubscriptionUpdate)
ctx.GQL.Subscription.AddFieldConfig("Self", GQLSubscriptionSelf)
ctx.GQL.Mutation.AddFieldConfig("sendUpdate", GQLMutationSendUpdate())
ctx.GQL.Mutation.AddFieldConfig("startChild", GQLMutationStartChild())
ctx.GQL.Mutation.AddFieldConfig("sendUpdate", GQLMutationSendUpdate)
ctx.GQL.Mutation.AddFieldConfig("startChild", GQLMutationStartChild)
err = ctx.RebuildSchema()
if err != nil {

@ -4,17 +4,15 @@ import (
"github.com/graphql-go/graphql"
)
var gql_mutation_send_update *graphql.Field = nil
func GQLMutationSendUpdate() *graphql.Field {
if gql_mutation_send_update == nil {
gql_mutation_send_update = &graphql.Field{
Type: GQLTypeSignal(),
var GQLMutationSendUpdate = NewField(func()*graphql.Field {
gql_mutation_send_update := &graphql.Field{
Type: GQLTypeSignal.Type,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Type: graphql.String,
},
"signal": &graphql.ArgumentConfig{
Type: GQLTypeSignalInput(),
Type: GQLTypeSignalInput.Type,
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
@ -65,16 +63,13 @@ func GQLMutationSendUpdate() *graphql.Field {
return signal, nil
},
}
}
return gql_mutation_send_update
}
})
var gql_mutation_start_child *graphql.Field = nil
func GQLMutationStartChild() *graphql.Field {
if gql_mutation_start_child == nil {
gql_mutation_start_child = &graphql.Field{
Type: GQLTypeSignal(),
var GQLMutationStartChild = NewField(func()*graphql.Field{
gql_mutation_start_child := &graphql.Field{
Type: GQLTypeSignal.Type,
Args: graphql.FieldConfigArgument{
"parent_id": &graphql.ArgumentConfig{
Type: graphql.String,
@ -132,7 +127,7 @@ func GQLMutationStartChild() *graphql.Field {
return signal, nil
},
}
}
return gql_mutation_start_child
}
})

@ -1,30 +1,38 @@
package graphvent
import (
"fmt"
"github.com/graphql-go/graphql"
)
var gql_query_self *graphql.Field = nil
func GQLQuerySelf() *graphql.Field {
if gql_query_self == nil {
gql_query_self = &graphql.Field{
Type: GQLTypeGQLThread(),
var GQLQuerySelf = &graphql.Field{
Type: GQLTypeGQLThread.Type,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
_, server, user, err := PrepResolve(p)
if err != nil {
return nil, err
}
err = server.Allowed("enumerate", "self", user)
if err != nil {
return nil, fmt.Errorf("User %s is not allowed to perform self.enumerate on %s", user.ID(), server.ID())
return nil, err
}
return server, nil
},
}
var GQLQueryUser = &graphql.Field{
Type: GQLTypeUser.Type,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
_, _, user, err := PrepResolve(p)
if err != nil {
return nil, err
}
return gql_query_self
err = user.Allowed("enumerate", "self", user)
if err != nil {
return nil, err
}
return user, nil
},
}

@ -50,33 +50,26 @@ func GQLSubscribeFn(p graphql.ResolveParams, send_nil bool, fn func(*Context, *G
return c, nil
}
var gql_subscription_self * graphql.Field = nil
func GQLSubscriptionSelf() * graphql.Field {
if gql_subscription_self == nil {
gql_subscription_self = &graphql.Field{
Type: GQLTypeGQLThread(),
var GQLSubscriptionSelf = NewField(func()*graphql.Field{
gql_subscription_self := &graphql.Field{
Type: GQLTypeGQLThread.Type,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return p.Source, nil
},
Subscribe: GQLSubscribeSelf,
}
}
return gql_subscription_self
}
})
var gql_subscription_update * graphql.Field = nil
func GQLSubscriptionUpdate() * graphql.Field {
if gql_subscription_update == nil {
gql_subscription_update = &graphql.Field{
Type: GQLTypeSignal(),
var GQLSubscriptionUpdate = NewField(func()*graphql.Field{
gql_subscription_update := &graphql.Field{
Type: GQLTypeSignal.Type,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return p.Source, nil
},
Subscribe: GQLSubscribeSignal,
}
}
return gql_subscription_update
}
})

@ -237,7 +237,7 @@ func TestGQLAuth(t * testing.T) {
url = fmt.Sprintf("https://localhost:%d/gql", port)
ser, err := json.MarshalIndent(&GQLPayload{
Query: "query { Self { Users { ID } } }",
Query: "query { Self { Users { ID, Name } } }",
}, "", " ")
fatalErr(t, err)

@ -5,10 +5,31 @@ import (
"reflect"
)
var gql_interface_graph_node *graphql.Interface = nil
func GQLInterfaceNode() *graphql.Interface {
if gql_interface_graph_node == nil {
gql_interface_graph_node = graphql.NewInterface(graphql.InterfaceConfig{
type Field *graphql.Field
func NewField(init func()*graphql.Field) Field {
return Field(init())
}
type Singleton[K graphql.Type] struct {
Type K
List *graphql.List
}
func NewSingleton[K graphql.Type](init func() K, post_init func(K, *graphql.List)) *Singleton[K] {
val := init()
list := graphql.NewList(val)
if post_init != nil {
post_init(val, list)
}
return &Singleton[K]{
Type: val,
List: list,
}
}
var GQLInterfaceNode = NewSingleton(func() *graphql.Interface {
i := graphql.NewInterface(graphql.InterfaceConfig{
Name: "Node",
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
ctx, ok := p.Context.Value("graph_context").(*Context)
@ -27,34 +48,21 @@ func GQLInterfaceNode() *graphql.Interface {
}
if p_type.Implements(node_type) {
return GQLTypeGraphNode()
return ctx.GQL.BaseNodeType
}
return nil
},
Fields: graphql.Fields{},
})
gql_interface_graph_node.AddFieldConfig("ID", &graphql.Field{
i.AddFieldConfig("ID", &graphql.Field{
Type: graphql.String,
})
}
return i
}, nil)
return gql_interface_graph_node
}
var gql_list_thread *graphql.List = nil
func GQLListThread() *graphql.List {
if gql_list_thread == nil {
gql_list_thread = graphql.NewList(GQLInterfaceThread())
}
return gql_list_thread
}
var gql_interface_thread *graphql.Interface = nil
func GQLInterfaceThread() *graphql.Interface {
if gql_interface_thread == nil {
gql_interface_thread = graphql.NewInterface(graphql.InterfaceConfig{
var GQLInterfaceThread = NewSingleton(func() *graphql.Interface {
gql_interface_thread := graphql.NewInterface(graphql.InterfaceConfig{
Name: "Thread",
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
ctx, ok := p.Context.Value("graph_context").(*Context)
@ -73,7 +81,7 @@ func GQLInterfaceThread() *graphql.Interface {
}
if p_type.Implements(thread_type) {
return GQLTypeSimpleThread()
return ctx.GQL.BaseThreadType
}
ctx.Log.Logf("gql", "Found no type that matches %+v: %+v", p_type, p_type.Implements(thread_type))
@ -94,42 +102,32 @@ func GQLInterfaceThread() *graphql.Interface {
Type: graphql.String,
})
gql_interface_thread.AddFieldConfig("Children", &graphql.Field{
Type: GQLListThread(),
})
gql_interface_thread.AddFieldConfig("Parent", &graphql.Field{
Type: GQLInterfaceThread(),
})
gql_interface_thread.AddFieldConfig("Requirements", &graphql.Field{
Type: GQLListLockable(),
Type: GQLInterfaceLockable.List,
})
gql_interface_thread.AddFieldConfig("Dependencies", &graphql.Field{
Type: GQLListLockable(),
Type: GQLInterfaceLockable.List,
})
gql_interface_thread.AddFieldConfig("Owner", &graphql.Field{
Type: GQLInterfaceLockable(),
Type: GQLInterfaceLockable.Type,
})
}
return gql_interface_thread
}
}, func(thread *graphql.Interface, thread_list *graphql.List) {
thread.AddFieldConfig("Children", &graphql.Field{
Type: thread_list,
})
var gql_list_lockable *graphql.List = nil
func GQLListLockable() *graphql.List {
if gql_list_lockable == nil {
gql_list_lockable = graphql.NewList(GQLInterfaceLockable())
}
return gql_list_lockable
}
thread.AddFieldConfig("Parent", &graphql.Field{
Type: thread,
})
var gql_interface_lockable *graphql.Interface = nil
func GQLInterfaceLockable() *graphql.Interface {
if gql_interface_lockable == nil {
gql_interface_lockable = graphql.NewInterface(graphql.InterfaceConfig{
})
var GQLInterfaceLockable = NewSingleton(func() *graphql.Interface {
gql_interface_lockable := graphql.NewInterface(graphql.InterfaceConfig{
Name: "Lockable",
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
ctx, ok := p.Context.Value("graph_context").(*Context)
@ -148,7 +146,7 @@ func GQLInterfaceLockable() *graphql.Interface {
}
if p_type.Implements(lockable_type) {
return GQLTypeSimpleLockable()
return ctx.GQL.BaseThreadType
}
return nil
},
@ -162,44 +160,27 @@ func GQLInterfaceLockable() *graphql.Interface {
gql_interface_lockable.AddFieldConfig("Name", &graphql.Field{
Type: graphql.String,
})
if gql_list_lockable == nil {
gql_list_lockable = graphql.NewList(gql_interface_lockable)
}
gql_interface_lockable.AddFieldConfig("Requirements", &graphql.Field{
Type: gql_list_lockable,
return gql_interface_lockable
}, func(lockable *graphql.Interface, lockable_list *graphql.List) {
lockable.AddFieldConfig("Requirements", &graphql.Field{
Type: lockable_list,
})
gql_interface_lockable.AddFieldConfig("Dependencies", &graphql.Field{
Type: gql_list_lockable,
lockable.AddFieldConfig("Dependencies", &graphql.Field{
Type: lockable_list,
})
gql_interface_lockable.AddFieldConfig("Owner", &graphql.Field{
Type: gql_interface_lockable,
lockable.AddFieldConfig("Owner", &graphql.Field{
Type: lockable,
})
})
}
return gql_interface_lockable
}
var gql_list_user *graphql.List = nil
func GQLListUser() *graphql.List {
if gql_list_user == nil {
gql_list_user = graphql.NewList(GQLTypeUser())
}
return gql_list_user
}
var gql_type_user *graphql.Object = nil
func GQLTypeUser() * graphql.Object {
if gql_type_user == nil {
gql_type_user = graphql.NewObject(graphql.ObjectConfig{
var GQLTypeUser = NewSingleton(func() *graphql.Object {
gql_type_user := graphql.NewObject(graphql.ObjectConfig{
Name: "User",
Interfaces: []*graphql.Interface{
GQLInterfaceNode(),
GQLInterfaceLockable(),
GQLInterfaceNode.Type,
GQLInterfaceLockable.Type,
},
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
ctx, ok := p.Context.Value("graph_context").(*Context)
@ -230,32 +211,29 @@ func GQLTypeUser() * graphql.Object {
})
gql_type_user.AddFieldConfig("Requirements", &graphql.Field{
Type: GQLListLockable(),
Type: GQLInterfaceLockable.List,
Resolve: GQLLockableRequirements,
})
gql_type_user.AddFieldConfig("Owner", &graphql.Field{
Type: GQLInterfaceLockable(),
Type: GQLInterfaceLockable.Type,
Resolve: GQLLockableOwner,
})
gql_type_user.AddFieldConfig("Dependencies", &graphql.Field{
Type: GQLListLockable(),
Type: GQLInterfaceLockable.List,
Resolve: GQLLockableDependencies,
})
}
return gql_type_user
}
}, nil)
var gql_type_gql_thread *graphql.Object = nil
func GQLTypeGQLThread() * graphql.Object {
if gql_type_gql_thread == nil {
gql_type_gql_thread = graphql.NewObject(graphql.ObjectConfig{
var GQLTypeGQLThread = NewSingleton(func() *graphql.Object {
gql_type_gql_thread := graphql.NewObject(graphql.ObjectConfig{
Name: "GQLThread",
Interfaces: []*graphql.Interface{
GQLInterfaceNode(),
GQLInterfaceThread(),
GQLInterfaceLockable(),
GQLInterfaceNode.Type,
GQLInterfaceThread.Type,
GQLInterfaceLockable.Type,
},
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
_, ok := p.Value.(*GQLThread)
@ -280,12 +258,12 @@ func GQLTypeGQLThread() * graphql.Object {
})
gql_type_gql_thread.AddFieldConfig("Children", &graphql.Field{
Type: GQLListThread(),
Type: GQLInterfaceThread.List,
Resolve: GQLThreadChildren,
})
gql_type_gql_thread.AddFieldConfig("Parent", &graphql.Field{
Type: GQLInterfaceThread(),
Type: GQLInterfaceThread.Type,
Resolve: GQLThreadParent,
})
@ -295,37 +273,34 @@ func GQLTypeGQLThread() * graphql.Object {
})
gql_type_gql_thread.AddFieldConfig("Requirements", &graphql.Field{
Type: GQLListLockable(),
Type: GQLInterfaceLockable.List,
Resolve: GQLLockableRequirements,
})
gql_type_gql_thread.AddFieldConfig("Owner", &graphql.Field{
Type: GQLInterfaceLockable(),
Type: GQLInterfaceLockable.Type,
Resolve: GQLLockableOwner,
})
gql_type_gql_thread.AddFieldConfig("Dependencies", &graphql.Field{
Type: GQLListLockable(),
Type: GQLInterfaceLockable.List,
Resolve: GQLLockableDependencies,
})
gql_type_gql_thread.AddFieldConfig("Users", &graphql.Field{
Type: GQLListUser(),
Type: GQLTypeUser.List,
Resolve: GQLThreadUsers,
})
}
return gql_type_gql_thread
}
}, nil)
var gql_type_simple_thread *graphql.Object = nil
func GQLTypeSimpleThread() * graphql.Object {
if gql_type_simple_thread == nil {
gql_type_simple_thread = graphql.NewObject(graphql.ObjectConfig{
var GQLTypeSimpleThread = NewSingleton(func() *graphql.Object {
gql_type_simple_thread := graphql.NewObject(graphql.ObjectConfig{
Name: "SimpleThread",
Interfaces: []*graphql.Interface{
GQLInterfaceNode(),
GQLInterfaceThread(),
GQLInterfaceLockable(),
GQLInterfaceNode.Type,
GQLInterfaceThread.Type,
GQLInterfaceLockable.Type,
},
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
ctx, ok := p.Context.Value("graph_context").(*Context)
@ -361,41 +336,39 @@ func GQLTypeSimpleThread() * graphql.Object {
})
gql_type_simple_thread.AddFieldConfig("Children", &graphql.Field{
Type: GQLListThread(),
Type: GQLInterfaceThread.List,
Resolve: GQLThreadChildren,
})
gql_type_simple_thread.AddFieldConfig("Parent", &graphql.Field{
Type: GQLInterfaceThread(),
Type: GQLInterfaceThread.Type,
Resolve: GQLThreadParent,
})
gql_type_simple_thread.AddFieldConfig("Requirements", &graphql.Field{
Type: GQLListLockable(),
Type: GQLInterfaceLockable.List,
Resolve: GQLLockableRequirements,
})
gql_type_simple_thread.AddFieldConfig("Owner", &graphql.Field{
Type: GQLInterfaceLockable(),
Type: GQLInterfaceLockable.Type,
Resolve: GQLLockableOwner,
})
gql_type_simple_thread.AddFieldConfig("Dependencies", &graphql.Field{
Type: GQLListLockable(),
Type: GQLInterfaceLockable.List,
Resolve: GQLLockableDependencies,
})
}
return gql_type_simple_thread
}
}, nil)
var gql_type_simple_lockable *graphql.Object = nil
func GQLTypeSimpleLockable() * graphql.Object {
if gql_type_simple_lockable == nil {
gql_type_simple_lockable = graphql.NewObject(graphql.ObjectConfig{
var GQLTypeSimpleLockable = NewSingleton(func() *graphql.Object {
gql_type_simple_lockable := graphql.NewObject(graphql.ObjectConfig{
Name: "SimpleLockable",
Interfaces: []*graphql.Interface{
GQLInterfaceNode(),
GQLInterfaceLockable(),
GQLInterfaceNode.Type,
GQLInterfaceLockable.Type,
},
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
ctx, ok := p.Context.Value("graph_context").(*Context)
@ -426,30 +399,28 @@ func GQLTypeSimpleLockable() * graphql.Object {
})
gql_type_simple_lockable.AddFieldConfig("Requirements", &graphql.Field{
Type: GQLListLockable(),
Type: GQLInterfaceLockable.List,
Resolve: GQLLockableRequirements,
})
gql_type_simple_lockable.AddFieldConfig("Owner", &graphql.Field{
Type: GQLInterfaceLockable(),
Type: GQLInterfaceLockable.Type,
Resolve: GQLLockableOwner,
})
gql_type_simple_lockable.AddFieldConfig("Dependencies", &graphql.Field{
Type: GQLListLockable(),
Type: GQLInterfaceLockable.List,
Resolve: GQLLockableDependencies,
})
}
return gql_type_simple_lockable
}
}, nil)
var gql_type_simple_node *graphql.Object = nil
func GQLTypeGraphNode() * graphql.Object {
if gql_type_simple_node == nil {
gql_type_simple_node = graphql.NewObject(graphql.ObjectConfig{
var GQLTypeGraphNode = NewSingleton(func() *graphql.Object {
object := graphql.NewObject(graphql.ObjectConfig{
Name: "GraphNode",
Interfaces: []*graphql.Interface{
GQLInterfaceNode(),
GQLInterfaceNode.Type,
},
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
ctx, ok := p.Context.Value("graph_context").(*Context)
@ -469,24 +440,21 @@ func GQLTypeGraphNode() * graphql.Object {
Fields: graphql.Fields{},
})
gql_type_simple_node.AddFieldConfig("ID", &graphql.Field{
object.AddFieldConfig("ID", &graphql.Field{
Type: graphql.String,
Resolve: GQLNodeID,
})
gql_type_simple_node.AddFieldConfig("Name", &graphql.Field{
object.AddFieldConfig("Name", &graphql.Field{
Type: graphql.String,
Resolve: GQLLockableName,
})
}
return gql_type_simple_node
}
return object
}, nil)
var gql_type_signal *graphql.Object = nil
func GQLTypeSignal() *graphql.Object {
if gql_type_signal == nil {
gql_type_signal = graphql.NewObject(graphql.ObjectConfig{
var GQLTypeSignal = NewSingleton(func() *graphql.Object {
gql_type_signal := graphql.NewObject(graphql.ObjectConfig{
Name: "SignalOut",
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
_, ok := p.Value.(GraphSignal)
@ -511,14 +479,11 @@ func GQLTypeSignal() *graphql.Object {
Type: graphql.String,
Resolve: GQLSignalString,
})
}
return gql_type_signal
}
}, nil)
var gql_type_signal_input *graphql.InputObject = nil
func GQLTypeSignalInput() *graphql.InputObject {
if gql_type_signal_input == nil {
gql_type_signal_input = graphql.NewInputObject(graphql.InputObjectConfig{
var GQLTypeSignalInput = NewSingleton(func()*graphql.InputObject {
gql_type_signal_input := graphql.NewInputObject(graphql.InputObjectConfig{
Name: "SignalIn",
Fields: graphql.InputObjectConfigFieldMap{},
})
@ -530,7 +495,7 @@ func GQLTypeSignalInput() *graphql.InputObject {
Type: graphql.String,
DefaultValue: "down",
})
}
return gql_type_signal_input
}
}, nil)

@ -101,6 +101,12 @@ func (node * GraphNode) Serialize() ([]byte, error) {
}
func (node *GraphNode) Allowed(action string, resource string, principal Node) error {
if principal == nil {
return fmt.Errorf("nil is not allowed to perform any actions")
}
if node.ID() == principal.ID() {
return nil
}
for _, policy := range(node.policies) {
if policy.Allows(action, resource, principal) == true {
return nil