Browse Source

Moved query and mutation resolvers into individual files

1.0 0.4.1
Gisle Aune 6 years ago
parent
commit
ed3e384d55
  1. 2
      cmd/rpdata-graphiql/main.go
  2. 156
      graphql/resolver/channel.go
  3. 161
      graphql/resolver/chapter.go
  4. 299
      graphql/resolver/character.go
  5. 15
      graphql/resolver/error.go
  6. 115
      graphql/resolver/file.go
  7. 229
      graphql/resolver/log.go
  8. 59
      graphql/resolver/mutations/addChannel.go
  9. 67
      graphql/resolver/mutations/addChapter.go
  10. 70
      graphql/resolver/mutations/addCharacter.go
  11. 48
      graphql/resolver/mutations/addCharacterNick.go
  12. 70
      graphql/resolver/mutations/addLog.go
  13. 60
      graphql/resolver/mutations/addPost.go
  14. 83
      graphql/resolver/mutations/addStory.go
  15. 53
      graphql/resolver/mutations/addStoryTag.go
  16. 50
      graphql/resolver/mutations/editChannel.go
  17. 63
      graphql/resolver/mutations/editChapter.go
  18. 64
      graphql/resolver/mutations/editCharacter.go
  19. 43
      graphql/resolver/mutations/editFile.go
  20. 51
      graphql/resolver/mutations/editLog.go
  21. 63
      graphql/resolver/mutations/editPost.go
  22. 69
      graphql/resolver/mutations/editStory.go
  23. 26
      graphql/resolver/mutations/login.go
  24. 16
      graphql/resolver/mutations/logout.go
  25. 45
      graphql/resolver/mutations/movePost.go
  26. 37
      graphql/resolver/mutations/removeChannel.go
  27. 37
      graphql/resolver/mutations/removeChapter.go
  28. 44
      graphql/resolver/mutations/removeCharacter.go
  29. 48
      graphql/resolver/mutations/removeCharacterNick.go
  30. 37
      graphql/resolver/mutations/removeFile.go
  31. 37
      graphql/resolver/mutations/removeLog.go
  32. 36
      graphql/resolver/mutations/removePost.go
  33. 41
      graphql/resolver/mutations/removeStory.go
  34. 53
      graphql/resolver/mutations/removeStoryTag.go
  35. 14
      graphql/resolver/mutations/resolver.go
  36. 208
      graphql/resolver/post.go
  37. 23
      graphql/resolver/queries/channel.go
  38. 28
      graphql/resolver/queries/channels.go
  39. 23
      graphql/resolver/queries/chapter.go
  40. 43
      graphql/resolver/queries/character.go
  41. 54
      graphql/resolver/queries/characters.go
  42. 23
      graphql/resolver/queries/file.go
  43. 43
      graphql/resolver/queries/files.go
  44. 32
      graphql/resolver/queries/log.go
  45. 79
      graphql/resolver/queries/logs.go
  46. 23
      graphql/resolver/queries/post.go
  47. 28
      graphql/resolver/queries/posts.go
  48. 11
      graphql/resolver/queries/resolver.go
  49. 13
      graphql/resolver/queries/session.go
  50. 77
      graphql/resolver/queries/stories.go
  51. 23
      graphql/resolver/queries/story.go
  52. 10
      graphql/resolver/queries/tags.go
  53. 13
      graphql/resolver/resolver.go
  54. 13
      graphql/resolver/root.go
  55. 39
      graphql/resolver/session.go
  56. 329
      graphql/resolver/story.go

2
cmd/rpdata-graphiql/main.go

@ -30,7 +30,7 @@ func main() {
} }
log.Println("Updated characters on", n, "logs") log.Println("Updated characters on", n, "logs")
schema, err := graphql.ParseSchema(schema.String(), &resolver.RootResolver{}, graphql.MaxParallelism(48))
schema, err := graphql.ParseSchema(schema.String(), &resolver.Resolver{}, graphql.MaxParallelism(48))
if err != nil { if err != nil {
log.Fatalln("Failed to parse schema:", err) log.Fatalln("Failed to parse schema:", err)
} }

156
graphql/resolver/channel.go

@ -1,156 +0,0 @@
package resolver
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/channel"
)
// ChannelArgs is args for channel query
type ChannelArgs struct {
Name string
}
// Channel implements the channel query
func (r *QueryResolver) Channel(ctx context.Context, args *ChannelArgs) (*types.ChannelResolver, error) {
channel, err := channel.FindName(args.Name)
if err != nil {
return nil, err
}
return &types.ChannelResolver{C: channel}, nil
}
// ChannelsArgs is args for channel query
type ChannelsArgs struct {
Logged *bool
}
// Channels implements the channels query
func (r *QueryResolver) Channels(ctx context.Context, args *ChannelsArgs) ([]*types.ChannelResolver, error) {
channels, err := channel.List(args.Logged != nil && *args.Logged)
if err != nil {
return nil, err
}
resolvers := make([]*types.ChannelResolver, len(channels))
for i := range channels {
resolvers[i] = &types.ChannelResolver{C: channels[i]}
}
return resolvers, nil
}
// ChannelAddArgs is input for the addChannel mutation
type ChannelAddArgs struct {
Input *struct {
Name string
Logged *bool
Hub *bool
EventName *string
LocationName *string
}
}
// AddChannel resolves the addChannel mutation
func (r *MutationResolver) AddChannel(ctx context.Context, args *ChannelAddArgs) (*types.ChannelResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("channel.add") {
return nil, ErrUnauthorized
}
logged := input.Logged != nil && *input.Logged
hub := input.Hub != nil && *input.Hub
eventName := ""
if input.EventName != nil {
eventName = *input.EventName
}
locationName := ""
if input.LocationName != nil {
locationName = *input.LocationName
}
channel, err := channel.New(input.Name, logged, hub, eventName, locationName)
if err != nil {
return nil, err
}
go change.Submit("Channel", "add", user.ID, channel.Name, map[string]interface{}{
"logged": channel.Logged,
"hub": channel.Hub,
"location": input.LocationName,
"event": input.EventName,
})
return &types.ChannelResolver{C: channel}, nil
}
// ChannelEditArgs is input for the editChannel mutation
type ChannelEditArgs struct {
Input *struct {
Name string
Logged *bool
Hub *bool
EventName *string
LocationName *string
}
}
// EditChannel resolves the editChannel mutation
func (r *MutationResolver) EditChannel(ctx context.Context, args *ChannelEditArgs) (*types.ChannelResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("channel.edit") {
return nil, ErrUnauthorized
}
channel, err := channel.FindName(input.Name)
if err != nil {
return nil, err
}
err = channel.Edit(input.Logged, input.Hub, input.EventName, input.LocationName)
if err != nil {
return nil, err
}
go change.Submit("Channel", "edit", user.ID, channel.Name, map[string]interface{}{
"logged": input.Logged,
"hub": input.Hub,
"location": input.LocationName,
"event": input.EventName,
})
return &types.ChannelResolver{C: channel}, nil
}
// RemoveChannel resolves the editChannel mutation
func (r *MutationResolver) RemoveChannel(ctx context.Context, args ChannelArgs) (*types.ChannelResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("channel.remove") {
return nil, ErrUnauthorized
}
channel, err := channel.FindName(args.Name)
if err != nil {
return nil, err
}
err = channel.Remove()
if err != nil {
return nil, err
}
go change.Submit("Channel", "remove", user.ID, channel.Name, nil)
return &types.ChannelResolver{C: channel}, nil
}

161
graphql/resolver/chapter.go

@ -1,161 +0,0 @@
package resolver
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/story"
)
// ChapterArgs is args for chapter query
type ChapterArgs struct {
ID string
}
// Chapter implements the chapter query
func (r *QueryResolver) Chapter(ctx context.Context, args *ChapterArgs) (*types.ChapterResolver, error) {
chapter, err := story.FindChapterID(args.ID)
if err != nil {
return nil, err
}
return &types.ChapterResolver{C: chapter}, nil
}
// AddChapterArgs is args for the addChapter mutation
type AddChapterArgs struct {
Input *struct {
StoryID string
Title string
Author *string
Source string
FictionalDate *string
}
}
// AddChapter implements the addChapter mutation
func (r *MutationResolver) AddChapter(ctx context.Context, args *AddChapterArgs) (*types.ChapterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "chapter.add") {
return nil, ErrUnauthorized
}
story, err := story.FindID(input.StoryID)
if err != nil {
return nil, err
}
author := user.ID
if input.Author != nil {
author = *input.Author
if user.ID != author && !user.Permitted("chapter.add") {
return nil, ErrPermissionDenied
}
}
fictionalDate := time.Time{}
if input.FictionalDate != nil {
fictionalDate, err = time.Parse(time.RFC3339Nano, *input.FictionalDate)
if err != nil {
return nil, err
}
}
chapter, err := story.AddChapter(input.Title, author, input.Source, time.Now(), fictionalDate)
if err != nil {
return nil, err
}
go change.Submit("Chapter", "add", user.ID, chapter.ID, map[string]interface{}{
"title": input.Title,
"author": author,
"fictionalDate": fictionalDate,
})
return &types.ChapterResolver{C: chapter}, nil
}
// EditChapterArgs is args for the editChapter mutation
type EditChapterArgs struct {
Input *struct {
ID string
Title *string
Source *string
FictionalDate *string
}
}
// EditChapter implements the editChapter mutation
func (r *MutationResolver) EditChapter(ctx context.Context, args *EditChapterArgs) (*types.ChapterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "chapter.edit") {
return nil, ErrUnauthorized
}
chapter, err := story.FindChapterID(input.ID)
if err != nil {
return nil, err
}
if chapter.Author != user.ID && !user.Permitted("chapter.edit") {
return nil, ErrPermissionDenied
}
var fictionalDate *time.Time
if input.FictionalDate != nil {
date, err := time.Parse(time.RFC3339Nano, *input.FictionalDate)
if err != nil {
return nil, err
}
fictionalDate = &date
}
err = chapter.Edit(input.Title, input.Source, fictionalDate)
if err != nil {
return nil, err
}
go change.Submit("Chapter", "edit", user.ID, chapter.ID, map[string]interface{}{
"title": input.Title,
"source": input.Source,
"fictionalDate": fictionalDate,
})
return &types.ChapterResolver{C: chapter}, nil
}
// DeleteChapterArgs is args for the addChapter mutation
type DeleteChapterArgs struct {
ID string
}
// RemoveChapter implements the removeChapter mutation
func (r *MutationResolver) RemoveChapter(ctx context.Context, args *DeleteChapterArgs) (*types.ChapterResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "chapter.edit") {
return nil, ErrUnauthorized
}
chapter, err := story.FindChapterID(args.ID)
if err != nil {
return nil, err
}
err = chapter.Remove()
if err != nil {
return nil, err
}
go change.Submit("Chapter", "remove", user.ID, chapter.ID, nil)
return &types.ChapterResolver{C: chapter}, nil
}

