diff --git a/graph2/queries/character.go b/graph2/queries/character.go index 668762d..3e5dde3 100644 --- a/graph2/queries/character.go +++ b/graph2/queries/character.go @@ -3,11 +3,16 @@ package queries import ( "context" "errors" + "strings" + "git.aiterp.net/rpdata/api/graph2/input" + "git.aiterp.net/rpdata/api/internal/auth" "git.aiterp.net/rpdata/api/models" "git.aiterp.net/rpdata/api/models/characters" ) +// Queries + func (r *resolver) Character(ctx context.Context, id *string, nick *string) (models.Character, error) { if id != nil { return characters.FindID(*id) @@ -21,3 +26,105 @@ func (r *resolver) Character(ctx context.Context, id *string, nick *string) (mod func (r *resolver) Characters(ctx context.Context, filter *characters.Filter) ([]models.Character, error) { return characters.List(filter) } + +// Mutations + +func (r *mutationResolver) AddCharacter(ctx context.Context, input input.CharacterAddInput) (models.Character, error) { + token := auth.TokenFromContext(ctx) + if !token.Permitted("member", "character.add") { + return models.Character{}, errors.New("You are not permitted to add characters") + } + if len(input.Name) < 2 || len(input.Nick) < 2 { + return models.Character{}, errors.New("You need to provide a name and a nick (min length: 2)") + } + + shortName := "" + if input.ShortName != nil { + shortName = *input.ShortName + } else { + shortName = strings.SplitN(input.Name, " ", 2)[0] + } + + description := "" + if input.Description != nil { + description = *input.Description + } + + author := token.UserID + if input.Author != nil && *input.Author != author { + if !token.Permitted("character.add") { + return models.Character{}, errors.New("You are only permitted to add your own characters") + } + + author = *input.Author + } + + return characters.Add(input.Nick, input.Name, shortName, author, description) +} + +func (r *mutationResolver) AddCharacterNick(ctx context.Context, input input.CharacterNickInput) (models.Character, error) { + character, err := characters.FindID(input.ID) + if err != nil { + return models.Character{}, errors.New("Character not found") + } + + if len(input.Nick) < 2 { + return models.Character{}, errors.New("You need to provide a valid nick (min length: 2)") + } + + token := auth.TokenFromContext(ctx) + if !token.PermittedUser(character.Author, "member", "character.edit") { + return models.Character{}, errors.New("You are not permitted to edit this character") + } + + return characters.AddNick(character, input.Nick) +} + +func (r *mutationResolver) RemoveCharacterNick(ctx context.Context, input input.CharacterNickInput) (models.Character, error) { + character, err := characters.FindID(input.ID) + if err != nil { + return models.Character{}, errors.New("Character not found") + } + + token := auth.TokenFromContext(ctx) + if !token.PermittedUser(character.Author, "member", "character.edit") { + return models.Character{}, errors.New("You are not permitted to edit this character") + } + + return characters.RemoveNick(character, input.Nick) +} + +func (r *mutationResolver) EditCharacter(ctx context.Context, input input.CharacterEditInput) (models.Character, error) { + character, err := characters.FindID(input.ID) + if err != nil { + return models.Character{}, errors.New("Character not found") + } + + if input.Name != nil && len(*input.Name) < 2 { + return models.Character{}, errors.New("You need to provide a valid name (min length: 2)") + } + if input.ShortName != nil && len(*input.ShortName) < 2 { + return models.Character{}, errors.New("You need to provide a valid short name (min length: 2)") + } + + token := auth.TokenFromContext(ctx) + if !token.PermittedUser(character.Author, "member", "character.edit") { + return models.Character{}, errors.New("You are not permitted to edit this character") + } + + return characters.Edit(character, input.Name, input.ShortName, input.Description) +} + +func (r *mutationResolver) RemoveCharacter(ctx context.Context, input input.CharacterRemoveInput) (models.Character, error) { + character, err := characters.FindID(input.ID) + if err != nil { + return models.Character{}, errors.New("Character not found") + } + + token := auth.TokenFromContext(ctx) + if !token.PermittedUser(character.Author, "member", "character.remove") { + return models.Character{}, errors.New("You are not permitted to remove this character") + } + + return characters.Remove(character) +} diff --git a/graph2/schema/root.gql b/graph2/schema/root.gql index feb88c7..870aa32 100644 --- a/graph2/schema/root.gql +++ b/graph2/schema/root.gql @@ -106,6 +106,22 @@ type Mutation { # Remove a post removePost(input: PostRemoveInput!): Post! + + + # Add a new character + addCharacter(input: CharacterAddInput!): Character! + + # Add nick to character + addCharacterNick(input: CharacterNickInput!): Character! + + # Remove nick from character + removeCharacterNick(input: CharacterNickInput!): Character! + + # Edit character + editCharacter(input: CharacterEditInput!): Character! + + # Remove a character + removeCharacter(input: CharacterRemoveInput!): Character! } # A Date represents a RFC3339 encoded date with up to millisecond precision. diff --git a/graph2/schema/types/Character.gql b/graph2/schema/types/Character.gql index ecef7b2..172fe63 100644 --- a/graph2/schema/types/Character.gql +++ b/graph2/schema/types/Character.gql @@ -71,6 +71,7 @@ input CharacterNickInput { nick: String! } +# Inpuit for editCharacter mutation input CharacterEditInput { # The id for the character to edit id: String! @@ -85,3 +86,9 @@ input CharacterEditInput { description: String } +# Input for removeCharacter mutation +input CharacterRemoveInput { + # The id for the character to edit + id: String! +} + diff --git a/models/characters/edit.go b/models/characters/edit.go new file mode 100644 index 0000000..169e722 --- /dev/null +++ b/models/characters/edit.go @@ -0,0 +1,32 @@ +package characters + +import ( + "git.aiterp.net/rpdata/api/models" + "github.com/globalsign/mgo/bson" +) + +// Edit sets the fields of metadata. Only non-empty and different fields will be set in the +// database, preventing out of order edits to two fields from conflicting +func Edit(character models.Character, name, shortName, description *string) (models.Character, error) { + changes := bson.M{} + + if name != nil && *name != character.Name { + character.Name = *name + changes["name"] = *name + } + if shortName != nil && *shortName != character.ShortName { + character.ShortName = *shortName + changes["shortName"] = *shortName + } + if description != nil && *description != character.Description { + character.Description = *description + changes["description"] = *description + } + + err := collection.UpdateId(character.ID, changes) + if err != nil { + return models.Character{}, err + } + + return character, nil +} diff --git a/models/characters/remove.go b/models/characters/remove.go new file mode 100644 index 0000000..7af4bc4 --- /dev/null +++ b/models/characters/remove.go @@ -0,0 +1,13 @@ +package characters + +import "git.aiterp.net/rpdata/api/models" + +// Remove removes a character, returning it if it succeeds +func Remove(character models.Character) (models.Character, error) { + err := collection.RemoveId(character.ID) + if err != nil { + return models.Character{}, err + } + + return character, nil +}