From 4f587820d129d750342925b51a72977cc130c45a Mon Sep 17 00:00:00 2001 From: Kevin Kandlbinder Date: Thu, 24 Mar 2022 16:35:45 +0100 Subject: [PATCH] api: Update graphql schema --- graph/generated/generated.go | 361 ++++++++++++++++++----------------- graph/helpers.go | 24 +++ graph/model/list.go | 2 + graph/model/models_gen.go | 11 +- graph/schema.graphqls | 15 +- graph/schema.resolvers.go | 335 ++++++++++++++++++++++++++++++-- internal/db/db.go | 8 +- internal/db/model/entry.go | 21 ++ internal/db/model/list.go | 1 + 9 files changed, 578 insertions(+), 200 deletions(-) diff --git a/graph/generated/generated.go b/graph/generated/generated.go index 9477a1d..4422b01 100644 --- a/graph/generated/generated.go +++ b/graph/generated/generated.go @@ -109,17 +109,17 @@ type ComplexityRoot struct { } Mutation struct { - AddMxid func(childComplexity int, input model.AddMxid) int - AddToList func(childComplexity int, input model.AddToList) int - CommentEntry func(childComplexity int, input model.CommentEntry) int - CommentList func(childComplexity int, input model.CommentList) int - CreateEntry func(childComplexity int, input model.CreateEntry) int - CreateList func(childComplexity int, input model.CreateList) int - DeleteEntry func(childComplexity int, input string) int - DeleteList func(childComplexity int, input string) int - Login func(childComplexity int, input model.Login) int - Register func(childComplexity int, input model.Register) int - RemoveMxid func(childComplexity int, input model.RemoveMxid) int + AddMxid func(childComplexity int, input model.AddMxid) int + AddToLists func(childComplexity int, input model.AddToLists) int + CommentEntry func(childComplexity int, input model.CommentEntry) int + CommentList func(childComplexity int, input model.CommentList) int + CreateEntry func(childComplexity int, input model.CreateEntry) int + CreateList func(childComplexity int, input model.CreateList) int + DeleteList func(childComplexity int, input string) int + Login func(childComplexity int, input model.Login) int + Register func(childComplexity int, input model.Register) int + RemoveFromLists func(childComplexity int, input model.RemoveFromLists) int + RemoveMxid func(childComplexity int, input model.RemoveMxid) int } PageInfo struct { @@ -180,10 +180,10 @@ type MutationResolver interface { RemoveMxid(ctx context.Context, input model.RemoveMxid) (*model.User, error) CreateEntry(ctx context.Context, input model.CreateEntry) (*model.Entry, error) CommentEntry(ctx context.Context, input model.CommentEntry) (*model.Entry, error) - DeleteEntry(ctx context.Context, input string) (bool, error) + AddToLists(ctx context.Context, input model.AddToLists) (*model.Entry, error) + RemoveFromLists(ctx context.Context, input model.RemoveFromLists) (*model.Entry, error) CreateList(ctx context.Context, input model.CreateList) (*model.List, error) CommentList(ctx context.Context, input model.CommentList) (*model.List, error) - AddToList(ctx context.Context, input model.AddToList) (*model.List, error) DeleteList(ctx context.Context, input string) (bool, error) } type QueryResolver interface { @@ -451,17 +451,17 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.AddMxid(childComplexity, args["input"].(model.AddMxid)), true - case "Mutation.addToList": - if e.complexity.Mutation.AddToList == nil { + case "Mutation.addToLists": + if e.complexity.Mutation.AddToLists == nil { break } - args, err := ec.field_Mutation_addToList_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_addToLists_args(context.TODO(), rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.AddToList(childComplexity, args["input"].(model.AddToList)), true + return e.complexity.Mutation.AddToLists(childComplexity, args["input"].(model.AddToLists)), true case "Mutation.commentEntry": if e.complexity.Mutation.CommentEntry == nil { @@ -511,18 +511,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.CreateList(childComplexity, args["input"].(model.CreateList)), true - case "Mutation.deleteEntry": - if e.complexity.Mutation.DeleteEntry == nil { - break - } - - args, err := ec.field_Mutation_deleteEntry_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Mutation.DeleteEntry(childComplexity, args["input"].(string)), true - case "Mutation.deleteList": if e.complexity.Mutation.DeleteList == nil { break @@ -559,6 +547,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.Register(childComplexity, args["input"].(model.Register)), true + case "Mutation.removeFromLists": + if e.complexity.Mutation.RemoveFromLists == nil { + break + } + + args, err := ec.field_Mutation_removeFromLists_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.RemoveFromLists(childComplexity, args["input"].(model.RemoveFromLists)), true + case "Mutation.removeMXID": if e.complexity.Mutation.RemoveMxid == nil { break @@ -846,7 +846,7 @@ type User { admin: Boolean matrixLinks: [String!] - pendingMatrixLinks: [String!] @owner + pendingMatrixLinks: [String!] } type UserConnection { @@ -1053,9 +1053,14 @@ input CommentList { comment: String! } -input AddToList { - list: ID! - entries: [ID!]! +input AddToLists { + lists: [ID!]! + entry: ID! +} + +input RemoveFromLists { + lists: [ID!]! + entry: ID! } input AddMXID { @@ -1074,11 +1079,11 @@ type Mutation { createEntry(input: CreateEntry!): Entry! @loggedIn commentEntry(input: CommentEntry!): Entry! @loggedIn - deleteEntry(input: ID!): Boolean! @loggedIn @hasRole(role: ADMIN) + addToLists(input: AddToLists!): Entry! @loggedIn + removeFromLists(input: RemoveFromLists!): Entry! @loggedIn createList(input: CreateList!): List! @loggedIn commentList(input: CommentList!): List! @loggedIn - addToList(input: AddToList!): List! @loggedIn @maintainer deleteList(input: ID!): Boolean! @loggedIn @owner } @@ -1240,13 +1245,13 @@ func (ec *executionContext) field_Mutation_addMXID_args(ctx context.Context, raw return args, nil } -func (ec *executionContext) field_Mutation_addToList_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_addToLists_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 model.AddToList + var arg0 model.AddToLists if tmp, ok := rawArgs["input"]; ok { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) - arg0, err = ec.unmarshalNAddToList2githubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐAddToList(ctx, tmp) + arg0, err = ec.unmarshalNAddToLists2githubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐAddToLists(ctx, tmp) if err != nil { return nil, err } @@ -1315,21 +1320,6 @@ func (ec *executionContext) field_Mutation_createList_args(ctx context.Context, return args, nil } -func (ec *executionContext) field_Mutation_deleteEntry_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["input"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) - arg0, err = ec.unmarshalNID2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["input"] = arg0 - return args, nil -} - func (ec *executionContext) field_Mutation_deleteList_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -1375,6 +1365,21 @@ func (ec *executionContext) field_Mutation_register_args(ctx context.Context, ra return args, nil } +func (ec *executionContext) field_Mutation_removeFromLists_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.RemoveFromLists + if tmp, ok := rawArgs["input"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + arg0, err = ec.unmarshalNRemoveFromLists2githubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐRemoveFromLists(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_removeMXID_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -3029,7 +3034,7 @@ func (ec *executionContext) _Mutation_commentEntry(ctx context.Context, field gr return ec.marshalNEntry2ᚖgithubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐEntry(ctx, field.Selections, res) } -func (ec *executionContext) _Mutation_deleteEntry(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Mutation_addToLists(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -3046,7 +3051,7 @@ func (ec *executionContext) _Mutation_deleteEntry(ctx context.Context, field gra ctx = graphql.WithFieldContext(ctx, fc) rawArgs := field.ArgumentMap(ec.Variables) - args, err := ec.field_Mutation_deleteEntry_args(ctx, rawArgs) + args, err := ec.field_Mutation_addToLists_args(ctx, rawArgs) if err != nil { ec.Error(ctx, err) return graphql.Null @@ -3055,7 +3060,7 @@ func (ec *executionContext) _Mutation_deleteEntry(ctx context.Context, field gra resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { directive0 := func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().DeleteEntry(rctx, args["input"].(string)) + return ec.resolvers.Mutation().AddToLists(rctx, args["input"].(model.AddToLists)) } directive1 := func(ctx context.Context) (interface{}, error) { if ec.directives.LoggedIn == nil { @@ -3063,28 +3068,18 @@ func (ec *executionContext) _Mutation_deleteEntry(ctx context.Context, field gra } return ec.directives.LoggedIn(ctx, nil, directive0) } - directive2 := func(ctx context.Context) (interface{}, error) { - role, err := ec.unmarshalNUserRole2githubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐUserRole(ctx, "ADMIN") - if err != nil { - return nil, err - } - if ec.directives.HasRole == nil { - return nil, errors.New("directive hasRole is not implemented") - } - return ec.directives.HasRole(ctx, nil, directive1, role) - } - tmp, err := directive2(rctx) + tmp, err := directive1(rctx) if err != nil { return nil, graphql.ErrorOnPath(ctx, err) } if tmp == nil { return nil, nil } - if data, ok := tmp.(bool); ok { + if data, ok := tmp.(*model.Entry); ok { return data, nil } - return nil, fmt.Errorf(`unexpected type %T from directive, should be bool`, tmp) + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/Unkn0wnCat/matrix-veles/graph/model.Entry`, tmp) }) if err != nil { ec.Error(ctx, err) @@ -3096,9 +3091,71 @@ func (ec *executionContext) _Mutation_deleteEntry(ctx context.Context, field gra } return graphql.Null } - res := resTmp.(bool) + res := resTmp.(*model.Entry) fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) + return ec.marshalNEntry2ᚖgithubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐEntry(ctx, field.Selections, res) +} + +func (ec *executionContext) _Mutation_removeFromLists(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + IsResolver: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_removeFromLists_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().RemoveFromLists(rctx, args["input"].(model.RemoveFromLists)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.LoggedIn == nil { + return nil, errors.New("directive loggedIn is not implemented") + } + return ec.directives.LoggedIn(ctx, nil, directive0) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.Entry); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/Unkn0wnCat/matrix-veles/graph/model.Entry`, tmp) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Entry) + fc.Result = res + return ec.marshalNEntry2ᚖgithubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐEntry(ctx, field.Selections, res) } func (ec *executionContext) _Mutation_createList(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { @@ -3225,74 +3282,6 @@ func (ec *executionContext) _Mutation_commentList(ctx context.Context, field gra return ec.marshalNList2ᚖgithubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐList(ctx, field.Selections, res) } -func (ec *executionContext) _Mutation_addToList(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "Mutation", - Field: field, - Args: nil, - IsMethod: true, - IsResolver: true, - } - - ctx = graphql.WithFieldContext(ctx, fc) - rawArgs := field.ArgumentMap(ec.Variables) - args, err := ec.field_Mutation_addToList_args(ctx, rawArgs) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - fc.Args = args - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - directive0 := func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().AddToList(rctx, args["input"].(model.AddToList)) - } - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.LoggedIn == nil { - return nil, errors.New("directive loggedIn is not implemented") - } - return ec.directives.LoggedIn(ctx, nil, directive0) - } - directive2 := func(ctx context.Context) (interface{}, error) { - if ec.directives.Maintainer == nil { - return nil, errors.New("directive maintainer is not implemented") - } - return ec.directives.Maintainer(ctx, nil, directive1) - } - - tmp, err := directive2(rctx) - if err != nil { - return nil, graphql.ErrorOnPath(ctx, err) - } - if tmp == nil { - return nil, nil - } - if data, ok := tmp.(*model.List); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be *github.com/Unkn0wnCat/matrix-veles/graph/model.List`, tmp) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.List) - fc.Result = res - return ec.marshalNList2ᚖgithubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐList(ctx, field.Selections, res) -} - func (ec *executionContext) _Mutation_deleteList(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -4150,28 +4139,8 @@ func (ec *executionContext) _User_pendingMatrixLinks(ctx context.Context, field ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - directive0 := func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.PendingMatrixLinks, nil - } - directive1 := func(ctx context.Context) (interface{}, error) { - if ec.directives.Owner == nil { - return nil, errors.New("directive owner is not implemented") - } - return ec.directives.Owner(ctx, obj, directive0) - } - - tmp, err := directive1(rctx) - if err != nil { - return nil, graphql.ErrorOnPath(ctx, err) - } - if tmp == nil { - return nil, nil - } - if data, ok := tmp.([]*string); ok { - return data, nil - } - return nil, fmt.Errorf(`unexpected type %T from directive, should be []*string`, tmp) + ctx = rctx // use context from middleware stack in children + return obj.PendingMatrixLinks, nil }) if err != nil { ec.Error(ctx, err) @@ -5470,8 +5439,8 @@ func (ec *executionContext) unmarshalInputAddMXID(ctx context.Context, obj inter return it, nil } -func (ec *executionContext) unmarshalInputAddToList(ctx context.Context, obj interface{}) (model.AddToList, error) { - var it model.AddToList +func (ec *executionContext) unmarshalInputAddToLists(ctx context.Context, obj interface{}) (model.AddToLists, error) { + var it model.AddToLists asMap := map[string]interface{}{} for k, v := range obj.(map[string]interface{}) { asMap[k] = v @@ -5479,19 +5448,19 @@ func (ec *executionContext) unmarshalInputAddToList(ctx context.Context, obj int for k, v := range asMap { switch k { - case "list": + case "lists": var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("list")) - it.List, err = ec.unmarshalNID2string(ctx, v) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("lists")) + it.Lists, err = ec.unmarshalNID2ᚕstringᚄ(ctx, v) if err != nil { return it, err } - case "entries": + case "entry": var err error - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("entries")) - it.Entries, err = ec.unmarshalNID2ᚕstringᚄ(ctx, v) + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("entry")) + it.Entry, err = ec.unmarshalNID2string(ctx, v) if err != nil { return it, err } @@ -6079,6 +6048,37 @@ func (ec *executionContext) unmarshalInputRegister(ctx context.Context, obj inte return it, nil } +func (ec *executionContext) unmarshalInputRemoveFromLists(ctx context.Context, obj interface{}) (model.RemoveFromLists, error) { + var it model.RemoveFromLists + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + for k, v := range asMap { + switch k { + case "lists": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("lists")) + it.Lists, err = ec.unmarshalNID2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } + case "entry": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("entry")) + it.Entry, err = ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputRemoveMXID(ctx context.Context, obj interface{}) (model.RemoveMxid, error) { var it model.RemoveMxid asMap := map[string]interface{}{} @@ -6817,8 +6817,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { invalids++ } - case "deleteEntry": - out.Values[i] = ec._Mutation_deleteEntry(ctx, field) + case "addToLists": + out.Values[i] = ec._Mutation_addToLists(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } + case "removeFromLists": + out.Values[i] = ec._Mutation_removeFromLists(ctx, field) if out.Values[i] == graphql.Null { invalids++ } @@ -6832,11 +6837,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { invalids++ } - case "addToList": - out.Values[i] = ec._Mutation_addToList(ctx, field) - if out.Values[i] == graphql.Null { - invalids++ - } case "deleteList": out.Values[i] = ec._Mutation_deleteList(ctx, field) if out.Values[i] == graphql.Null { @@ -7380,8 +7380,8 @@ func (ec *executionContext) unmarshalNAddMXID2githubᚗcomᚋUnkn0wnCatᚋmatrix return res, graphql.ErrorOnPath(ctx, err) } -func (ec *executionContext) unmarshalNAddToList2githubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐAddToList(ctx context.Context, v interface{}) (model.AddToList, error) { - res, err := ec.unmarshalInputAddToList(ctx, v) +func (ec *executionContext) unmarshalNAddToLists2githubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐAddToLists(ctx context.Context, v interface{}) (model.AddToLists, error) { + res, err := ec.unmarshalInputAddToLists(ctx, v) return res, graphql.ErrorOnPath(ctx, err) } @@ -7719,6 +7719,11 @@ func (ec *executionContext) unmarshalNRegister2githubᚗcomᚋUnkn0wnCatᚋmatri return res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) unmarshalNRemoveFromLists2githubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐRemoveFromLists(ctx context.Context, v interface{}) (model.RemoveFromLists, error) { + res, err := ec.unmarshalInputRemoveFromLists(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) unmarshalNRemoveMXID2githubᚗcomᚋUnkn0wnCatᚋmatrixᚑvelesᚋgraphᚋmodelᚐRemoveMxid(ctx context.Context, v interface{}) (model.RemoveMxid, error) { res, err := ec.unmarshalInputRemoveMXID(ctx, v) return res, graphql.ErrorOnPath(ctx, err) diff --git a/graph/helpers.go b/graph/helpers.go index 27dc34a..3026798 100644 --- a/graph/helpers.go +++ b/graph/helpers.go @@ -12,6 +12,30 @@ import ( "time" ) +func PerformListMaintainerCheck(listIdHex string, userIdHex string) error { + id, err := primitive.ObjectIDFromHex(listIdHex) + if err != nil { + return err + } + + list, err := db.GetListByID(id) + if err != nil { + return err + } + + if list.Creator.Hex() == userIdHex { + return nil + } + + for _, maintainerId := range list.Maintainers { + if maintainerId.Hex() == userIdHex { + return nil + } + } + + return errors.New("unauthorized") +} + func GetUserFromContext(ctx context.Context) (*model2.DBUser, error) { userID, err := GetUserIDFromContext(ctx) if err != nil { diff --git a/graph/model/list.go b/graph/model/list.go index d5f43a0..71fbab8 100644 --- a/graph/model/list.go +++ b/graph/model/list.go @@ -11,6 +11,7 @@ type List struct { Tags []string `json:"tags"` RawComments []*model.DBComment MaintainerIDs []*primitive.ObjectID + CreatorID primitive.ObjectID } func MakeList(dbList *model.DBHashList) *List { @@ -20,5 +21,6 @@ func MakeList(dbList *model.DBHashList) *List { Tags: dbList.Tags, RawComments: dbList.Comments, MaintainerIDs: dbList.Maintainers, + CreatorID: dbList.Creator, } } diff --git a/graph/model/models_gen.go b/graph/model/models_gen.go index b451ae1..36b927e 100644 --- a/graph/model/models_gen.go +++ b/graph/model/models_gen.go @@ -13,9 +13,9 @@ type AddMxid struct { Mxid string `json:"mxid"` } -type AddToList struct { - List string `json:"list"` - Entries []string `json:"entries"` +type AddToLists struct { + Lists []string `json:"lists"` + Entry string `json:"entry"` } type CommentConnection struct { @@ -143,6 +143,11 @@ type Register struct { MxID string `json:"mxID"` } +type RemoveFromLists struct { + Lists []string `json:"lists"` + Entry string `json:"entry"` +} + type RemoveMxid struct { Mxid string `json:"mxid"` } diff --git a/graph/schema.graphqls b/graph/schema.graphqls index 65df468..7b1b588 100644 --- a/graph/schema.graphqls +++ b/graph/schema.graphqls @@ -246,9 +246,14 @@ input CommentList { comment: String! } -input AddToList { - list: ID! - entries: [ID!]! +input AddToLists { + lists: [ID!]! + entry: ID! +} + +input RemoveFromLists { + lists: [ID!]! + entry: ID! } input AddMXID { @@ -267,11 +272,11 @@ type Mutation { createEntry(input: CreateEntry!): Entry! @loggedIn commentEntry(input: CommentEntry!): Entry! @loggedIn - deleteEntry(input: ID!): Boolean! @loggedIn @hasRole(role: ADMIN) + addToLists(input: AddToLists!): Entry! @loggedIn + removeFromLists(input: RemoveFromLists!): Entry! @loggedIn createList(input: CreateList!): List! @loggedIn commentList(input: CommentList!): List! @loggedIn - addToList(input: AddToList!): List! @loggedIn @maintainer deleteList(input: ID!): Boolean! @loggedIn @owner } diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go index 0a4b8af..4c062d1 100644 --- a/graph/schema.resolvers.go +++ b/graph/schema.resolvers.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "math/big" + "strings" "time" "github.com/Unkn0wnCat/matrix-veles/graph/generated" @@ -130,7 +131,12 @@ func (r *entryResolver) Comments(ctx context.Context, obj *model.Entry, first *i } func (r *listResolver) Creator(ctx context.Context, obj *model.List) (*model.User, error) { - panic(fmt.Errorf("not implemented")) + user, err := db.GetUserByID(obj.CreatorID) + if err != nil { + return nil, errors.New("database error") + } + + return model.MakeUser(user), nil } func (r *listResolver) Comments(ctx context.Context, obj *model.List, first *int, after *string) (*model.CommentConnection, error) { @@ -330,39 +336,342 @@ func (r *mutationResolver) Login(ctx context.Context, input model.Login) (string } func (r *mutationResolver) Register(ctx context.Context, input model.Register) (string, error) { - panic(fmt.Errorf("not implemented")) + _, err := db.GetUserByUsername(input.Username) + if !errors.Is(err, mongo.ErrNoDocuments) { + return "", errors.New("username taken") + } + + user := model2.DBUser{ + ID: primitive.NewObjectID(), + Username: input.Username, + PendingMatrixLinks: []*string{&input.MxID}, + Password: &input.Password, + } + + err = user.HashPassword() + if err != nil { + return "", errors.New("server error") + } + + err = db.SaveUser(&user) + if err != nil { + return "", errors.New("database error") + } + + jwtSigningKey := []byte(viper.GetString("bot.web.secret")) + + claims := model2.JwtClaims{ + Username: user.Username, + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24 * 365 * 100)), + IssuedAt: jwt.NewNumericDate(time.Now()), + NotBefore: jwt.NewNumericDate(time.Now()), + Issuer: "veles-api", + Subject: user.ID.Hex(), + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + ss, err := token.SignedString(jwtSigningKey) + if err != nil { + return "", errors.New("unable to create token") + } + + return ss, nil } func (r *mutationResolver) AddMxid(ctx context.Context, input model.AddMxid) (*model.User, error) { - panic(fmt.Errorf("not implemented")) + user, err := GetUserFromContext(ctx) + if err != nil { + return nil, err + } + + for _, mxid := range append(user.MatrixLinks, user.PendingMatrixLinks...) { + if strings.EqualFold(*mxid, input.Mxid) { + return model.MakeUser(user), nil + } + } + + user.PendingMatrixLinks = append(user.PendingMatrixLinks, &input.Mxid) + + err = db.SaveUser(user) + if err != nil { + return nil, errors.New("database error") + } + + return model.MakeUser(user), nil } func (r *mutationResolver) RemoveMxid(ctx context.Context, input model.RemoveMxid) (*model.User, error) { - panic(fmt.Errorf("not implemented")) + user, err := GetUserFromContext(ctx) + if err != nil { + return nil, err + } + + for i, mxid := range user.MatrixLinks { + if strings.EqualFold(*mxid, input.Mxid) { + user.MatrixLinks = append(user.MatrixLinks[:i], user.MatrixLinks[i+1:]...) + } + } + + for i, mxid := range user.PendingMatrixLinks { + if strings.EqualFold(*mxid, input.Mxid) { + user.PendingMatrixLinks = append(user.PendingMatrixLinks[:i], user.PendingMatrixLinks[i+1:]...) + } + } + + err = db.SaveUser(user) + if err != nil { + return nil, errors.New("database error") + } + + return model.MakeUser(user), nil } func (r *mutationResolver) CreateEntry(ctx context.Context, input model.CreateEntry) (*model.Entry, error) { - panic(fmt.Errorf("not implemented")) + user, err := GetUserFromContext(ctx) + if err != nil { + return nil, err + } + + entry, err := db.GetEntryByHash(input.HashValue) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + return nil, errors.New("database error") + } + + if entry == nil { + entry = &model2.DBEntry{ + ID: primitive.NewObjectID(), + Tags: input.Tags, + HashValue: input.HashValue, + Timestamp: time.Now(), + AddedBy: &user.ID, + Comments: nil, + } + } + + if len(input.PartOf) > 0 { + for _, partOfId := range input.PartOf { + err = PerformListMaintainerCheck(partOfId, user.ID.Hex()) + if err != nil { + return nil, errors.New("error adding to lists") + } + + partOf, _ := primitive.ObjectIDFromHex(partOfId) // This can't fail, it worked in PerformListMaintainerCheck + entry.AddTo(&partOf) + } + } + + if input.Comment != nil { + entry.Comments = append(entry.Comments, &model2.DBComment{ + Timestamp: time.Now(), + CommentedBy: &user.ID, + Content: *input.Comment, + }) + } + + err = db.SaveEntry(entry) + if err != nil { + return nil, errors.New("database error") + } + + return model.MakeEntry(entry), nil } func (r *mutationResolver) CommentEntry(ctx context.Context, input model.CommentEntry) (*model.Entry, error) { - panic(fmt.Errorf("not implemented")) + user, err := GetUserFromContext(ctx) + if err != nil { + return nil, err + } + + id, err := primitive.ObjectIDFromHex(input.Entry) + if err != nil { + return nil, err + } + + entry, err := db.GetEntryByID(id) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, errors.New("not found") + } + return nil, errors.New("database error") + } + + entry.Comments = append(entry.Comments, &model2.DBComment{ + Timestamp: time.Now(), + CommentedBy: &user.ID, + Content: input.Comment, + }) + + err = db.SaveEntry(entry) + if err != nil { + return nil, errors.New("database error") + } + + return model.MakeEntry(entry), nil } -func (r *mutationResolver) DeleteEntry(ctx context.Context, input string) (bool, error) { - panic(fmt.Errorf("not implemented")) +func (r *mutationResolver) AddToLists(ctx context.Context, input model.AddToLists) (*model.Entry, error) { + user, err := GetUserFromContext(ctx) + if err != nil { + return nil, err + } + + id, err := primitive.ObjectIDFromHex(input.Entry) + if err != nil { + return nil, err + } + + entry, err := db.GetEntryByID(id) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, errors.New("not found") + } + return nil, errors.New("database error") + } + + if len(input.Lists) > 0 { + for _, partOfId := range input.Lists { + err = PerformListMaintainerCheck(partOfId, user.ID.Hex()) + if err != nil { + return nil, errors.New("error adding to lists") + } + + partOf, _ := primitive.ObjectIDFromHex(partOfId) // This can't fail, it worked in PerformListMaintainerCheck + entry.AddTo(&partOf) + } + } + + err = db.SaveEntry(entry) + if err != nil { + return nil, errors.New("database error") + } + + return model.MakeEntry(entry), nil +} + +func (r *mutationResolver) RemoveFromLists(ctx context.Context, input model.RemoveFromLists) (*model.Entry, error) { + user, err := GetUserFromContext(ctx) + if err != nil { + return nil, err + } + + id, err := primitive.ObjectIDFromHex(input.Entry) + if err != nil { + return nil, err + } + + entry, err := db.GetEntryByID(id) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, errors.New("not found") + } + return nil, errors.New("database error") + } + + if len(input.Lists) > 0 { + for _, partOfId := range input.Lists { + err = PerformListMaintainerCheck(partOfId, user.ID.Hex()) + if err != nil { + return nil, errors.New("error adding to lists") + } + + partOf, _ := primitive.ObjectIDFromHex(partOfId) // This can't fail, it worked in PerformListMaintainerCheck + entry.RemoveFrom(&partOf) + } + } + + err = db.SaveEntry(entry) + if err != nil { + return nil, errors.New("database error") + } + + return model.MakeEntry(entry), nil } func (r *mutationResolver) CreateList(ctx context.Context, input model.CreateList) (*model.List, error) { - panic(fmt.Errorf("not implemented")) + user, err := GetUserFromContext(ctx) + if err != nil { + return nil, err + } + + _, err = db.GetListByName(input.Name) + if !errors.Is(err, mongo.ErrNoDocuments) { + return nil, errors.New("name taken") + } + + list := model2.DBHashList{ + ID: primitive.NewObjectID(), + Name: input.Name, + Tags: input.Tags, + Creator: user.ID, + } + + for _, maintainer := range input.Maintainers { + id, err := primitive.ObjectIDFromHex(maintainer) + if err != nil { + return nil, err + } + + maintainerUser, err := db.GetUserByID(id) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, errors.New("maintainer not found") + } + + return nil, errors.New("database error") + } + + list.Maintainers = append(list.Maintainers, &maintainerUser.ID) + } + + if input.Comment != nil { + list.Comments = append(list.Comments, &model2.DBComment{ + Timestamp: time.Now(), + CommentedBy: &user.ID, + Content: *input.Comment, + }) + } + + err = db.SaveList(&list) + if err != nil { + return nil, errors.New("database error") + } + + return model.MakeList(&list), nil } func (r *mutationResolver) CommentList(ctx context.Context, input model.CommentList) (*model.List, error) { - panic(fmt.Errorf("not implemented")) -} + user, err := GetUserFromContext(ctx) + if err != nil { + return nil, err + } -func (r *mutationResolver) AddToList(ctx context.Context, input model.AddToList) (*model.List, error) { - panic(fmt.Errorf("not implemented")) + id, err := primitive.ObjectIDFromHex(input.List) + if err != nil { + return nil, err + } + + list, err := db.GetListByID(id) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, errors.New("not found") + } + return nil, errors.New("database error") + } + + list.Comments = append(list.Comments, &model2.DBComment{ + Timestamp: time.Now(), + CommentedBy: &user.ID, + Content: input.Comment, + }) + + err = db.SaveList(list) + if err != nil { + return nil, errors.New("database error") + } + + return model.MakeList(list), nil } func (r *mutationResolver) DeleteList(ctx context.Context, input string) (bool, error) { diff --git a/internal/db/db.go b/internal/db/db.go index 6818135..8cd002a 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -10,6 +10,7 @@ import ( "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "log" + "regexp" "time" ) @@ -235,7 +236,12 @@ func GetUserByID(id primitive.ObjectID) (*model.DBUser, error) { func GetUserByUsername(username string) (*model.DBUser, error) { db := DbClient.Database(viper.GetString("bot.mongo.database")) - res := db.Collection(viper.GetString("bot.mongo.collection.users")).FindOne(context.TODO(), bson.D{{"username", username}}) + regexPattern := "^" + regexp.QuoteMeta(username) + "$" + + res := db.Collection(viper.GetString("bot.mongo.collection.users")).FindOne(context.TODO(), bson.D{{"username", primitive.Regex{ + Pattern: regexPattern, + Options: "i", + }}}) if res.Err() != nil { return nil, res.Err() } diff --git a/internal/db/model/entry.go b/internal/db/model/entry.go index 5fc288b..cef1de7 100644 --- a/internal/db/model/entry.go +++ b/internal/db/model/entry.go @@ -15,3 +15,24 @@ type DBEntry struct { AddedBy *primitive.ObjectID `bson:"added_by" json:"added_by"` // AddedBy is a reference to the user who added this Comments []*DBComment `bson:"comments" json:"comments"` // Comments regarding this entry } + +func (entry *DBEntry) AddTo(id *primitive.ObjectID) { + for _, addedTo := range entry.PartOf { + if addedTo.Hex() == id.Hex() { + return + } + } + + entry.PartOf = append(entry.PartOf, id) +} + +func (entry *DBEntry) RemoveFrom(id *primitive.ObjectID) { + for i, addedTo := range entry.PartOf { + if addedTo.Hex() == id.Hex() { + entry.PartOf = append(entry.PartOf[:i], entry.PartOf[i+1:]...) + return + } + } + + return +} diff --git a/internal/db/model/list.go b/internal/db/model/list.go index d5827ee..b668ad1 100644 --- a/internal/db/model/list.go +++ b/internal/db/model/list.go @@ -7,5 +7,6 @@ type DBHashList struct { Name string `bson:"name" json:"name"` Tags []string `bson:"tags" json:"tags"` // Tags of this list for discovery, and sorting Comments []*DBComment `bson:"comments" json:"comments"` // Comments regarding this list + Creator primitive.ObjectID `bson:"creator" json:"creator"` // Creator of the list Maintainers []*primitive.ObjectID `bson:"maintainers" json:"maintainers"` // Maintainers contains references to the users who may edit this list }