299
graphql/resolver/character.go

@ -1,299 +0,0 @@
package resolver
import (
"context"
"errors"
"strings"
"git.aiterp.net/rpdata/api/graphql/loader"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/character"
"git.aiterp.net/rpdata/api/model/log"
)
// CharacterArgs is an arg
type CharacterArgs struct {
ID *string
Nick *string
}
// Character resolver
func (r *QueryResolver) Character(ctx context.Context, args *CharacterArgs) (*types.CharacterResolver, error) {
var char character.Character
var err error
loader := loader.FromContext(ctx)
if loader == nil {
return nil, errors.New("no loader")
}
switch {
case args.ID != nil:
char, err = character.FindID(*args.ID)
case args.Nick != nil:
char, err = character.FindNick(*args.Nick)
default:
err = ErrCannotResolve
}
if err != nil {
return nil, err
}
return &types.CharacterResolver{C: char}, nil
}
// CharactersArgs is an arg
type CharactersArgs struct {
IDs *[]string
Nicks *[]string
Author *string
}
// Characters resolves the characters query
func (r *QueryResolver) Characters(ctx context.Context, args *CharactersArgs) ([]*types.CharacterResolver, error) {
var chars []character.Character
var err error
loader := loader.FromContext(ctx)
if loader == nil {
return nil, errors.New("no loader")
}
switch {
case args.IDs != nil:
chars, err = character.ListIDs(*args.IDs...)
case args.Nicks != nil:
chars, err = character.ListNicks(*args.Nicks...)
case args.Author != nil:
chars, err = character.ListAuthor(*args.Author)
default:
chars, err = character.List()
}
if err != nil {
return nil, err
}
resolvers := make([]*types.CharacterResolver, 0, len(chars))
for i := range chars {
if chars[i].ID == "" {
continue
}
resolvers = append(resolvers, &types.CharacterResolver{C: chars[i]})
}
return resolvers, nil
}
// AddCharacterInput is args for the addCharacter mutation
type AddCharacterInput struct {
Nick string
Name string
ShortName *string
Author *string
Description *string
}
// AddCharacter resolves the addCharacter mutation
func (r *MutationResolver) AddCharacter(ctx context.Context, args struct{ Input *AddCharacterInput }) (*types.CharacterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "character.add") {
return nil, ErrUnauthorized
}
nick := input.Nick
name := input.Name
shortName := ""
if input.ShortName != nil {
shortName = *input.ShortName
} else {
shortName = strings.SplitN(input.Name, " ", 2)[0]
}
author := user.ID
if input.Author != nil {
author = *input.Author
if author != user.ID && !user.Permitted("character.add") {
return nil, ErrPermissionDenied
}
}
description := ""
if input.Description != nil {
description = *input.Description
}
character, err := character.New(nick, name, shortName, author, description)
if err != nil {
return nil, err
}
go change.Submit("Character", "add", user.ID, character.ID, map[string]interface{}{
"name": character.Name,
"nick": character.Nicks[0],
"author": character.Author,
})
log.ScheduleCharacterUpdate()
return &types.CharacterResolver{C: character}, nil
}
// CharacterNickInput is args for mutation addCharacterNick/removeCharacterNick
type CharacterNickInput struct {
ID string
Nick string
}
// AddCharacterNick resolves the addCharacterNick mutation
func (r *MutationResolver) AddCharacterNick(ctx context.Context, args struct{ Input *CharacterNickInput }) (*types.CharacterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
character, err := character.FindID(input.ID)
if err != nil {
return nil, err
}
if character.Author != user.ID && !user.Permitted("character.edit") {
return nil, ErrPermissionDenied
}
err = character.AddNick(input.Nick)
if err != nil {
return nil, err
}
go change.Submit("Character", "add.nick", user.ID, character.ID, map[string]interface{}{
"nick": input.Nick,
})
log.ScheduleCharacterUpdate()
return &types.CharacterResolver{C: character}, nil
}
// RemoveCharacterNick resolves the removeCharacterNick mutation
func (r *MutationResolver) RemoveCharacterNick(ctx context.Context, args struct{ Input *CharacterNickInput }) (*types.CharacterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
character, err := character.FindID(input.ID)
if err != nil {
return nil, err
}
if character.Author != user.ID && !user.Permitted("character.edit") {
return nil, ErrPermissionDenied
}
err = character.RemoveNick(input.Nick)
if err != nil {
return nil, err
}
go change.Submit("Character", "remove.nick", user.ID, character.ID, map[string]interface{}{
"nick": input.Nick,
})
log.ScheduleCharacterUpdate()
return &types.CharacterResolver{C: character}, nil
}
// CharacterEditInput is args for mutation addCharacterNick/removeCharacterNick
type CharacterEditInput struct {
ID string
Name *string
ShortName *string
Description *string
}
// EditCharacter resolves the editCharacter mutation
func (r *MutationResolver) EditCharacter(ctx context.Context, args struct{ Input *CharacterEditInput }) (*types.CharacterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
character, err := character.FindID(input.ID)
if err != nil {
return nil, err
}
if character.Author != user.ID && !user.Permitted("character.edit") {
return nil, ErrPermissionDenied
}
name := ""
if input.Name != nil {
name = *input.Name
}
shortName := ""
if input.ShortName != nil {
shortName = *input.ShortName
}
description := ""
if input.Description != nil {
description = *input.Description
}
err = character.Edit(name, shortName, description)
if err != nil {
return nil, err
}
go change.Submit("Character", "edit", user.ID, character.ID, map[string]interface{}{
"name": character.Name,
"shortName": character.ShortName,
"description": character.Description,
})
return &types.CharacterResolver{C: character}, nil
}
// RemoveCharacter resolves the removeCharacter mutation
func (r *MutationResolver) RemoveCharacter(ctx context.Context, args struct{ ID string }) (*types.CharacterResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
character, err := character.FindID(args.ID)
if err != nil {
return nil, err
}
if character.Author != user.ID && !user.Permitted("character.remove") {
return nil, ErrPermissionDenied
}
err = character.Remove()
if err != nil {
return nil, err
}
go change.Submit("Character", "remove", user.ID, character.ID, map[string]interface{}{
"name": character.Name,
"author": character.Author,
"nicks": character.Nicks,
})
return &types.CharacterResolver{C: character}, nil
}

15
graphql/resolver/error.go

@ -1,15 +0,0 @@
package resolver
import "errors"
// ErrCannotResolve is returned when a resolver constructor is at its wit's end
var ErrCannotResolve = errors.New("Cannot resolve due to invalid arguments")
// ErrNotImplemented is for TODOs
var ErrNotImplemented = errors.New("Resolver not implemented")
// ErrUnauthorized is when a guest acts like they own the place
var ErrUnauthorized = errors.New("Unauthorized")
// ErrPermissionDenied is returned when users act above their station
var ErrPermissionDenied = errors.New("Permission denied")

115
graphql/resolver/file.go

@ -1,115 +0,0 @@
package resolver
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/file"
)
// FileArgs is an arg
type FileArgs struct {
ID string
}
// File implements the file query
func (r *QueryResolver) File(ctx context.Context, args *FileArgs) (*types.FileResolver, error) {
file, err := file.FindID(args.ID)
if err != nil {
return nil, err
}
return &types.FileResolver{F: file}, nil
}
// FilesArgs is an arg
type FilesArgs struct {
IncludePublic *bool
MimeTypes *[]string
}
// Files implements the file query
func (r *QueryResolver) Files(ctx context.Context, args *FilesArgs) ([]*types.FileResolver, error) {
user := session.FromContext(ctx).User()
author := ""
if user != nil {
author = user.ID
}
public := args.IncludePublic != nil && *args.IncludePublic == true
mimeTypes := []string(nil)
if args.MimeTypes != nil {
mimeTypes = *args.MimeTypes
}
files, err := file.List(author, public, mimeTypes)
if err != nil {
return nil, err
}
resolvers := make([]*types.FileResolver, len(files))
for i := range files {
resolvers[i] = &types.FileResolver{F: files[i]}
}
return resolvers, nil
}
// FileEditArgs is args for the editFile mutation
type FileEditArgs struct {
Input *struct {
ID string
Name *string
Public *bool
}
}
// EditFile resolves the editFile mutation
func (r *MutationResolver) EditFile(ctx context.Context, args *FileEditArgs) (*types.FileResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
file, err := file.FindID(input.ID)
if err != nil {
return nil, err
}
if file.Author != user.ID && !user.Permitted("file.edit") {
return nil, ErrUnauthorized
}
err = file.Edit(input.Name, input.Public)
if err != nil {
return nil, err
}
return &types.FileResolver{F: file}, nil
}
// RemoveFile resolves the removeFIle mutation
func (r *MutationResolver) RemoveFile(ctx context.Context, args *FileArgs) (*types.FileResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
file, err := file.FindID(args.ID)
if err != nil {
return nil, err
}
if file.Author != user.ID && !user.Permitted("file.remove") {
return nil, ErrUnauthorized
}
err = file.Delete()
if err != nil {
return nil, err
}
return &types.FileResolver{F: file}, nil
}

