diff --git a/context.go b/context.go index 9c12447..8d3029b 100644 --- a/context.go +++ b/context.go @@ -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 { diff --git a/gql_mutation.go b/gql_mutation.go index 47d013b..ed105b7 100644 --- a/gql_mutation.go +++ b/gql_mutation.go @@ -4,135 +4,130 @@ 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(), - Args: graphql.FieldConfigArgument{ - "id": &graphql.ArgumentConfig{ - Type: graphql.String, - }, - "signal": &graphql.ArgumentConfig{ - Type: GQLTypeSignalInput(), - }, +var GQLMutationSendUpdate = NewField(func()*graphql.Field { + gql_mutation_send_update := &graphql.Field{ + Type: GQLTypeSignal.Type, + Args: graphql.FieldConfigArgument{ + "id": &graphql.ArgumentConfig{ + Type: graphql.String, }, - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - ctx, server, user, err := PrepResolve(p) - if err != nil { - return nil, err - } - - err = server.Allowed("signal", "self", user) - if err != nil { - return nil, err - } - - signal_map, err := ExtractParam[map[string]interface{}](p, "signal") - if err != nil { - return nil, err - } - - var signal GraphSignal = nil - if signal_map["Direction"] == "up" { - signal = NewSignal(server, signal_map["Type"].(string)) - } else if signal_map["Direction"] == "down" { - signal = NewDownSignal(server, signal_map["Type"].(string)) - } else if signal_map["Direction"] == "direct" { - signal = NewDirectSignal(server, signal_map["Type"].(string)) - } else { - return nil, fmt.Errorf("Bad direction: %d", signal_map["Direction"]) - } - - id, err := ExtractID(p, "id") - if err != nil { - return nil, err - } - - var node Node = nil - err = UseStates(ctx, []Node{server}, func(nodes NodeMap) (error){ - node = FindChild(ctx, server, id, nodes) - if node == nil { - return fmt.Errorf("Failed to find ID: %s as child of server thread", id) - } - node.Signal(ctx, signal, nodes) - return nil - }) - if err != nil { - return nil, err - } - - return signal, nil + "signal": &graphql.ArgumentConfig{ + Type: GQLTypeSignalInput.Type, }, - } + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + ctx, server, user, err := PrepResolve(p) + if err != nil { + return nil, err + } + + err = server.Allowed("signal", "self", user) + if err != nil { + return nil, err + } + + signal_map, err := ExtractParam[map[string]interface{}](p, "signal") + if err != nil { + return nil, err + } + + var signal GraphSignal = nil + if signal_map["Direction"] == "up" { + signal = NewSignal(server, signal_map["Type"].(string)) + } else if signal_map["Direction"] == "down" { + signal = NewDownSignal(server, signal_map["Type"].(string)) + } else if signal_map["Direction"] == "direct" { + signal = NewDirectSignal(server, signal_map["Type"].(string)) + } else { + return nil, fmt.Errorf("Bad direction: %d", signal_map["Direction"]) + } + + id, err := ExtractID(p, "id") + if err != nil { + return nil, err + } + + var node Node = nil + err = UseStates(ctx, []Node{server}, func(nodes NodeMap) (error){ + node = FindChild(ctx, server, id, nodes) + if node == nil { + return fmt.Errorf("Failed to find ID: %s as child of server thread", id) + } + node.Signal(ctx, signal, nodes) + return nil + }) + if err != nil { + return nil, err + } + + 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(), - Args: graphql.FieldConfigArgument{ - "parent_id": &graphql.ArgumentConfig{ - Type: graphql.String, - }, - "child_id": &graphql.ArgumentConfig{ - Type: graphql.String, - }, - "action": &graphql.ArgumentConfig{ - Type: graphql.String, - DefaultValue: "start", - }, +}) + +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, }, - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - ctx, server, user, err := PrepResolve(p) - if err != nil { - return nil, err - } - - err = server.Allowed("start_child", "self", user) - if err != nil { - return nil, err - } - - parent_id, err := ExtractID(p, "parent_id") - if err != nil { - return nil, err - } - - child_id, err := ExtractID(p, "child_id") - if err != nil { - return nil, err - } - - action, err := ExtractParam[string](p, "action") - if err != nil { - return nil, err + "child_id": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + "action": &graphql.ArgumentConfig{ + Type: graphql.String, + DefaultValue: "start", + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + ctx, server, user, err := PrepResolve(p) + if err != nil { + return nil, err + } + + err = server.Allowed("start_child", "self", user) + if err != nil { + return nil, err + } + + parent_id, err := ExtractID(p, "parent_id") + if err != nil { + return nil, err + } + + child_id, err := ExtractID(p, "child_id") + if err != nil { + return nil, err + } + + action, err := ExtractParam[string](p, "action") + if err != nil { + return nil, err + } + + var signal GraphSignal + err = UseStates(ctx, []Node{server}, func(nodes NodeMap) (error){ + node := FindChild(ctx, server, parent_id, nodes) + if node == nil { + return fmt.Errorf("Failed to find ID: %s as child of server thread", parent_id) } - - var signal GraphSignal - err = UseStates(ctx, []Node{server}, func(nodes NodeMap) (error){ - node := FindChild(ctx, server, parent_id, nodes) - if node == nil { - return fmt.Errorf("Failed to find ID: %s as child of server thread", parent_id) - } - return UseMoreStates(ctx, []Node{node}, nodes, func(NodeMap) error { - signal = NewStartChildSignal(server, child_id, action) - return node.Signal(ctx, signal, nodes) - }) + return UseMoreStates(ctx, []Node{node}, nodes, func(NodeMap) error { + signal = NewStartChildSignal(server, child_id, action) + return node.Signal(ctx, signal, nodes) }) - if err != nil { - return nil, err - } - - // TODO: wait for the result of the signal to send back instead of just the signal - return signal, nil - }, - } + }) + if err != nil { + return nil, err + } + + // TODO: wait for the result of the signal to send back instead of just the signal + return signal, nil + }, } return gql_mutation_start_child -} +}) + diff --git a/gql_query.go b/gql_query.go index 26a4f03..2225357 100644 --- a/gql_query.go +++ b/gql_query.go @@ -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(), - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - _, server, user, err := PrepResolve(p) +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 + } - if err != nil { - return nil, err - } + err = server.Allowed("enumerate", "self", user) + 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 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 server, nil - }, + err = user.Allowed("enumerate", "self", user) + if err != nil { + return nil, err } - } - return gql_query_self + return user, nil + }, } diff --git a/gql_subscribe.go b/gql_subscribe.go index d1868ad..46f99c4 100644 --- a/gql_subscribe.go +++ b/gql_subscribe.go @@ -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(), - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - return p.Source, nil - }, - Subscribe: GQLSubscribeSelf, - } +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(), - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - return p.Source, nil - }, - Subscribe: GQLSubscribeSignal, - } +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 -} +}) diff --git a/gql_test.go b/gql_test.go index 187213c..7a92aaf 100644 --- a/gql_test.go +++ b/gql_test.go @@ -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) diff --git a/gql_types.go b/gql_types.go index 755b527..7b3c1b2 100644 --- a/gql_types.go +++ b/gql_types.go @@ -5,532 +5,497 @@ 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{ - Name: "Node", - ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil - } - - valid_nodes := ctx.GQL.ValidNodes - node_type := ctx.GQL.NodeType - p_type := reflect.TypeOf(p.Value) - - for key, value := range(valid_nodes) { - if p_type == key { - return value - } - } - - if p_type.Implements(node_type) { - return GQLTypeGraphNode() - } +type Field *graphql.Field - return nil - }, - Fields: graphql.Fields{}, - }) - - gql_interface_graph_node.AddFieldConfig("ID", &graphql.Field{ - Type: graphql.String, - }) - } - - return gql_interface_graph_node +func NewField(init func()*graphql.Field) Field { + return Field(init()) } -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 +type Singleton[K graphql.Type] struct { + Type K + List *graphql.List } -var gql_interface_thread *graphql.Interface = nil -func GQLInterfaceThread() *graphql.Interface { - if gql_interface_thread == nil { - gql_interface_thread = graphql.NewInterface(graphql.InterfaceConfig{ - Name: "Thread", - ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil - } - - valid_threads := ctx.GQL.ValidThreads - thread_type := ctx.GQL.ThreadType - p_type := reflect.TypeOf(p.Value) - - for key, value := range(valid_threads) { - if p_type == key { - return value - } - } - - if p_type.Implements(thread_type) { - return GQLTypeSimpleThread() - } - - ctx.Log.Logf("gql", "Found no type that matches %+v: %+v", p_type, p_type.Implements(thread_type)) - return nil - }, - Fields: graphql.Fields{}, - }) - - gql_interface_thread.AddFieldConfig("ID", &graphql.Field{ - Type: graphql.String, - }) - - gql_interface_thread.AddFieldConfig("Name", &graphql.Field{ - Type: graphql.String, - }) - - gql_interface_thread.AddFieldConfig("State", &graphql.Field{ - 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(), - }) - - gql_interface_thread.AddFieldConfig("Dependencies", &graphql.Field{ - Type: GQLListLockable(), - }) - - gql_interface_thread.AddFieldConfig("Owner", &graphql.Field{ - Type: GQLInterfaceLockable(), - }) +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 gql_interface_thread -} - -var gql_list_lockable *graphql.List = nil -func GQLListLockable() *graphql.List { - if gql_list_lockable == nil { - gql_list_lockable = graphql.NewList(GQLInterfaceLockable()) + return &Singleton[K]{ + Type: val, + List: list, } - return gql_list_lockable } -var gql_interface_lockable *graphql.Interface = nil -func GQLInterfaceLockable() *graphql.Interface { - if gql_interface_lockable == nil { - gql_interface_lockable = graphql.NewInterface(graphql.InterfaceConfig{ - Name: "Lockable", - ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return nil - } +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) + if ok == false { + return nil + } - valid_lockables := ctx.GQL.ValidLockables - lockable_type := ctx.GQL.LockableType - p_type := reflect.TypeOf(p.Value) + valid_nodes := ctx.GQL.ValidNodes + node_type := ctx.GQL.NodeType + p_type := reflect.TypeOf(p.Value) - for key, value := range(valid_lockables) { - if p_type == key { - return value - } - } - - if p_type.Implements(lockable_type) { - return GQLTypeSimpleLockable() + for key, value := range(valid_nodes) { + if p_type == key { + return value } + } + + if p_type.Implements(node_type) { + return ctx.GQL.BaseNodeType + } + + return nil + }, + Fields: graphql.Fields{}, + }) + i.AddFieldConfig("ID", &graphql.Field{ + Type: graphql.String, + }) + return i +}, nil) + +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) + if ok == false { return nil - }, - Fields: graphql.Fields{}, - }) + } - gql_interface_lockable.AddFieldConfig("ID", &graphql.Field{ - Type: graphql.String, - }) + valid_threads := ctx.GQL.ValidThreads + thread_type := ctx.GQL.ThreadType + p_type := reflect.TypeOf(p.Value) - gql_interface_lockable.AddFieldConfig("Name", &graphql.Field{ - Type: graphql.String, - }) + for key, value := range(valid_threads) { + if p_type == key { + return value + } + } - if gql_list_lockable == nil { - gql_list_lockable = graphql.NewList(gql_interface_lockable) - } + if p_type.Implements(thread_type) { + return ctx.GQL.BaseThreadType + } - gql_interface_lockable.AddFieldConfig("Requirements", &graphql.Field{ - Type: gql_list_lockable, - }) + ctx.Log.Logf("gql", "Found no type that matches %+v: %+v", p_type, p_type.Implements(thread_type)) + return nil + }, + Fields: graphql.Fields{}, + }) - gql_interface_lockable.AddFieldConfig("Dependencies", &graphql.Field{ - Type: gql_list_lockable, - }) + gql_interface_thread.AddFieldConfig("ID", &graphql.Field{ + Type: graphql.String, + }) - gql_interface_lockable.AddFieldConfig("Owner", &graphql.Field{ - Type: gql_interface_lockable, - }) + gql_interface_thread.AddFieldConfig("Name", &graphql.Field{ + Type: graphql.String, + }) - } + gql_interface_thread.AddFieldConfig("State", &graphql.Field{ + Type: graphql.String, + }) - return gql_interface_lockable -} + gql_interface_thread.AddFieldConfig("Requirements", &graphql.Field{ + Type: GQLInterfaceLockable.List, + }) -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 -} + gql_interface_thread.AddFieldConfig("Dependencies", &graphql.Field{ + Type: GQLInterfaceLockable.List, + }) -var gql_type_user *graphql.Object = nil -func GQLTypeUser() * graphql.Object { - if gql_type_user == nil { - gql_type_user = graphql.NewObject(graphql.ObjectConfig{ - Name: "User", - Interfaces: []*graphql.Interface{ - GQLInterfaceNode(), - GQLInterfaceLockable(), - }, - IsTypeOf: func(p graphql.IsTypeOfParams) bool { - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return false - } + gql_interface_thread.AddFieldConfig("Owner", &graphql.Field{ + Type: GQLInterfaceLockable.Type, + }) - lockable_type := ctx.GQL.LockableType - value_type := reflect.TypeOf(p.Value) + return gql_interface_thread +}, func(thread *graphql.Interface, thread_list *graphql.List) { + thread.AddFieldConfig("Children", &graphql.Field{ + Type: thread_list, + }) + + thread.AddFieldConfig("Parent", &graphql.Field{ + Type: thread, + }) + +}) + +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) + if ok == false { + return nil + } - if value_type.Implements(lockable_type) { - return true - } + valid_lockables := ctx.GQL.ValidLockables + lockable_type := ctx.GQL.LockableType + p_type := reflect.TypeOf(p.Value) + for key, value := range(valid_lockables) { + if p_type == key { + return value + } + } + + if p_type.Implements(lockable_type) { + return ctx.GQL.BaseThreadType + } + return nil + }, + Fields: graphql.Fields{}, + }) + + gql_interface_lockable.AddFieldConfig("ID", &graphql.Field{ + Type: graphql.String, + }) + + gql_interface_lockable.AddFieldConfig("Name", &graphql.Field{ + Type: graphql.String, + }) + return gql_interface_lockable +}, func(lockable *graphql.Interface, lockable_list *graphql.List) { + lockable.AddFieldConfig("Requirements", &graphql.Field{ + Type: lockable_list, + }) + + lockable.AddFieldConfig("Dependencies", &graphql.Field{ + Type: lockable_list, + }) + + lockable.AddFieldConfig("Owner", &graphql.Field{ + Type: lockable, + }) +}) + +var GQLTypeUser = NewSingleton(func() *graphql.Object { + gql_type_user := graphql.NewObject(graphql.ObjectConfig{ + Name: "User", + Interfaces: []*graphql.Interface{ + GQLInterfaceNode.Type, + GQLInterfaceLockable.Type, + }, + IsTypeOf: func(p graphql.IsTypeOfParams) bool { + ctx, ok := p.Context.Value("graph_context").(*Context) + if ok == false { return false - }, - Fields: graphql.Fields{}, - }) - - gql_type_user.AddFieldConfig("ID", &graphql.Field{ - Type: graphql.String, - Resolve: GQLNodeID, - }) - - gql_type_user.AddFieldConfig("Name", &graphql.Field{ - Type: graphql.String, - Resolve: GQLLockableName, - }) - - gql_type_user.AddFieldConfig("Requirements", &graphql.Field{ - Type: GQLListLockable(), - Resolve: GQLLockableRequirements, - }) - - gql_type_user.AddFieldConfig("Owner", &graphql.Field{ - Type: GQLInterfaceLockable(), - Resolve: GQLLockableOwner, - }) - - gql_type_user.AddFieldConfig("Dependencies", &graphql.Field{ - Type: GQLListLockable(), - Resolve: GQLLockableDependencies, - }) - } + } + + lockable_type := ctx.GQL.LockableType + value_type := reflect.TypeOf(p.Value) + + if value_type.Implements(lockable_type) { + return true + } + + return false + }, + Fields: graphql.Fields{}, + }) + + gql_type_user.AddFieldConfig("ID", &graphql.Field{ + Type: graphql.String, + Resolve: GQLNodeID, + }) + + gql_type_user.AddFieldConfig("Name", &graphql.Field{ + Type: graphql.String, + Resolve: GQLLockableName, + }) + + gql_type_user.AddFieldConfig("Requirements", &graphql.Field{ + Type: GQLInterfaceLockable.List, + Resolve: GQLLockableRequirements, + }) + + gql_type_user.AddFieldConfig("Owner", &graphql.Field{ + Type: GQLInterfaceLockable.Type, + Resolve: GQLLockableOwner, + }) + + gql_type_user.AddFieldConfig("Dependencies", &graphql.Field{ + Type: GQLInterfaceLockable.List, + Resolve: GQLLockableDependencies, + }) return gql_type_user -} - -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{ - Name: "GQLThread", - Interfaces: []*graphql.Interface{ - GQLInterfaceNode(), - GQLInterfaceThread(), - GQLInterfaceLockable(), - }, - IsTypeOf: func(p graphql.IsTypeOfParams) bool { - _, ok := p.Value.(*GQLThread) - return ok - }, - Fields: graphql.Fields{}, - }) - - gql_type_gql_thread.AddFieldConfig("ID", &graphql.Field{ - Type: graphql.String, - Resolve: GQLNodeID, - }) - - gql_type_gql_thread.AddFieldConfig("Name", &graphql.Field{ - Type: graphql.String, - Resolve: GQLLockableName, - }) - - gql_type_gql_thread.AddFieldConfig("State", &graphql.Field{ - Type: graphql.String, - Resolve: GQLThreadState, - }) - - gql_type_gql_thread.AddFieldConfig("Children", &graphql.Field{ - Type: GQLListThread(), - Resolve: GQLThreadChildren, - }) - - gql_type_gql_thread.AddFieldConfig("Parent", &graphql.Field{ - Type: GQLInterfaceThread(), - Resolve: GQLThreadParent, - }) - - gql_type_gql_thread.AddFieldConfig("Listen", &graphql.Field{ - Type: graphql.String, - Resolve: GQLThreadListen, - }) - - gql_type_gql_thread.AddFieldConfig("Requirements", &graphql.Field{ - Type: GQLListLockable(), - Resolve: GQLLockableRequirements, - }) - - gql_type_gql_thread.AddFieldConfig("Owner", &graphql.Field{ - Type: GQLInterfaceLockable(), - Resolve: GQLLockableOwner, - }) - - gql_type_gql_thread.AddFieldConfig("Dependencies", &graphql.Field{ - Type: GQLListLockable(), - Resolve: GQLLockableDependencies, - }) - - gql_type_gql_thread.AddFieldConfig("Users", &graphql.Field{ - Type: GQLListUser(), - Resolve: GQLThreadUsers, - }) - } +}, nil) + +var GQLTypeGQLThread = NewSingleton(func() *graphql.Object { + gql_type_gql_thread := graphql.NewObject(graphql.ObjectConfig{ + Name: "GQLThread", + Interfaces: []*graphql.Interface{ + GQLInterfaceNode.Type, + GQLInterfaceThread.Type, + GQLInterfaceLockable.Type, + }, + IsTypeOf: func(p graphql.IsTypeOfParams) bool { + _, ok := p.Value.(*GQLThread) + return ok + }, + Fields: graphql.Fields{}, + }) + + gql_type_gql_thread.AddFieldConfig("ID", &graphql.Field{ + Type: graphql.String, + Resolve: GQLNodeID, + }) + + gql_type_gql_thread.AddFieldConfig("Name", &graphql.Field{ + Type: graphql.String, + Resolve: GQLLockableName, + }) + + gql_type_gql_thread.AddFieldConfig("State", &graphql.Field{ + Type: graphql.String, + Resolve: GQLThreadState, + }) + + gql_type_gql_thread.AddFieldConfig("Children", &graphql.Field{ + Type: GQLInterfaceThread.List, + Resolve: GQLThreadChildren, + }) + + gql_type_gql_thread.AddFieldConfig("Parent", &graphql.Field{ + Type: GQLInterfaceThread.Type, + Resolve: GQLThreadParent, + }) + + gql_type_gql_thread.AddFieldConfig("Listen", &graphql.Field{ + Type: graphql.String, + Resolve: GQLThreadListen, + }) + + gql_type_gql_thread.AddFieldConfig("Requirements", &graphql.Field{ + Type: GQLInterfaceLockable.List, + Resolve: GQLLockableRequirements, + }) + + gql_type_gql_thread.AddFieldConfig("Owner", &graphql.Field{ + Type: GQLInterfaceLockable.Type, + Resolve: GQLLockableOwner, + }) + + gql_type_gql_thread.AddFieldConfig("Dependencies", &graphql.Field{ + Type: GQLInterfaceLockable.List, + Resolve: GQLLockableDependencies, + }) + + gql_type_gql_thread.AddFieldConfig("Users", &graphql.Field{ + Type: GQLTypeUser.List, + Resolve: GQLThreadUsers, + }) return gql_type_gql_thread -} - -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{ - Name: "SimpleThread", - Interfaces: []*graphql.Interface{ - GQLInterfaceNode(), - GQLInterfaceThread(), - GQLInterfaceLockable(), - }, - IsTypeOf: func(p graphql.IsTypeOfParams) bool { - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return false - } - - thread_type := ctx.GQL.ThreadType - - value_type := reflect.TypeOf(p.Value) - - if value_type.Implements(thread_type) { - return true - } - +}, nil) + +var GQLTypeSimpleThread = NewSingleton(func() *graphql.Object { + gql_type_simple_thread := graphql.NewObject(graphql.ObjectConfig{ + Name: "SimpleThread", + Interfaces: []*graphql.Interface{ + GQLInterfaceNode.Type, + GQLInterfaceThread.Type, + GQLInterfaceLockable.Type, + }, + IsTypeOf: func(p graphql.IsTypeOfParams) bool { + ctx, ok := p.Context.Value("graph_context").(*Context) + if ok == false { return false - }, - Fields: graphql.Fields{}, - }) - gql_type_simple_thread.AddFieldConfig("ID", &graphql.Field{ - Type: graphql.String, - Resolve: GQLNodeID, - }) - - gql_type_simple_thread.AddFieldConfig("Name", &graphql.Field{ - Type: graphql.String, - Resolve: GQLLockableName, - }) - - gql_type_simple_thread.AddFieldConfig("State", &graphql.Field{ - Type: graphql.String, - Resolve: GQLThreadState, - }) - - gql_type_simple_thread.AddFieldConfig("Children", &graphql.Field{ - Type: GQLListThread(), - Resolve: GQLThreadChildren, - }) - - gql_type_simple_thread.AddFieldConfig("Parent", &graphql.Field{ - Type: GQLInterfaceThread(), - Resolve: GQLThreadParent, - }) - - gql_type_simple_thread.AddFieldConfig("Requirements", &graphql.Field{ - Type: GQLListLockable(), - Resolve: GQLLockableRequirements, - }) - - gql_type_simple_thread.AddFieldConfig("Owner", &graphql.Field{ - Type: GQLInterfaceLockable(), - Resolve: GQLLockableOwner, - }) - - gql_type_simple_thread.AddFieldConfig("Dependencies", &graphql.Field{ - Type: GQLListLockable(), - Resolve: GQLLockableDependencies, - }) - } - return gql_type_simple_thread -} + } + + thread_type := ctx.GQL.ThreadType + + value_type := reflect.TypeOf(p.Value) + + if value_type.Implements(thread_type) { + return true + } + + return false + }, + Fields: graphql.Fields{}, + }) + gql_type_simple_thread.AddFieldConfig("ID", &graphql.Field{ + Type: graphql.String, + Resolve: GQLNodeID, + }) + + gql_type_simple_thread.AddFieldConfig("Name", &graphql.Field{ + Type: graphql.String, + Resolve: GQLLockableName, + }) + + gql_type_simple_thread.AddFieldConfig("State", &graphql.Field{ + Type: graphql.String, + Resolve: GQLThreadState, + }) + + gql_type_simple_thread.AddFieldConfig("Children", &graphql.Field{ + Type: GQLInterfaceThread.List, + Resolve: GQLThreadChildren, + }) + + gql_type_simple_thread.AddFieldConfig("Parent", &graphql.Field{ + Type: GQLInterfaceThread.Type, + Resolve: GQLThreadParent, + }) + + gql_type_simple_thread.AddFieldConfig("Requirements", &graphql.Field{ + Type: GQLInterfaceLockable.List, + Resolve: GQLLockableRequirements, + }) + + gql_type_simple_thread.AddFieldConfig("Owner", &graphql.Field{ + Type: GQLInterfaceLockable.Type, + Resolve: GQLLockableOwner, + }) + + gql_type_simple_thread.AddFieldConfig("Dependencies", &graphql.Field{ + Type: GQLInterfaceLockable.List, + Resolve: GQLLockableDependencies, + }) -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{ - Name: "SimpleLockable", - Interfaces: []*graphql.Interface{ - GQLInterfaceNode(), - GQLInterfaceLockable(), - }, - IsTypeOf: func(p graphql.IsTypeOfParams) bool { - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return false - } + return gql_type_simple_thread +}, nil) + +var GQLTypeSimpleLockable = NewSingleton(func() *graphql.Object { + gql_type_simple_lockable := graphql.NewObject(graphql.ObjectConfig{ + Name: "SimpleLockable", + Interfaces: []*graphql.Interface{ + GQLInterfaceNode.Type, + GQLInterfaceLockable.Type, + }, + IsTypeOf: func(p graphql.IsTypeOfParams) bool { + ctx, ok := p.Context.Value("graph_context").(*Context) + if ok == false { + return false + } - lockable_type := ctx.GQL.LockableType - value_type := reflect.TypeOf(p.Value) + lockable_type := ctx.GQL.LockableType + value_type := reflect.TypeOf(p.Value) - if value_type.Implements(lockable_type) { - return true - } + if value_type.Implements(lockable_type) { + return true + } - return false - }, - Fields: graphql.Fields{}, - }) - - gql_type_simple_lockable.AddFieldConfig("ID", &graphql.Field{ - Type: graphql.String, - Resolve: GQLNodeID, - }) - - gql_type_simple_lockable.AddFieldConfig("Name", &graphql.Field{ - Type: graphql.String, - Resolve: GQLLockableName, - }) - - gql_type_simple_lockable.AddFieldConfig("Requirements", &graphql.Field{ - Type: GQLListLockable(), - Resolve: GQLLockableRequirements, - }) - - gql_type_simple_lockable.AddFieldConfig("Owner", &graphql.Field{ - Type: GQLInterfaceLockable(), - Resolve: GQLLockableOwner, - }) - - gql_type_simple_lockable.AddFieldConfig("Dependencies", &graphql.Field{ - Type: GQLListLockable(), - Resolve: GQLLockableDependencies, - }) - } - return gql_type_simple_lockable -} + return false + }, + Fields: graphql.Fields{}, + }) -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{ - Name: "GraphNode", - Interfaces: []*graphql.Interface{ - GQLInterfaceNode(), - }, - IsTypeOf: func(p graphql.IsTypeOfParams) bool { - ctx, ok := p.Context.Value("graph_context").(*Context) - if ok == false { - return false - } + gql_type_simple_lockable.AddFieldConfig("ID", &graphql.Field{ + Type: graphql.String, + Resolve: GQLNodeID, + }) - node_type := ctx.GQL.NodeType - value_type := reflect.TypeOf(p.Value) + gql_type_simple_lockable.AddFieldConfig("Name", &graphql.Field{ + Type: graphql.String, + Resolve: GQLLockableName, + }) - if value_type.Implements(node_type) { - return true - } + gql_type_simple_lockable.AddFieldConfig("Requirements", &graphql.Field{ + Type: GQLInterfaceLockable.List, + Resolve: GQLLockableRequirements, + }) - return false - }, - Fields: graphql.Fields{}, - }) - - gql_type_simple_node.AddFieldConfig("ID", &graphql.Field{ - Type: graphql.String, - Resolve: GQLNodeID, - }) - - gql_type_simple_node.AddFieldConfig("Name", &graphql.Field{ - Type: graphql.String, - Resolve: GQLLockableName, - }) - } + gql_type_simple_lockable.AddFieldConfig("Owner", &graphql.Field{ + Type: GQLInterfaceLockable.Type, + Resolve: GQLLockableOwner, + }) - return gql_type_simple_node -} + gql_type_simple_lockable.AddFieldConfig("Dependencies", &graphql.Field{ + Type: GQLInterfaceLockable.List, + Resolve: GQLLockableDependencies, + }) -var gql_type_signal *graphql.Object = nil -func GQLTypeSignal() *graphql.Object { - if gql_type_signal == nil { - gql_type_signal = graphql.NewObject(graphql.ObjectConfig{ - Name: "SignalOut", - IsTypeOf: func(p graphql.IsTypeOfParams) bool { - _, ok := p.Value.(GraphSignal) - return ok - }, - Fields: graphql.Fields{}, - }) - - gql_type_signal.AddFieldConfig("Type", &graphql.Field{ - Type: graphql.String, - Resolve: GQLSignalType, - }) - gql_type_signal.AddFieldConfig("Source", &graphql.Field{ - Type: graphql.String, - Resolve: GQLSignalSource, - }) - gql_type_signal.AddFieldConfig("Direction", &graphql.Field{ - Type: graphql.String, - Resolve: GQLSignalDirection, - }) - gql_type_signal.AddFieldConfig("String", &graphql.Field{ - Type: graphql.String, - Resolve: GQLSignalString, - }) - } + return gql_type_simple_lockable +}, nil) + +var GQLTypeGraphNode = NewSingleton(func() *graphql.Object { + object := graphql.NewObject(graphql.ObjectConfig{ + Name: "GraphNode", + Interfaces: []*graphql.Interface{ + GQLInterfaceNode.Type, + }, + IsTypeOf: func(p graphql.IsTypeOfParams) bool { + ctx, ok := p.Context.Value("graph_context").(*Context) + if ok == false { + return false + } + + node_type := ctx.GQL.NodeType + value_type := reflect.TypeOf(p.Value) + + if value_type.Implements(node_type) { + return true + } + + return false + }, + Fields: graphql.Fields{}, + }) + + object.AddFieldConfig("ID", &graphql.Field{ + Type: graphql.String, + Resolve: GQLNodeID, + }) + + object.AddFieldConfig("Name", &graphql.Field{ + Type: graphql.String, + Resolve: GQLLockableName, + }) + + return object +}, nil) + +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) + return ok + }, + Fields: graphql.Fields{}, + }) + + gql_type_signal.AddFieldConfig("Type", &graphql.Field{ + Type: graphql.String, + Resolve: GQLSignalType, + }) + gql_type_signal.AddFieldConfig("Source", &graphql.Field{ + Type: graphql.String, + Resolve: GQLSignalSource, + }) + gql_type_signal.AddFieldConfig("Direction", &graphql.Field{ + Type: graphql.String, + Resolve: GQLSignalDirection, + }) + gql_type_signal.AddFieldConfig("String", &graphql.Field{ + Type: graphql.String, + Resolve: GQLSignalString, + }) return gql_type_signal -} +}, nil) + +var GQLTypeSignalInput = NewSingleton(func()*graphql.InputObject { + gql_type_signal_input := graphql.NewInputObject(graphql.InputObjectConfig{ + Name: "SignalIn", + Fields: graphql.InputObjectConfigFieldMap{}, + }) + gql_type_signal_input.AddFieldConfig("Type", &graphql.InputObjectFieldConfig{ + Type: graphql.String, + DefaultValue: "cancel", + }) + gql_type_signal_input.AddFieldConfig("Direction", &graphql.InputObjectFieldConfig{ + Type: graphql.String, + DefaultValue: "down", + }) -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{ - Name: "SignalIn", - Fields: graphql.InputObjectConfigFieldMap{}, - }) - gql_type_signal_input.AddFieldConfig("Type", &graphql.InputObjectFieldConfig{ - Type: graphql.String, - DefaultValue: "cancel", - }) - gql_type_signal_input.AddFieldConfig("Direction", &graphql.InputObjectFieldConfig{ - Type: graphql.String, - DefaultValue: "down", - }) - } return gql_type_signal_input -} +}, nil) diff --git a/node.go b/node.go index f0a99fc..4248621 100644 --- a/node.go +++ b/node.go @@ -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