229
graphql/resolver/log.go

@ -1,229 +0,0 @@
package resolver
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/log"
)
// LogArgs is an arg
type LogArgs struct {
ID *string
}
// Log finds log
func (r *QueryResolver) Log(ctx context.Context, args *LogArgs) (*types.LogResolver, error) {
var l log.Log
var err error
switch {
case args.ID != nil:
l, err = log.FindID(*args.ID)
default:
err = ErrCannotResolve
}
if err != nil {
return nil, err
}
return &types.LogResolver{L: l}, nil
}
// LogQueryArgs is args for the logs query
type LogQueryArgs struct {
Filter *struct {
Search *string
Characters *[]string
Channels *[]string
Events *[]string
Open *bool
Limit *int32
}
}
// Logs resolves the logs query
func (r *QueryResolver) Logs(ctx context.Context, args *LogQueryArgs) ([]*types.LogResolver, error) {
var logs []log.Log
var err error
filter := args.Filter
if filter != nil {
limit := 100
search := ""
if filter.Search != nil {
search = *filter.Search
limit = 0
}
channels := []string(nil)
if filter.Channels != nil {
channels = *filter.Channels
limit = 0
}
characters := []string(nil)
if filter.Characters != nil {
characters = *filter.Characters
limit = 0
}
events := []string(nil)
if filter.Events != nil {
events = *filter.Events
limit = 0
}
if filter.Limit != nil {
limit = int(*filter.Limit)
}
open := filter.Open != nil && *filter.Open == true
logs, err = log.ListSearch(search, channels, characters, events, open, limit)
if err != nil {
return nil, err
}
} else {
logs, err = log.List(100)
if err != nil {
return nil, err
}
}
resolvers := make([]*types.LogResolver, len(logs))
for i := range logs {
resolvers[i] = &types.LogResolver{L: logs[i]}
}
return resolvers, nil
}
// LogAddArgs is args for the addLog mutation
type LogAddArgs struct {
Input *struct {
Date string
Channel string
Title *string
Open *bool
Event *string
Description *string
}
}
// AddLog resolves the addLog mutation
func (r *MutationResolver) AddLog(ctx context.Context, args *LogAddArgs) (*types.LogResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("log.add") {
return nil, ErrUnauthorized
}
date, err := time.Parse(time.RFC3339Nano, args.Input.Date)
if err != nil {
return nil, err
}
title := ""
if input.Title != nil {
title = *input.Title
}
event := ""
if input.Event != nil {
event = *input.Event
}
description := ""
if input.Description != nil {
description = *input.Description
}
open := input.Open != nil && *input.Open == true
log, err := log.New(date, input.Channel, title, event, description, open)
if err != nil {
return nil, err
}
go change.Submit("Log", "add", user.ID, log.ID, map[string]interface{}{
"channel": log.Channel,
"title": log.Title,
"event": log.Event,
"description": log.Description,
"open": log.Open,
})
return &types.LogResolver{L: log}, nil
}
// LogEditArgs is an input
type LogEditArgs struct {
Input *struct {
ID string
Title *string
Event *string
Description *string
Open *bool
}
}
// EditLog resolves the editLog mutation
func (r *MutationResolver) EditLog(ctx context.Context, args *LogEditArgs) (*types.LogResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("log.edit") {
return nil, ErrUnauthorized
}
log, err := log.FindID(input.ID)
if err != nil {
return nil, err
}
err = log.Edit(input.Title, input.Event, input.Description, input.Open)
if err != nil {
return nil, err
}
go change.Submit("Log", "edit", user.ID, log.ID, map[string]interface{}{
"channel": log.Channel,
"title": input.Title,
"event": input.Event,
"description": input.Description,
"open": input.Open,
})
return &types.LogResolver{L: log}, nil
}
// RemoveLog resolves the removeLog mutation
func (r *MutationResolver) RemoveLog(ctx context.Context, args *struct{ ID string }) (*types.LogResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("log.remove") {
return nil, ErrUnauthorized
}
log, err := log.FindID(args.ID)
if err != nil {
return nil, err
}
err = log.Remove()
if err != nil {
return nil, err
}
go change.Submit("Log", "remove", user.ID, log.ID, nil)
return &types.LogResolver{L: log}, nil
}

59
graphql/resolver/mutations/addChannel.go

@ -0,0 +1,59 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/channel"
)
// ChannelAddArgs is input for the addChannel mutation
type ChannelAddArgs struct {
Input *struct {
Name string
Logged *bool
Hub *bool
EventName *string
LocationName *string
}
}
// AddChannel resolves the addChannel mutation
func (r *MutationResolver) AddChannel(ctx context.Context, args *ChannelAddArgs) (*types.ChannelResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("channel.add") {
return nil, ErrUnauthorized
}
logged := input.Logged != nil && *input.Logged
hub := input.Hub != nil && *input.Hub
eventName := ""
if input.EventName != nil {
eventName = *input.EventName
}
locationName := ""
if input.LocationName != nil {
locationName = *input.LocationName
}
channel, err := channel.New(input.Name, logged, hub, eventName, locationName)
if err != nil {
return nil, err
}
go change.Submit("Channel", "add", user.ID, channel.Name, map[string]interface{}{
"logged": channel.Logged,
"hub": channel.Hub,
"location": input.LocationName,
"event": input.EventName,
})
return &types.ChannelResolver{C: channel}, nil
}

67
graphql/resolver/mutations/addChapter.go

@ -0,0 +1,67 @@
package mutations
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/story"
)
// AddChapterArgs is args for the addChapter mutation
type AddChapterArgs struct {
Input *struct {
StoryID string
Title string
Author *string
Source string
FictionalDate *string
}
}
// AddChapter resolves the addChapter mutation
func (r *MutationResolver) AddChapter(ctx context.Context, args *AddChapterArgs) (*types.ChapterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "chapter.add") {
return nil, ErrUnauthorized
}
story, err := story.FindID(input.StoryID)
if err != nil {
return nil, err
}
author := user.ID
if input.Author != nil {
author = *input.Author
if user.ID != author && !user.Permitted("chapter.add") {
return nil, ErrPermissionDenied
}
}
fictionalDate := time.Time{}
if input.FictionalDate != nil {
fictionalDate, err = time.Parse(time.RFC3339Nano, *input.FictionalDate)
if err != nil {
return nil, err
}
}
chapter, err := story.AddChapter(input.Title, author, input.Source, time.Now(), fictionalDate)
if err != nil {
return nil, err
}
go change.Submit("Chapter", "add", user.ID, chapter.ID, map[string]interface{}{
"title": input.Title,
"author": author,
"fictionalDate": fictionalDate,
})
return &types.ChapterResolver{C: chapter}, nil
}

70
graphql/resolver/mutations/addCharacter.go

@ -0,0 +1,70 @@
package mutations
import (
"context"
"strings"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/character"
"git.aiterp.net/rpdata/api/model/log"
)
// AddCharacterInput is args for the addCharacter mutation
type AddCharacterInput struct {
Nick string
Name string
ShortName *string
Author *string
Description *string
}
// AddCharacter resolves the addCharacter mutation
func (r *MutationResolver) AddCharacter(ctx context.Context, args struct{ Input *AddCharacterInput }) (*types.CharacterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "character.add") {
return nil, ErrUnauthorized
}
nick := input.Nick
name := input.Name
shortName := ""
if input.ShortName != nil {
shortName = *input.ShortName
} else {
shortName = strings.SplitN(input.Name, " ", 2)[0]
}
author := user.ID
if input.Author != nil {
author = *input.Author
if author != user.ID && !user.Permitted("character.add") {
return nil, ErrPermissionDenied
}
}
description := ""
if input.Description != nil {
description = *input.Description
}
character, err := character.New(nick, name, shortName, author, description)
if err != nil {
return nil, err
}
go change.Submit("Character", "add", user.ID, character.ID, map[string]interface{}{
"name": character.Name,
"nick": character.Nicks[0],
"author": character.Author,
})
log.ScheduleCharacterUpdate()
return &types.CharacterResolver{C: character}, nil
}

48
graphql/resolver/mutations/addCharacterNick.go

@ -0,0 +1,48 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/character"
"git.aiterp.net/rpdata/api/model/log"
)
// AddCharacterNickInput is args for the addCharacterNick mutation
type AddCharacterNickInput struct {
ID string
Nick string
}
// AddCharacterNick resolves the addCharacterNick mutation
func (r *MutationResolver) AddCharacterNick(ctx context.Context, args struct{ Input *AddCharacterNickInput }) (*types.CharacterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
character, err := character.FindID(input.ID)
if err != nil {
return nil, err
}
if character.Author != user.ID && !user.Permitted("character.edit") {
return nil, ErrPermissionDenied
}
err = character.AddNick(input.Nick)
if err != nil {
return nil, err
}
go change.Submit("Character", "add.nick", user.ID, character.ID, map[string]interface{}{
"nick": input.Nick,
})
log.ScheduleCharacterUpdate()
return &types.CharacterResolver{C: character}, nil
}

70
graphql/resolver/mutations/addLog.go

@ -0,0 +1,70 @@
package mutations
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/log"
)
// LogAddArgs is args for the addLog mutation
type LogAddArgs struct {
Input *struct {
Date string
Channel string
Title *string
Open *bool
Event *string
Description *string
}
}
// AddLog resolves the addLog mutation
func (r *MutationResolver) AddLog(ctx context.Context, args *LogAddArgs) (*types.LogResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("log.add") {
return nil, ErrUnauthorized
}
date, err := time.Parse(time.RFC3339Nano, args.Input.Date)
if err != nil {
return nil, err
}
title := ""
if input.Title != nil {
title = *input.Title
}
event := ""
if input.Event != nil {
event = *input.Event
}
description := ""
if input.Description != nil {
description = *input.Description
}
open := input.Open != nil && *input.Open == true
log, err := log.New(date, input.Channel, title, event, description, open)
if err != nil {
return nil, err
}
go change.Submit("Log", "add", user.ID, log.ID, map[string]interface{}{
"channel": log.Channel,
"title": log.Title,
"event": log.Event,
"description": log.Description,
"open": log.Open,
})
return &types.LogResolver{L: log}, nil
}

60
graphql/resolver/mutations/addPost.go

@ -0,0 +1,60 @@
package mutations
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/log"
)
// PostAddArgs is args for addPost mutation
type PostAddArgs struct {
Input *struct {
LogID string
Time string
Kind string
Nick string
Text string
}
}
// AddPost resolves the addPost mutation
func (r *MutationResolver) AddPost(ctx context.Context, args *PostAddArgs) (*types.PostResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("post.add") {
return nil, ErrUnauthorized
}
postTime, err := time.Parse(time.RFC3339Nano, input.Time)
if err != nil {
return nil, err
}
log, err := log.FindID(input.LogID)
if err != nil {
return nil, err
}
post, err := log.NewPost(postTime, input.Kind, input.Nick, input.Text)
if err != nil {
return nil, err
}
go change.Submit("Post", "add", user.ID, post.ID, map[string]interface{}{
"logId": post.LogID,
"time": post.Time,
"kind": post.Kind,
"nick": post.Nick,
"text": post.Text,
"position": post.Position,
})
go log.UpdateCharacters()
return &types.PostResolver{P: post}, nil
}

83
graphql/resolver/mutations/addStory.go

@ -0,0 +1,83 @@
package mutations
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/story"
)
// StoryAddArgs is args for the addStory mutation
type StoryAddArgs struct {
Input *struct {
Name string
Category string
Author *string
Open *bool
Listed *bool
FictionalDate *string
Tags *[]struct {
Kind string
Name string
}
}
}
// AddStory resolves the addStory mutation
func (r *MutationResolver) AddStory(ctx context.Context, args *StoryAddArgs) (*types.StoryResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "story.add") {
return nil, ErrUnauthorized
}
author := user.ID
if input.Author != nil {
author = *input.Author
if user.ID != author && !user.Permitted("story.add") {
return nil, ErrPermissionDenied
}
}
listed := (input.Listed != nil && *input.Listed == true)
open := (input.Open != nil && *input.Open == true)
tags := make([]story.Tag, 0, 8)
if input.Tags != nil {
for _, tagInput := range *input.Tags {
tags = append(tags, story.Tag{
Kind: tagInput.Kind,
Name: tagInput.Name,
})
}
}
fictionalDate := time.Time{}
if input.FictionalDate != nil {
date, err := time.Parse(time.RFC3339Nano, *input.FictionalDate)
if err != nil {
return nil, err
}
fictionalDate = date
}
story, err := story.New(input.Name, author, input.Category, listed, open, tags, time.Now(), fictionalDate)
if err != nil {
return nil, err
}
go change.Submit("Story", "add", user.ID, story.ID, map[string]interface{}{
"name": input.Name,
"category": input.Category,
"author": input.Author,
})
return &types.StoryResolver{S: story}, nil
}

53
graphql/resolver/mutations/addStoryTag.go

@ -0,0 +1,53 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/story"
)
// StoryTagAddArgs is args for the addStoryTag mutation
type StoryTagAddArgs struct {
Input *struct {
ID string
Tag struct {
Kind string
Name string
}
}
}
// AddStoryTag resolves the addStoryTag mutation
func (r *MutationResolver) AddStoryTag(ctx context.Context, args *StoryTagAddArgs) (*types.StoryResolver, error) {
input := args.Input
tag := story.Tag{Kind: input.Tag.Kind, Name: input.Tag.Name}
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "story.edit") {
return nil, ErrUnauthorized
}
story, err := story.FindID(input.ID)
if err != nil {
return nil, err
}
if story.Author != user.ID && !user.Permitted("story.edit") {
return nil, ErrPermissionDenied
}
err = story.AddTag(tag)
if err != nil {
return nil, err
}
go change.Submit("Story", "add.tag", user.ID, story.ID, map[string]interface{}{
"kind": tag.Kind,
"name": tag.Name,
})
return &types.StoryResolver{S: story}, nil
}

50
graphql/resolver/mutations/editChannel.go

@ -0,0 +1,50 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/channel"
)
// ChannelEditArgs is input for the editChannel mutation
type ChannelEditArgs struct {
Input *struct {
Name string
Logged *bool
Hub *bool
EventName *string
LocationName *string
}
}
// EditChannel resolves the editChannel mutation
func (r *MutationResolver) EditChannel(ctx context.Context, args *ChannelEditArgs) (*types.ChannelResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("channel.edit") {
return nil, ErrUnauthorized
}
channel, err := channel.FindName(input.Name)
if err != nil {
return nil, err
}
err = channel.Edit(input.Logged, input.Hub, input.EventName, input.LocationName)
if err != nil {
return nil, err
}
go change.Submit("Channel", "edit", user.ID, channel.Name, map[string]interface{}{
"logged": input.Logged,
"hub": input.Hub,
"location": input.LocationName,
"event": input.EventName,
})
return &types.ChannelResolver{C: channel}, nil
}

63
graphql/resolver/mutations/editChapter.go

@ -0,0 +1,63 @@
package mutations
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/story"
)
// EditChapterArgs is args for the editChapter mutation
type EditChapterArgs struct {
Input *struct {
ID string
Title *string
Source *string
FictionalDate *string
}
}
// EditChapter resolves the editChapter mutation
func (r *MutationResolver) EditChapter(ctx context.Context, args *EditChapterArgs) (*types.ChapterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "chapter.edit") {
return nil, ErrUnauthorized
}
chapter, err := story.FindChapterID(input.ID)
if err != nil {
return nil, err
}
if chapter.Author != user.ID && !user.Permitted("chapter.edit") {
return nil, ErrPermissionDenied
}
var fictionalDate *time.Time
if input.FictionalDate != nil {
date, err := time.Parse(time.RFC3339Nano, *input.FictionalDate)
if err != nil {
return nil, err
}
fictionalDate = &date
}
err = chapter.Edit(input.Title, input.Source, fictionalDate)
if err != nil {
return nil, err
}
go change.Submit("Chapter", "edit", user.ID, chapter.ID, map[string]interface{}{
"title": input.Title,
"source": input.Source,
"fictionalDate": fictionalDate,
})
return &types.ChapterResolver{C: chapter}, nil
}

64
graphql/resolver/mutations/editCharacter.go

@ -0,0 +1,64 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/character"
)
// CharacterEditInput is args for mutation addCharacterNick/removeCharacterNick
type CharacterEditInput struct {
ID string
Name *string
ShortName *string
Description *string
}
// EditCharacter resolves the editCharacter mutation
func (r *MutationResolver) EditCharacter(ctx context.Context, args struct{ Input *CharacterEditInput }) (*types.CharacterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
character, err := character.FindID(input.ID)
if err != nil {
return nil, err
}
if character.Author != user.ID && !user.Permitted("character.edit") {
return nil, ErrPermissionDenied
}
name := ""
if input.Name != nil {
name = *input.Name
}
shortName := ""
if input.ShortName != nil {
shortName = *input.ShortName
}
description := ""
if input.Description != nil {
description = *input.Description
}
err = character.Edit(name, shortName, description)
if err != nil {
return nil, err
}
go change.Submit("Character", "edit", user.ID, character.ID, map[string]interface{}{
"name": character.Name,
"shortName": character.ShortName,
"description": character.Description,
})
return &types.CharacterResolver{C: character}, nil
}

43
graphql/resolver/mutations/editFile.go

@ -0,0 +1,43 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/file"
)
// FileEditArgs is args for the editFile mutation
type FileEditArgs struct {
Input *struct {
ID string
Name *string
Public *bool
}
}
// EditFile resolves the editFile mutation
func (r *MutationResolver) EditFile(ctx context.Context, args *FileEditArgs) (*types.FileResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
file, err := file.FindID(input.ID)
if err != nil {
return nil, err
}
if file.Author != user.ID && !user.Permitted("file.edit") {
return nil, ErrUnauthorized
}
err = file.Edit(input.Name, input.Public)
if err != nil {
return nil, err
}
return &types.FileResolver{F: file}, nil
}

51
graphql/resolver/mutations/editLog.go

@ -0,0 +1,51 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/log"
)
// LogEditArgs is args for the editLog mutation
type LogEditArgs struct {
Input *struct {
ID string
Title *string
Event *string
Description *string
Open *bool
}
}
// EditLog resolves the editLog mutation
func (r *MutationResolver) EditLog(ctx context.Context, args *LogEditArgs) (*types.LogResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("log.edit") {
return nil, ErrUnauthorized
}
log, err := log.FindID(input.ID)
if err != nil {
return nil, err
}
err = log.Edit(input.Title, input.Event, input.Description, input.Open)
if err != nil {
return nil, err
}
go change.Submit("Log", "edit", user.ID, log.ID, map[string]interface{}{
"channel": log.Channel,
"title": input.Title,
"event": input.Event,
"description": input.Description,
"open": input.Open,
})
return &types.LogResolver{L: log}, nil
}

63
graphql/resolver/mutations/editPost.go

@ -0,0 +1,63 @@
package mutations
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/log"
)
// PostEditArgs is args for the editPost mutation
type PostEditArgs struct {
Input *struct {
ID string
Time *string
Kind *string
Nick *string
Text *string
}
}
// EditPost resolves the editPost mutation
func (r *MutationResolver) EditPost(ctx context.Context, args *PostEditArgs) (*types.PostResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("post.edit") {
return nil, ErrUnauthorized
}
postTime := (*time.Time)(nil)
if args.Input.Time != nil {
t, err := time.Parse(time.RFC3339Nano, *input.Time)
if err != nil {
return nil, err
}
postTime = &t
}
post, err := log.FindPostID(input.ID)
if err != nil {
return nil, err
}
err = post.Edit(postTime, input.Kind, input.Nick, input.Text)
if err != nil {
return nil, err
}
go change.Submit("Post", "edit", user.ID, post.ID, map[string]interface{}{
"time": postTime,
"kind": input.Kind,
"nick": input.Nick,
"text": input.Text,
})
go log.UpdateCharacters(post.LogID)
return &types.PostResolver{P: post}, nil
}

69
graphql/resolver/mutations/editStory.go

@ -0,0 +1,69 @@
package mutations
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/story"
)
// StoryEditArgs is args for the addStory mutation
type StoryEditArgs struct {
Input *struct {
ID string
Name *string
Category *string
Author *string
Open *bool
Listed *bool
FictionalDate *string
}
}
// EditStory resolves the editStory mutation
func (r *MutationResolver) EditStory(ctx context.Context, args *StoryEditArgs) (*types.StoryResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "story.edit") {
return nil, ErrUnauthorized
}
story, err := story.FindID(input.ID)
if err != nil {
return nil, err
}
if story.Author != user.ID && !user.Permitted("story.edit") {
return nil, ErrPermissionDenied
}
var fictionalDate *time.Time
if input.FictionalDate != nil {
date, err := time.Parse(time.RFC3339Nano, *input.FictionalDate)
if err != nil {
return nil, err
}
fictionalDate = &date
}
err = story.Edit(input.Name, input.Category, input.Listed, input.Open, fictionalDate)
if err != nil {
return nil, err
}
go change.Submit("Story", "edit", user.ID, story.ID, map[string]interface{}{
"name": input.Name,
"category": input.Category,
"author": input.Author,
"open": input.Open,
"listed": input.Listed,
"fictionalDate": input.FictionalDate,
})
return &types.StoryResolver{S: story}, nil
}

26
graphql/resolver/mutations/login.go

@ -0,0 +1,26 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
)
// LoginArgs is args for the login mutation
type LoginArgs struct {
Username string
Password string
}
// Login resolves the login mutation
func (r *MutationResolver) Login(ctx context.Context, args *LoginArgs) (*types.SessionResolver, error) {
session := session.FromContext(ctx)
err := session.Login(args.Username, args.Password)
if err != nil {
return nil, err
}
return &types.SessionResolver{S: session}, nil
}

16
graphql/resolver/mutations/logout.go

@ -0,0 +1,16 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
)
// Logout resolves mutation.logout
func (r *MutationResolver) Logout(ctx context.Context) (*types.SessionResolver, error) {
session := session.FromContext(ctx)
session.Logout()
return &types.SessionResolver{S: session}, nil
}

45
graphql/resolver/mutations/movePost.go

@ -0,0 +1,45 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/log"
)
// PostMoveArgs is args for movePost mutation
type PostMoveArgs struct {
Input *struct {
ID string
ToPosition int32
}
}
// MovePost resolves the movePost mutation
func (r *MutationResolver) MovePost(ctx context.Context, args *PostMoveArgs) (*types.PostResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("post.move") {
return nil, ErrUnauthorized
}
post, err := log.FindPostID(input.ID)
if err != nil {
return nil, err
}
err = post.Move(int(input.ToPosition))
if err != nil {
return nil, err
}
go change.Submit("Post", "move", user.ID, post.ID, map[string]interface{}{
"logId": post.LogID,
"targetIndex": input.ToPosition,
})
return &types.PostResolver{P: post}, nil
}

37
graphql/resolver/mutations/removeChannel.go

@ -0,0 +1,37 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/channel"
)
// RemoveChannelArgs is args for removeChannels mutation
type RemoveChannelArgs struct {
Name string
}
// RemoveChannel resolves the editChannel mutation
func (r *MutationResolver) RemoveChannel(ctx context.Context, args RemoveChannelArgs) (*types.ChannelResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("channel.remove") {
return nil, ErrUnauthorized
}
channel, err := channel.FindName(args.Name)
if err != nil {
return nil, err
}
err = channel.Remove()
if err != nil {
return nil, err
}
go change.Submit("Channel", "remove", user.ID, channel.Name, nil)
return &types.ChannelResolver{C: channel}, nil
}

37
graphql/resolver/mutations/removeChapter.go

@ -0,0 +1,37 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/story"
)
// RemoveChapterArgs is args for the addChapter mutation
type RemoveChapterArgs struct {
ID string
}
// RemoveChapter resolves the removeChapter mutation
func (r *MutationResolver) RemoveChapter(ctx context.Context, args *RemoveChapterArgs) (*types.ChapterResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "chapter.edit") {
return nil, ErrUnauthorized
}
chapter, err := story.FindChapterID(args.ID)
if err != nil {
return nil, err
}
err = chapter.Remove()
if err != nil {
return nil, err
}
go change.Submit("Chapter", "remove", user.ID, chapter.ID, nil)
return &types.ChapterResolver{C: chapter}, nil
}

44
graphql/resolver/mutations/removeCharacter.go

@ -0,0 +1,44 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/character"
)
// RemoveCharacterArgs is args for the removeCharacter mutation
type RemoveCharacterArgs struct {
ID string
}
// RemoveCharacter resolves the removeCharacter mutation
func (r *MutationResolver) RemoveCharacter(ctx context.Context, args RemoveCharacterArgs) (*types.CharacterResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
character, err := character.FindID(args.ID)
if err != nil {
return nil, err
}
if character.Author != user.ID && !user.Permitted("character.remove") {
return nil, ErrPermissionDenied
}
err = character.Remove()
if err != nil {
return nil, err
}
go change.Submit("Character", "remove", user.ID, character.ID, map[string]interface{}{
"name": character.Name,
"author": character.Author,
"nicks": character.Nicks,
})
return &types.CharacterResolver{C: character}, nil
}

48
graphql/resolver/mutations/removeCharacterNick.go

@ -0,0 +1,48 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/character"
"git.aiterp.net/rpdata/api/model/log"
)
// RemoveCharacterNick is args for the addCharacterNick mutation
type RemoveCharacterNick struct {
ID string
Nick string
}
// RemoveCharacterNick resolves the removeCharacterNick mutation
func (r *MutationResolver) RemoveCharacterNick(ctx context.Context, args struct{ Input *RemoveCharacterNick }) (*types.CharacterResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
character, err := character.FindID(input.ID)
if err != nil {
return nil, err
}
if character.Author != user.ID && !user.Permitted("character.edit") {
return nil, ErrPermissionDenied
}
err = character.RemoveNick(input.Nick)
if err != nil {
return nil, err
}
go change.Submit("Character", "remove.nick", user.ID, character.ID, map[string]interface{}{
"nick": input.Nick,
})
log.ScheduleCharacterUpdate()
return &types.CharacterResolver{C: character}, nil
}

37
graphql/resolver/mutations/removeFile.go

@ -0,0 +1,37 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/file"
)
// RemoveFileArgs is an arg
type RemoveFileArgs struct {
ID string
}
// RemoveFile resolves the removeFIle mutation
func (r *MutationResolver) RemoveFile(ctx context.Context, args *RemoveFileArgs) (*types.FileResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member") {
return nil, ErrUnauthorized
}
file, err := file.FindID(args.ID)
if err != nil {
return nil, err
}
if file.Author != user.ID && !user.Permitted("file.remove") {
return nil, ErrUnauthorized
}
err = file.Delete()
if err != nil {
return nil, err
}
return &types.FileResolver{F: file}, nil
}

37
graphql/resolver/mutations/removeLog.go

@ -0,0 +1,37 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/log"
)
// RemoveLogArgs is args for the removeLog mutation
type RemoveLogArgs struct {
ID string
}
// RemoveLog resolves the removeLog mutation
func (r *MutationResolver) RemoveLog(ctx context.Context, args *RemoveLogArgs) (*types.LogResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("log.remove") {
return nil, ErrUnauthorized
}
log, err := log.FindID(args.ID)
if err != nil {
return nil, err
}
err = log.Remove()
if err != nil {
return nil, err
}
go change.Submit("Log", "remove", user.ID, log.ID, nil)
return &types.LogResolver{L: log}, nil
}

36
graphql/resolver/mutations/removePost.go

@ -0,0 +1,36 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/log"
)
// PostRemoveArgs is args for the removePost mutation
type PostRemoveArgs struct {
ID string
}
// RemovePost resolves the removePost mutation
func (r *MutationResolver) RemovePost(ctx context.Context, args PostRemoveArgs) (*types.PostResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("post.remove") {
return nil, ErrUnauthorized
}
post, err := log.RemovePost(args.ID)
if err != nil {
return nil, err
}
go change.Submit("Post", "remove", user.ID, post.ID, map[string]interface{}{
"logId": post.LogID,
})
go log.UpdateCharacters(post.LogID)
return &types.PostResolver{P: post}, nil
}

41
graphql/resolver/mutations/removeStory.go

@ -0,0 +1,41 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/story"
)
// StoryRemoveArgs is args for the removeStory mutation
type StoryRemoveArgs struct {
ID string
}
// RemoveStory resolves the removeStory mutation
func (r *MutationResolver) RemoveStory(ctx context.Context, args *StoryRemoveArgs) (*types.StoryResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "story.edit") {
return nil, ErrUnauthorized
}
story, err := story.FindID(args.ID)
if err != nil {
return nil, err
}
if story.Author != user.ID && !user.Permitted("story.remove") {
return nil, ErrPermissionDenied
}
err = story.Remove()
if err != nil {
return nil, err
}
go change.Submit("Story", "remove", user.ID, story.ID, nil)
return &types.StoryResolver{S: story}, nil
}

53
graphql/resolver/mutations/removeStoryTag.go

@ -0,0 +1,53 @@
package mutations
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/story"
)
// StoryTagRemoveArgs is args for the removeStoryTag mutation
type StoryTagRemoveArgs struct {
Input *struct {
ID string
Tag struct {
Kind string
Name string
}
}
}
// RemoveStoryTag resolves the removeStoryTag mutation
func (r *MutationResolver) RemoveStoryTag(ctx context.Context, args *StoryTagRemoveArgs) (*types.StoryResolver, error) {
input := args.Input
tag := story.Tag{Kind: input.Tag.Kind, Name: input.Tag.Name}
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "story.edit") {
return nil, ErrUnauthorized
}
story, err := story.FindID(input.ID)
if err != nil {
return nil, err
}
if story.Author != user.ID && !user.Permitted("story.edit") {
return nil, ErrPermissionDenied
}
err = story.RemoveTag(tag)
if err != nil {
return nil, err
}
go change.Submit("Story", "remove.tag", user.ID, story.ID, map[string]interface{}{
"kind": tag.Kind,
"name": tag.Name,
})
return &types.StoryResolver{S: story}, nil
}

14
graphql/resolver/mutations/resolver.go

@ -0,0 +1,14 @@
// Package mutations contains resolvers for individual GrahpQL mutations. They were previously mixed in with one another, but that caused
// difficulty seeking out specific mutations.
package mutations
import "errors"
// MutationResolver is a resolver for all mutations. The stuttery name is due to being embedded in the root resolver.
type MutationResolver struct{}
// ErrUnauthorized is when a guest acts like they own the place
var ErrUnauthorized = errors.New("Unauthorized")
// ErrPermissionDenied is returned when users act above their station
var ErrPermissionDenied = errors.New("Permission denied")

208
graphql/resolver/post.go

@ -1,208 +0,0 @@
package resolver
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/log"
)
// PostArgs is an arg
type PostArgs struct {
ID string
}
// Post implements the post query
func (r *QueryResolver) Post(ctx context.Context, args *PostArgs) (*types.PostResolver, error) {
post, err := log.FindPostID(args.ID)
if err != nil {
return nil, err
}
return &types.PostResolver{P: post}, nil
}
// PostsArgs is an arg
type PostsArgs struct {
IDs []string
}
// Posts implements the posts query
func (r *QueryResolver) Posts(ctx context.Context, args *PostsArgs) ([]*types.PostResolver, error) {
posts, err := log.ListPostIDs(args.IDs...)
if err != nil {
return nil, err
}
resolvers := make([]*types.PostResolver, len(posts))
for i := range resolvers {
resolvers[i] = &types.PostResolver{P: posts[i]}
}
return resolvers, nil
}
// PostAddArgs is args for addPost mutation
type PostAddArgs struct {
Input *struct {
LogID string
Time string
Kind string
Nick string
Text string
}
}
// AddPost resolves the addPost mutation
func (r *MutationResolver) AddPost(ctx context.Context, args *PostAddArgs) (*types.PostResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("post.add") {
return nil, ErrUnauthorized
}
postTime, err := time.Parse(time.RFC3339Nano, input.Time)
if err != nil {
return nil, err
}
log, err := log.FindID(input.LogID)
if err != nil {
return nil, err
}
post, err := log.NewPost(postTime, input.Kind, input.Nick, input.Text)
if err != nil {
return nil, err
}
go change.Submit("Post", "add", user.ID, post.ID, map[string]interface{}{
"logId": post.LogID,
"time": post.Time,
"kind": post.Kind,
"nick": post.Nick,
"text": post.Text,
"position": post.Position,
})
go log.UpdateCharacters()
return &types.PostResolver{P: post}, nil
}
// PostEditArgs is args for the editPost mutation
type PostEditArgs struct {
Input *struct {
ID string
Time *string
Kind *string
Nick *string
Text *string
}
}
// EditPost resolves the editPost mutation
func (r *MutationResolver) EditPost(ctx context.Context, args *PostEditArgs) (*types.PostResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("post.edit") {
return nil, ErrUnauthorized
}
postTime := (*time.Time)(nil)
if args.Input.Time != nil {
t, err := time.Parse(time.RFC3339Nano, *input.Time)
if err != nil {
return nil, err
}
postTime = &t
}
post, err := log.FindPostID(input.ID)
if err != nil {
return nil, err
}
err = post.Edit(postTime, input.Kind, input.Nick, input.Text)
if err != nil {
return nil, err
}
go change.Submit("Post", "edit", user.ID, post.ID, map[string]interface{}{
"time": postTime,
"kind": input.Kind,
"nick": input.Nick,
"text": input.Text,
})
go log.UpdateCharacters(post.LogID)
return &types.PostResolver{P: post}, nil
}
// PostMoveArgs is args for movePost mutation
type PostMoveArgs struct {
Input *struct {
ID string
ToPosition int32
}
}
// MovePost resolves the movePost mutation
func (r *MutationResolver) MovePost(ctx context.Context, args *PostMoveArgs) (*types.PostResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("post.move") {
return nil, ErrUnauthorized
}
post, err := log.FindPostID(input.ID)
if err != nil {
return nil, err
}
err = post.Move(int(input.ToPosition))
if err != nil {
return nil, err
}
go change.Submit("Post", "move", user.ID, post.ID, map[string]interface{}{
"logId": post.LogID,
"targetIndex": input.ToPosition,
})
return &types.PostResolver{P: post}, nil
}
// PostRemoveArgs is an arg
type PostRemoveArgs struct {
ID string
}
// RemovePost resolves the removePost mutation
func (r *MutationResolver) RemovePost(ctx context.Context, args PostRemoveArgs) (*types.PostResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("post.remove") {
return nil, ErrUnauthorized
}
post, err := log.RemovePost(args.ID)
if err != nil {
return nil, err
}
go change.Submit("Post", "remove", user.ID, post.ID, map[string]interface{}{
"logId": post.LogID,
})
go log.UpdateCharacters(post.LogID)
return &types.PostResolver{P: post}, nil
}

23
graphql/resolver/queries/channel.go

@ -0,0 +1,23 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/channel"
)
// ChannelArgs is args for channel query
type ChannelArgs struct {
Name string
}
// Channel resolves the channel query
func (r *QueryResolver) Channel(ctx context.Context, args *ChannelArgs) (*types.ChannelResolver, error) {
channel, err := channel.FindName(args.Name)
if err != nil {
return nil, err
}
return &types.ChannelResolver{C: channel}, nil
}

28
graphql/resolver/queries/channels.go

@ -0,0 +1,28 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/channel"
)
// ChannelsArgs is args for channel query
type ChannelsArgs struct {
Logged *bool
}
// Channels resolves the channels query
func (r *QueryResolver) Channels(ctx context.Context, args *ChannelsArgs) ([]*types.ChannelResolver, error) {
channels, err := channel.List(args.Logged != nil && *args.Logged)
if err != nil {
return nil, err
}
resolvers := make([]*types.ChannelResolver, len(channels))
for i := range channels {
resolvers[i] = &types.ChannelResolver{C: channels[i]}
}
return resolvers, nil
}

23
graphql/resolver/queries/chapter.go

@ -0,0 +1,23 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/story"
)
// ChapterArgs is args for chapter query
type ChapterArgs struct {
ID string
}
// Chapter resolves the chapter query
func (r *QueryResolver) Chapter(ctx context.Context, args *ChapterArgs) (*types.ChapterResolver, error) {
chapter, err := story.FindChapterID(args.ID)
if err != nil {
return nil, err
}
return &types.ChapterResolver{C: chapter}, nil
}

43
graphql/resolver/queries/character.go

@ -0,0 +1,43 @@
package queries
import (
"context"
"errors"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/character"
)
// ErrIncorrectArguments is returned by character query.
var ErrIncorrectArguments = errors.New("You can only query character by ID or Nick")
// CharacterArgs is args for character query
type CharacterArgs struct {
ID *string
Nick *string
}
// Character resolves the character query
func (r *QueryResolver) Character(ctx context.Context, args *CharacterArgs) (*types.CharacterResolver, error) {
var char character.Character
var err error
if args.Nick != nil && args.ID != nil {
return nil, ErrIncorrectArguments
}
switch {
case args.ID != nil:
char, err = character.FindID(*args.ID)
case args.Nick != nil:
char, err = character.FindNick(*args.Nick)
default:
err = ErrIncorrectArguments
}
if err != nil {
return nil, err
}
return &types.CharacterResolver{C: char}, nil
}

54
graphql/resolver/queries/characters.go

@ -0,0 +1,54 @@
package queries
import (
"context"
"errors"
"git.aiterp.net/rpdata/api/graphql/loader"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/character"
)
// CharactersArgs is args for characters query
type CharactersArgs struct {
IDs *[]string
Nicks *[]string
Author *string
}
// Characters resolves the characters query
func (r *QueryResolver) Characters(ctx context.Context, args *CharactersArgs) ([]*types.CharacterResolver, error) {
var chars []character.Character
var err error
loader := loader.FromContext(ctx)
if loader == nil {
return nil, errors.New("no loader")
}
switch {
case args.IDs != nil:
chars, err = character.ListIDs(*args.IDs...)
case args.Nicks != nil:
chars, err = character.ListNicks(*args.Nicks...)
case args.Author != nil:
chars, err = character.ListAuthor(*args.Author)
default:
chars, err = character.List()
}
if err != nil {
return nil, err
}
resolvers := make([]*types.CharacterResolver, 0, len(chars))
for i := range chars {
if chars[i].ID == "" {
continue
}
resolvers = append(resolvers, &types.CharacterResolver{C: chars[i]})
}
return resolvers, nil
}

23
graphql/resolver/queries/file.go

@ -0,0 +1,23 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/file"
)
// FileArgs is args for file query
type FileArgs struct {
ID string
}
// File resolves the file query
func (r *QueryResolver) File(ctx context.Context, args *FileArgs) (*types.FileResolver, error) {
file, err := file.FindID(args.ID)
if err != nil {
return nil, err
}
return &types.FileResolver{F: file}, nil
}

43
graphql/resolver/queries/files.go

@ -0,0 +1,43 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/file"
)
// FilesArgs is args for files query
type FilesArgs struct {
IncludePublic *bool
MimeTypes *[]string
}
// Files resolves the file query
func (r *QueryResolver) Files(ctx context.Context, args *FilesArgs) ([]*types.FileResolver, error) {
user := session.FromContext(ctx).User()
author := ""
if user != nil {
author = user.ID
}
public := args.IncludePublic != nil && *args.IncludePublic == true
mimeTypes := []string(nil)
if args.MimeTypes != nil {
mimeTypes = *args.MimeTypes
}
files, err := file.List(author, public, mimeTypes)
if err != nil {
return nil, err
}
resolvers := make([]*types.FileResolver, len(files))
for i := range files {
resolvers[i] = &types.FileResolver{F: files[i]}
}
return resolvers, nil
}

32
graphql/resolver/queries/log.go

@ -0,0 +1,32 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/log"
)
// LogArgs is args for log query
type LogArgs struct {
ID *string
}
// Log resolves the log query
func (r *QueryResolver) Log(ctx context.Context, args *LogArgs) (*types.LogResolver, error) {
var l log.Log
var err error
switch {
case args.ID != nil:
l, err = log.FindID(*args.ID)
default:
err = ErrCannotResolve
}
if err != nil {
return nil, err
}
return &types.LogResolver{L: l}, nil
}

79
graphql/resolver/queries/logs.go

@ -0,0 +1,79 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/log"
)
// LogsArgs is args for the logs query
type LogsArgs struct {
Filter *struct {
Search *string
Characters *[]string
Channels *[]string
Events *[]string
Open *bool
Limit *int32
}
}
// Logs resolves the logs query
func (r *QueryResolver) Logs(ctx context.Context, args *LogsArgs) ([]*types.LogResolver, error) {
var logs []log.Log
var err error
filter := args.Filter
if filter != nil {
limit := 100
search := ""
if filter.Search != nil {
search = *filter.Search
limit = 0
}
channels := []string(nil)
if filter.Channels != nil {
channels = *filter.Channels
limit = 0
}
characters := []string(nil)
if filter.Characters != nil {
characters = *filter.Characters
limit = 0
}
events := []string(nil)
if filter.Events != nil {
events = *filter.Events
limit = 0
}
if filter.Limit != nil {
limit = int(*filter.Limit)
}
open := filter.Open != nil && *filter.Open == true
logs, err = log.ListSearch(search, channels, characters, events, open, limit)
if err != nil {
return nil, err
}
} else {
logs, err = log.List(100)
if err != nil {
return nil, err
}
}
resolvers := make([]*types.LogResolver, len(logs))
for i := range logs {
resolvers[i] = &types.LogResolver{L: logs[i]}
}
return resolvers, nil
}

23
graphql/resolver/queries/post.go

@ -0,0 +1,23 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/log"
)
// PostArgs is args for the post query
type PostArgs struct {
ID string
}
// Post resolves the post query
func (r *QueryResolver) Post(ctx context.Context, args *PostArgs) (*types.PostResolver, error) {
post, err := log.FindPostID(args.ID)
if err != nil {
return nil, err
}
return &types.PostResolver{P: post}, nil
}

28
graphql/resolver/queries/posts.go

@ -0,0 +1,28 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/log"
)
// PostsArgs is args for the posts query
type PostsArgs struct {
IDs []string
}
// Posts resolves the posts query
func (r *QueryResolver) Posts(ctx context.Context, args *PostsArgs) ([]*types.PostResolver, error) {
posts, err := log.ListPostIDs(args.IDs...)
if err != nil {
return nil, err
}
resolvers := make([]*types.PostResolver, len(posts))
for i := range resolvers {
resolvers[i] = &types.PostResolver{P: posts[i]}
}
return resolvers, nil
}

11
graphql/resolver/queries/resolver.go

@ -0,0 +1,11 @@
// Package queries contains resolvers for individual GrahpQL queries. They were previously mixed in with one another, but that caused
// difficulty seeking out specific queries.
package queries
import "errors"
// QueryResolver is a resolver for all queries. The stuttery name is due to being embedded in the root resolver.
type QueryResolver struct{}
// ErrCannotResolve is returned when a resolver constructor is at its wit's end
var ErrCannotResolve = errors.New("Cannot resolve due to invalid arguments")

13
graphql/resolver/queries/session.go

@ -0,0 +1,13 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
)
// Session resolves query.session
func (r *QueryResolver) Session(ctx context.Context) (*types.SessionResolver, error) {
return &types.SessionResolver{S: session.FromContext(ctx)}, nil
}

77
graphql/resolver/queries/stories.go

@ -0,0 +1,77 @@
package queries
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/story"
)
// StoriesArg is args for stories query
type StoriesArg struct {
Filter *struct {
Author *string
Tags *[]struct {
Kind string
Name string
}
EarliestFictionalDate *string
LatestFictionalDate *string
Limit *int32
}
}
// Stories resolves the stories query
func (r *QueryResolver) Stories(ctx context.Context, args *StoriesArg) ([]*types.StoryResolver, error) {
filter := args.Filter
author := ""
if filter != nil && filter.Author != nil {
author = *filter.Author
}
tags := make([]story.Tag, 0, 8)
if filter != nil && filter.Tags != nil {
for _, tagInput := range *filter.Tags {
tags = append(tags, story.Tag{
Kind: tagInput.Kind,
Name: tagInput.Name,
})
}
}
earliest := time.Time{}
err := error(nil)
if filter != nil && filter.EarliestFictionalDate != nil {
earliest, err = time.Parse(time.RFC3339Nano, *filter.EarliestFictionalDate)
if err != nil {
return nil, err
}
}
latest := time.Time{}
if filter != nil && filter.LatestFictionalDate != nil {
latest, err = time.Parse(time.RFC3339Nano, *filter.LatestFictionalDate)
if err != nil {
return nil, err
}
}
limit := 30
if filter != nil && filter.Limit != nil {
limit = int(*filter.Limit)
}
stories, err := story.List(author, tags, earliest, latest, limit)
if err != nil {
return nil, err
}
resolvers := make([]*types.StoryResolver, len(stories))
for i, story := range stories {
resolvers[i] = &types.StoryResolver{S: story}
}
return resolvers, nil
}

23
graphql/resolver/queries/story.go

@ -0,0 +1,23 @@
package queries
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/story"
)
// StoryArgs is args for story query
type StoryArgs struct {
ID string
}
// Story resolves the story query
func (r *QueryResolver) Story(ctx context.Context, args *StoryArgs) (*types.StoryResolver, error) {
story, err := story.FindID(args.ID)
if err != nil {
return nil, err
}
return &types.StoryResolver{S: story}, nil
}

10
graphql/resolver/tag.go → graphql/resolver/queries/tags.go

@ -1,17 +1,11 @@
package resolver
package queries
import ( import (
"git.aiterp.net/rpdata/api/graphql/resolver/types" "git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/model/story" "git.aiterp.net/rpdata/api/model/story"
) )
// TagInput resolves the TagInput input
type TagInput struct {
Kind string
Name string
}
// Tags implements the tags query
// Tags resolves the tags query
func (r *QueryResolver) Tags() ([]*types.TagResolver, error) { func (r *QueryResolver) Tags() ([]*types.TagResolver, error) {
tags, err := story.ListTags() tags, err := story.ListTags()
if err != nil { if err != nil {

13
graphql/resolver/resolver.go

@ -0,0 +1,13 @@
package resolver
import (
"git.aiterp.net/rpdata/api/graphql/resolver/mutations"
"git.aiterp.net/rpdata/api/graphql/resolver/queries"
)
// The Resolver combines the query and mutation resolvers from the subpackages.
// This is the one to pass along with the schema.
type Resolver struct {
queries.QueryResolver
mutations.MutationResolver
}

13
graphql/resolver/root.go

@ -1,13 +0,0 @@
package resolver
// The RootResolver brings queries and mutations together. The rest is just for readability.
type RootResolver struct {
MutationResolver
QueryResolver
}
// The QueryResolver is the entry point for all top-level read operations.
type QueryResolver struct{}
// The MutationResolver is the entry point for all top-level mutation operations.
type MutationResolver struct{}

39
graphql/resolver/session.go

@ -1,39 +0,0 @@
package resolver
import (
"context"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
)
// LoginArgs is args
type LoginArgs struct {
Username string
Password string
}
// Session resolves query.session
func (r *QueryResolver) Session(ctx context.Context) (*types.SessionResolver, error) {
return &types.SessionResolver{S: session.FromContext(ctx)}, nil
}
// Login resolves mutation.login
func (r *MutationResolver) Login(ctx context.Context, args *LoginArgs) (*types.SessionResolver, error) {
session := session.FromContext(ctx)
err := session.Login(args.Username, args.Password)
if err != nil {
return nil, err
}
return &types.SessionResolver{S: session}, nil
}
// Logout resolves mutation.logout
func (r *MutationResolver) Logout(ctx context.Context) (*types.SessionResolver, error) {
session := session.FromContext(ctx)
session.Logout()
return &types.SessionResolver{S: session}, nil
}

329
graphql/resolver/story.go

@ -1,329 +0,0 @@
package resolver
import (
"context"
"time"
"git.aiterp.net/rpdata/api/graphql/resolver/types"
"git.aiterp.net/rpdata/api/internal/session"
"git.aiterp.net/rpdata/api/model/change"
"git.aiterp.net/rpdata/api/model/story"
)
// StoryArgs is args for story query
type StoryArgs struct {
ID string
}
// Story implements the story query
func (r *QueryResolver) Story(ctx context.Context, args *StoryArgs) (*types.StoryResolver, error) {
story, err := story.FindID(args.ID)
if err != nil {
return nil, err
}
return &types.StoryResolver{S: story}, nil
}
// StoriesArg is args for stories query
type StoriesArg struct {
Filter *struct {
Author *string
Tags *[]TagInput
EarliestFictionalDate *string
LatestFictionalDate *string
Limit *int32
}
}
// Stories implements the stories query
func (r *QueryResolver) Stories(ctx context.Context, args *StoriesArg) ([]*types.StoryResolver, error) {
filter := args.Filter
author := ""
if filter != nil && filter.Author != nil {
author = *filter.Author
}
tags := make([]story.Tag, 0, 8)
if filter != nil && filter.Tags != nil {
for _, tagInput := range *filter.Tags {
tags = append(tags, story.Tag{
Kind: tagInput.Kind,
Name: tagInput.Name,
})
}
}
earliest := time.Time{}
err := error(nil)
if filter != nil && filter.EarliestFictionalDate != nil {
earliest, err = time.Parse(time.RFC3339Nano, *filter.EarliestFictionalDate)
if err != nil {
return nil, err
}
}
latest := time.Time{}
if filter != nil && filter.LatestFictionalDate != nil {
latest, err = time.Parse(time.RFC3339Nano, *filter.LatestFictionalDate)
if err != nil {
return nil, err
}
}
limit := 30
if filter != nil && filter.Limit != nil {
limit = int(*filter.Limit)
}
stories, err := story.List(author, tags, earliest, latest, limit)
if err != nil {
return nil, err
}
resolvers := make([]*types.StoryResolver, len(stories))
for i, story := range stories {
resolvers[i] = &types.StoryResolver{S: story}
}
return resolvers, nil
}
// StoryAddArgs is args for the addStory mutation
type StoryAddArgs struct {
Input *struct {
Name string
Category string
Author *string
Open *bool
Listed *bool
Tags *[]TagInput
FictionalDate *string
}
}
// AddStory implements the addStory mutation
func (r *MutationResolver) AddStory(ctx context.Context, args *StoryAddArgs) (*types.StoryResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "story.add") {
return nil, ErrUnauthorized
}
author := user.ID
if input.Author != nil {
author = *input.Author
if user.ID != author && !user.Permitted("story.add") {
return nil, ErrPermissionDenied
}
}
listed := (input.Listed != nil && *input.Listed == true)
open := (input.Open != nil && *input.Open == true)
tags := make([]story.Tag, 0, 8)
if input.Tags != nil {
for _, tagInput := range *input.Tags {
tags = append(tags, story.Tag{
Kind: tagInput.Kind,
Name: tagInput.Name,
})
}
}
fictionalDate := time.Time{}
if input.FictionalDate != nil {
date, err := time.Parse(time.RFC3339Nano, *input.FictionalDate)
if err != nil {
return nil, err
}
fictionalDate = date
}
story, err := story.New(input.Name, author, input.Category, listed, open, tags, time.Now(), fictionalDate)
if err != nil {
return nil, err
}
go change.Submit("Story", "add", user.ID, story.ID, map[string]interface{}{
"name": input.Name,
"category": input.Category,
"author": input.Author,
})
return &types.StoryResolver{S: story}, nil
}
// StoryTagAddArgs is args for the addStoryTag mutation
type StoryTagAddArgs struct {
Input *struct {
ID string
Tag TagInput
}
}
// AddStoryTag implements the addStoryTag mutation
func (r *MutationResolver) AddStoryTag(ctx context.Context, args *StoryTagAddArgs) (*types.StoryResolver, error) {
input := args.Input
tag := story.Tag{Kind: input.Tag.Kind, Name: input.Tag.Name}
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "story.edit") {
return nil, ErrUnauthorized
}
story, err := story.FindID(input.ID)
if err != nil {
return nil, err
}
if story.Author != user.ID && !user.Permitted("story.edit") {
return nil, ErrPermissionDenied
}
err = story.AddTag(tag)
if err != nil {
return nil, err
}
go change.Submit("Story", "add.tag", user.ID, story.ID, map[string]interface{}{
"kind": tag.Kind,
"name": tag.Name,
})
return &types.StoryResolver{S: story}, nil
}
// StoryTagRemoveArgs is args for the removeStoryTag mutation
type StoryTagRemoveArgs struct {
Input *struct {
ID string
Tag TagInput
}
}
// RemoveStoryTag implements the removeStoryTag mutation
func (r *MutationResolver) RemoveStoryTag(ctx context.Context, args *StoryTagRemoveArgs) (*types.StoryResolver, error) {
input := args.Input
tag := story.Tag{Kind: input.Tag.Kind, Name: input.Tag.Name}
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "story.edit") {
return nil, ErrUnauthorized
}
story, err := story.FindID(input.ID)
if err != nil {
return nil, err
}
if story.Author != user.ID && !user.Permitted("story.edit") {
return nil, ErrPermissionDenied
}
err = story.RemoveTag(tag)
if err != nil {
return nil, err
}
go change.Submit("Story", "remove.tag", user.ID, story.ID, map[string]interface{}{
"kind": tag.Kind,
"name": tag.Name,
})
return &types.StoryResolver{S: story}, nil
}
// StoryEditArgs is args for the addStory mutation
type StoryEditArgs struct {
Input *struct {
ID string
Name *string
Category *string
Author *string
Open *bool
Listed *bool
FictionalDate *string
}
}
// EditStory implements the editStory mutation
func (r *MutationResolver) EditStory(ctx context.Context, args *StoryEditArgs) (*types.StoryResolver, error) {
input := args.Input
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "story.edit") {
return nil, ErrUnauthorized
}
story, err := story.FindID(input.ID)
if err != nil {
return nil, err
}
if story.Author != user.ID && !user.Permitted("story.edit") {
return nil, ErrPermissionDenied
}
var fictionalDate *time.Time
if input.FictionalDate != nil {
date, err := time.Parse(time.RFC3339Nano, *input.FictionalDate)
if err != nil {
return nil, err
}
fictionalDate = &date
}
err = story.Edit(input.Name, input.Category, input.Listed, input.Open, fictionalDate)
if err != nil {
return nil, err
}
go change.Submit("Story", "edit", user.ID, story.ID, map[string]interface{}{
"name": input.Name,
"category": input.Category,
"author": input.Author,
"open": input.Open,
"listed": input.Listed,
"fictionalDate": input.FictionalDate,
})
return &types.StoryResolver{S: story}, nil
}
// StoryRemoveArgs is args for the removeStory mutation
type StoryRemoveArgs struct {
ID string
}
// RemoveStory implements the removeStory mutation
func (r *MutationResolver) RemoveStory(ctx context.Context, args *StoryRemoveArgs) (*types.StoryResolver, error) {
user := session.FromContext(ctx).User()
if user == nil || !user.Permitted("member", "story.edit") {
return nil, ErrUnauthorized
}
story, err := story.FindID(args.ID)
if err != nil {
return nil, err
}
if story.Author != user.ID && !user.Permitted("story.remove") {
return nil, ErrPermissionDenied
}
err = story.Remove()
if err != nil {
return nil, err
}
go change.Submit("Story", "remove", user.ID, story.ID, nil)
return &types.StoryResolver{S: story}, nil
}
Loading…
Cancel
Save