Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba1c1e0a4b | ||
|
|
18e77b8205 | ||
|
|
d8871259a1 | ||
|
|
26d7e36631 | ||
|
|
51489ed901 | ||
|
|
ed3e384d55 | ||
|
|
9455fd960f | ||
|
|
36939ffc59 | ||
|
|
5fedce5899 | ||
|
|
dced5282b1 | ||
|
|
d05f3a8ca8 | ||
|
|
53e2dfc6b6 | ||
|
|
fba499024b | ||
|
|
cc765e220a | ||
|
|
ba49b1fd30 | ||
|
|
8c290c8dcd | ||
|
|
576e1df001 |
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
vendor
|
vendor
|
||||||
schema/bindata.go
|
graphql/schema/bindata.go
|
||||||
config.json
|
config.json
|
||||||
api
|
api
|
||||||
debug
|
debug
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/graphql/loader"
|
||||||
|
"git.aiterp.net/rpdata/api/graphql/resolver"
|
||||||
|
"git.aiterp.net/rpdata/api/graphql/schema"
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
"git.aiterp.net/rpdata/api/internal/session"
|
||||||
"git.aiterp.net/rpdata/api/internal/store"
|
"git.aiterp.net/rpdata/api/internal/store"
|
||||||
"git.aiterp.net/rpdata/api/loader"
|
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
"git.aiterp.net/rpdata/api/model/change"
|
||||||
"git.aiterp.net/rpdata/api/model/file"
|
"git.aiterp.net/rpdata/api/model/file"
|
||||||
logModel "git.aiterp.net/rpdata/api/model/log"
|
logModel "git.aiterp.net/rpdata/api/model/log"
|
||||||
"git.aiterp.net/rpdata/api/resolver"
|
|
||||||
"git.aiterp.net/rpdata/api/schema"
|
|
||||||
graphql "github.com/graph-gophers/graphql-go"
|
graphql "github.com/graph-gophers/graphql-go"
|
||||||
"github.com/graph-gophers/graphql-go/relay"
|
"github.com/graph-gophers/graphql-go/relay"
|
||||||
)
|
)
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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")
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
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 {
|
||||||
|
Filter *struct {
|
||||||
|
Logged *bool
|
||||||
|
EventName *string
|
||||||
|
LocationName *string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channels resolves the channels query
|
||||||
|
func (r *QueryResolver) Channels(ctx context.Context, args *ChannelsArgs) ([]*types.ChannelResolver, error) {
|
||||||
|
var channels []channel.Channel
|
||||||
|
var err error
|
||||||
|
|
||||||
|
filter := args.Filter
|
||||||
|
if filter != nil {
|
||||||
|
channels, err = channel.List(filter.Logged, filter.EventName, filter.LocationName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
channels, err = channel.List(nil, nil, nil)
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package queries
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
|
"git.aiterp.net/rpdata/api/model/character"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CharactersArgs is args for characters query
|
||||||
|
type CharactersArgs struct {
|
||||||
|
Filter *struct {
|
||||||
|
IDs *[]string
|
||||||
|
Nicks *[]string
|
||||||
|
Names *[]string
|
||||||
|
Author *string
|
||||||
|
Search *string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Characters resolves the characters query
|
||||||
|
func (r *QueryResolver) Characters(ctx context.Context, args *CharactersArgs) ([]*types.CharacterResolver, error) {
|
||||||
|
var characters []character.Character
|
||||||
|
var err error
|
||||||
|
|
||||||
|
filter := args.Filter
|
||||||
|
if filter != nil {
|
||||||
|
var ids []string
|
||||||
|
var nicks []string
|
||||||
|
var names []string
|
||||||
|
|
||||||
|
if filter.IDs != nil {
|
||||||
|
ids = *filter.IDs
|
||||||
|
}
|
||||||
|
if filter.Nicks != nil {
|
||||||
|
nicks = *filter.Nicks
|
||||||
|
}
|
||||||
|
if filter.Names != nil {
|
||||||
|
names = *filter.Names
|
||||||
|
}
|
||||||
|
|
||||||
|
characters, err = character.ListFilter(ids, nicks, names, filter.Author, filter.Search)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
characters, err = character.List()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvers := make([]*types.CharacterResolver, 0, len(characters))
|
||||||
|
for _, character := range characters {
|
||||||
|
resolvers = append(resolvers, &types.CharacterResolver{C: character})
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvers, nil
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
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 {
|
||||||
|
Filter *struct {
|
||||||
|
Public *bool
|
||||||
|
MimeTypes *[]string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Files resolves the file query
|
||||||
|
func (r *QueryResolver) Files(ctx context.Context, args *FilesArgs) ([]*types.FileResolver, error) {
|
||||||
|
filter := args.Filter
|
||||||
|
user := session.FromContext(ctx).User()
|
||||||
|
|
||||||
|
author := ""
|
||||||
|
if user != nil {
|
||||||
|
author = user.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
mimeTypes := []string(nil)
|
||||||
|
if filter.MimeTypes != nil {
|
||||||
|
mimeTypes = *filter.MimeTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := file.List(author, filter.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
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
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) {
|
||||||
|
log, err := log.FindID(args.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.LogResolver{L: log}, nil
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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")
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package queries
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||||
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tags resolves the tags query
|
||||||
|
func (r *QueryResolver) Tags() ([]*types.TagResolver, error) {
|
||||||
|
tags, err := story.ListTags()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvers := make([]*types.TagResolver, len(tags))
|
||||||
|
for i, tag := range tags {
|
||||||
|
resolvers[i] = &types.TagResolver{T: tag}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvers, nil
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "git.aiterp.net/rpdata/api/model/channel"
|
||||||
|
|
||||||
|
// ChannelResolver for the Channel graphql type
|
||||||
|
type ChannelResolver struct{ C channel.Channel }
|
||||||
|
|
||||||
|
// Name resolves channel.name
|
||||||
|
func (r *ChannelResolver) Name() string {
|
||||||
|
return r.C.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logged resolves channel.logged
|
||||||
|
func (r *ChannelResolver) Logged() bool {
|
||||||
|
return r.C.Logged
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hub resolves channel.hub
|
||||||
|
func (r *ChannelResolver) Hub() bool {
|
||||||
|
return r.C.Hub
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventName resolves channel.eventName
|
||||||
|
func (r *ChannelResolver) EventName() *string {
|
||||||
|
if r.C.Event == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r.C.Event
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocationName resolves channel.locationName
|
||||||
|
func (r *ChannelResolver) LocationName() *string {
|
||||||
|
if r.C.Location == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r.C.Location
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChapterResolver for the Chapter graphql type
|
||||||
|
type ChapterResolver struct{ C story.Chapter }
|
||||||
|
|
||||||
|
// ID resolves Chapter.id
|
||||||
|
func (r *ChapterResolver) ID() string {
|
||||||
|
return r.C.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// StoryID resolves Chapter.storyId
|
||||||
|
func (r *ChapterResolver) StoryID() string {
|
||||||
|
return r.C.StoryID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Title resolves Chapter.title
|
||||||
|
func (r *ChapterResolver) Title() string {
|
||||||
|
return r.C.Title
|
||||||
|
}
|
||||||
|
|
||||||
|
// Author resolves Chapter.author
|
||||||
|
func (r *ChapterResolver) Author() string {
|
||||||
|
return r.C.Author
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source resolves Chapter.source
|
||||||
|
func (r *ChapterResolver) Source() string {
|
||||||
|
return r.C.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreatedDate resolves Chapter.createdDate
|
||||||
|
func (r *ChapterResolver) CreatedDate() string {
|
||||||
|
return r.C.CreatedDate.Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FictionalDate resolves Chapter.fictionalDate
|
||||||
|
func (r *ChapterResolver) FictionalDate() string {
|
||||||
|
return r.C.FictionalDate.Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditedDate resolves Chapter.editedDate
|
||||||
|
func (r *ChapterResolver) EditedDate() string {
|
||||||
|
return r.C.EditedDate.Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "git.aiterp.net/rpdata/api/model/character"
|
||||||
|
|
||||||
|
// CharacterResolver for the Character graphql type
|
||||||
|
type CharacterResolver struct{ C character.Character }
|
||||||
|
|
||||||
|
// ID is a property resolver
|
||||||
|
func (r *CharacterResolver) ID() string {
|
||||||
|
return r.C.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nick is a property resolver
|
||||||
|
func (r *CharacterResolver) Nick() *string {
|
||||||
|
if len(r.C.Nicks) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r.C.Nicks[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nicks is a property resolver
|
||||||
|
func (r *CharacterResolver) Nicks() []string {
|
||||||
|
return r.C.Nicks
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name is a property resolver
|
||||||
|
func (r *CharacterResolver) Name() string {
|
||||||
|
return r.C.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShortName is a property resolver
|
||||||
|
func (r *CharacterResolver) ShortName() string {
|
||||||
|
return r.C.ShortName
|
||||||
|
}
|
||||||
|
|
||||||
|
// Author is a property resolver
|
||||||
|
func (r *CharacterResolver) Author() string {
|
||||||
|
return r.C.Author
|
||||||
|
}
|
||||||
|
|
||||||
|
// Description is a property resolver
|
||||||
|
func (r *CharacterResolver) Description() string {
|
||||||
|
return r.C.Description
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/model/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FileResolver for the File graphql type
|
||||||
|
type FileResolver struct{ F file.File }
|
||||||
|
|
||||||
|
// ID resolves File.id
|
||||||
|
func (f *FileResolver) ID() string {
|
||||||
|
return f.F.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Author resolves File.author
|
||||||
|
func (f *FileResolver) Author() string {
|
||||||
|
return f.F.Author
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kind resolves File.kind
|
||||||
|
func (f *FileResolver) Kind() string {
|
||||||
|
return f.F.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time resolves File.time
|
||||||
|
func (f *FileResolver) Time() string {
|
||||||
|
return f.F.Time.Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public resolves File.public
|
||||||
|
func (f *FileResolver) Public() bool {
|
||||||
|
return f.F.Public
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name resolves File.name
|
||||||
|
func (f *FileResolver) Name() string {
|
||||||
|
return f.F.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// MimeType resolves File.mimeType
|
||||||
|
func (f *FileResolver) MimeType() string {
|
||||||
|
return f.F.MimeType
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size resolves File.size
|
||||||
|
func (f *FileResolver) Size() int32 {
|
||||||
|
return int32(f.F.Size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL resolves File.url
|
||||||
|
func (f *FileResolver) URL() *string {
|
||||||
|
if f.F.URL == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &f.F.URL
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/graphql/loader"
|
||||||
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LogResolver for the Log graphql type
|
||||||
|
type LogResolver struct{ L log.Log }
|
||||||
|
|
||||||
|
// ID resolves Log.id
|
||||||
|
func (r *LogResolver) ID() string {
|
||||||
|
return r.L.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShortID resolves Log.shortId
|
||||||
|
func (r *LogResolver) ShortID() string {
|
||||||
|
return r.L.ShortID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date resolves Log.date
|
||||||
|
func (r *LogResolver) Date() string {
|
||||||
|
return r.L.Date.Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChannelName resolves Log.channelName
|
||||||
|
func (r *LogResolver) ChannelName() string {
|
||||||
|
return r.L.Channel
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channel resolves Log.channe
|
||||||
|
func (r *LogResolver) Channel(ctx context.Context) (*ChannelResolver, error) {
|
||||||
|
loader := loader.FromContext(ctx)
|
||||||
|
if loader == nil {
|
||||||
|
return nil, errors.New("no loader")
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := loader.Channel("name", r.L.Channel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ChannelResolver{C: channel}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Title resolves Log.title
|
||||||
|
func (r *LogResolver) Title() string {
|
||||||
|
return r.L.Title
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event resolves Log.event
|
||||||
|
func (r *LogResolver) Event() string {
|
||||||
|
return r.L.Event
|
||||||
|
}
|
||||||
|
|
||||||
|
// Description resolves Log.description
|
||||||
|
func (r *LogResolver) Description() string {
|
||||||
|
return r.L.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open resolves Log.open
|
||||||
|
func (r *LogResolver) Open() bool {
|
||||||
|
return r.L.Open
|
||||||
|
}
|
||||||
|
|
||||||
|
// Characters resolves Log.characters
|
||||||
|
func (r *LogResolver) Characters(ctx context.Context) ([]*CharacterResolver, error) {
|
||||||
|
loader := loader.FromContext(ctx)
|
||||||
|
if loader == nil {
|
||||||
|
return nil, errors.New("no loader")
|
||||||
|
}
|
||||||
|
|
||||||
|
chars, err := loader.Characters("id", r.L.CharacterIDs...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvers := make([]*CharacterResolver, 0, len(chars))
|
||||||
|
for i := range chars {
|
||||||
|
if chars[i].ID == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvers = append(resolvers, &CharacterResolver{C: chars[i]})
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Posts resolves Log.posts
|
||||||
|
func (r *LogResolver) Posts(ctx context.Context, args *LogPostArgs) ([]*PostResolver, error) {
|
||||||
|
var kinds []string
|
||||||
|
if args.Kinds != nil {
|
||||||
|
kinds = *args.Kinds
|
||||||
|
}
|
||||||
|
|
||||||
|
posts, err := r.L.Posts(kinds...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvers := make([]*PostResolver, len(posts))
|
||||||
|
for i := range posts {
|
||||||
|
resolvers[i] = &PostResolver{posts[i]}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogPostArgs is an arg
|
||||||
|
type LogPostArgs struct {
|
||||||
|
Kinds *[]string
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PostResolver for the Post graphql type
|
||||||
|
type PostResolver struct{ P log.Post }
|
||||||
|
|
||||||
|
// ID resolves Post.id
|
||||||
|
func (r *PostResolver) ID() string {
|
||||||
|
return r.P.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogID resolves Post.logId
|
||||||
|
func (r *PostResolver) LogID() string {
|
||||||
|
return r.P.LogID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time resolves Post.time
|
||||||
|
func (r *PostResolver) Time() string {
|
||||||
|
return r.P.Time.Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kind resolves Post.logId
|
||||||
|
func (r *PostResolver) Kind() string {
|
||||||
|
return r.P.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nick resolves Post.nick
|
||||||
|
func (r *PostResolver) Nick() string {
|
||||||
|
return r.P.Nick
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text resolves Post.text
|
||||||
|
func (r *PostResolver) Text() string {
|
||||||
|
return r.P.Text
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position resolves Post.text
|
||||||
|
func (r *PostResolver) Position() int32 {
|
||||||
|
return int32(r.P.Position)
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "git.aiterp.net/rpdata/api/internal/session"
|
||||||
|
|
||||||
|
// SessionResolver resolves Session
|
||||||
|
type SessionResolver struct{ S *session.Session }
|
||||||
|
|
||||||
|
// User resolves Session.user
|
||||||
|
func (r *SessionResolver) User() *UserResolver {
|
||||||
|
user := r.S.User()
|
||||||
|
if user == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &UserResolver{U: user}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/model/story"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StoryResolver for the Story graphql type
|
||||||
|
type StoryResolver struct{ S story.Story }
|
||||||
|
|
||||||
|
// ID resolves Story.id
|
||||||
|
func (r *StoryResolver) ID() string {
|
||||||
|
return r.S.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Author resolves Story.author
|
||||||
|
func (r *StoryResolver) Author() string {
|
||||||
|
return r.S.Author
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name resolves Story.name
|
||||||
|
func (r *StoryResolver) Name() string {
|
||||||
|
return r.S.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Category resolves Story.category
|
||||||
|
func (r *StoryResolver) Category() string {
|
||||||
|
return r.S.Category
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open resolves Story.open
|
||||||
|
func (r *StoryResolver) Open() bool {
|
||||||
|
return r.S.Open
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listed resolves Story.listed
|
||||||
|
func (r *StoryResolver) Listed() bool {
|
||||||
|
return r.S.Listed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tags resolves Story.tags
|
||||||
|
func (r *StoryResolver) Tags() []*TagResolver {
|
||||||
|
resolvers := make([]*TagResolver, len(r.S.Tags))
|
||||||
|
for i, tag := range r.S.Tags {
|
||||||
|
resolvers[i] = &TagResolver{T: tag}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvers
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chapters resolves Story.chapters
|
||||||
|
func (r *StoryResolver) Chapters() ([]*ChapterResolver, error) {
|
||||||
|
chapters, err := r.S.Chapters()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvers := make([]*ChapterResolver, len(chapters))
|
||||||
|
for i, chapter := range chapters {
|
||||||
|
resolvers[i] = &ChapterResolver{C: chapter}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreatedDate resolves Story.createdDate
|
||||||
|
func (r *StoryResolver) CreatedDate() string {
|
||||||
|
return r.S.CreatedDate.Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FictionalDate resolves Story.fictionalDate
|
||||||
|
func (r *StoryResolver) FictionalDate() string {
|
||||||
|
return r.S.FictionalDate.Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdatedDate resolves Story.updatedDate
|
||||||
|
func (r *StoryResolver) UpdatedDate() string {
|
||||||
|
return r.S.UpdatedDate.Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "git.aiterp.net/rpdata/api/model/story"
|
||||||
|
|
||||||
|
// TagResolver for the Tag graphql type
|
||||||
|
type TagResolver struct{ T story.Tag }
|
||||||
|
|
||||||
|
// Kind resolves Tag.kind
|
||||||
|
func (r *TagResolver) Kind() string {
|
||||||
|
return r.T.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name resolves Tag.name
|
||||||
|
func (r *TagResolver) Name() string {
|
||||||
|
return r.T.Name
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package resolver
|
package types
|
||||||
|
|
||||||
import "git.aiterp.net/rpdata/api/internal/session"
|
import "git.aiterp.net/rpdata/api/internal/session"
|
||||||
|
|
||||||
@@ -3,44 +3,44 @@ type Query {
|
|||||||
# Find character by either an ID or a nick.
|
# Find character by either an ID or a nick.
|
||||||
character(id: String, nick: String): Character
|
character(id: String, nick: String): Character
|
||||||
|
|
||||||
# Find characters by either a list of ids, nicks or an author. Only one parameter at a time
|
# Find characters
|
||||||
characters(ids: [String!], nicks: [String!], author: String): [Character!]!
|
characters(filter: CharactersFilter): [Character!]!
|
||||||
|
|
||||||
|
|
||||||
# Find channel by name
|
# Find channel by name
|
||||||
channel(name: String!): Channel
|
channel(name: String!): Channel
|
||||||
|
|
||||||
# Find all channels. Specifying `logged: true` restricts the search to only logged.
|
# Find channels
|
||||||
channels(logged: Boolean): [Channel!]!
|
channels(filter: ChannelsFilter): [Channel!]!
|
||||||
|
|
||||||
|
|
||||||
# Find log by ID
|
# Find log by ID
|
||||||
log(id: String): Log
|
log(id: String!): Log
|
||||||
|
|
||||||
# Find logs by a list of IDs
|
# Find logs
|
||||||
logs(input: LogQueryInput): [LogHeader!]!
|
logs(filter: LogsFilter): [LogHeader!]!
|
||||||
|
|
||||||
|
|
||||||
# Find post by ID
|
# Find post by ID.
|
||||||
post(id: String!): Post
|
post(id: String!): Post
|
||||||
|
|
||||||
# Find posts by IDs. It's meant to allow other parts of the UI to link to a cluster of posts, e.g. for a room description for the
|
# Find posts by IDs. It's meant to allow other parts of the UI to link to a cluster of posts, e.g. for a room description for the
|
||||||
# Mapp should it ever become a thing.
|
# Mapp should it ever become a thing. This does not have a filter, since it's meant to be queried in the logs' response's selection set.
|
||||||
posts(ids: [String!]!): [Post!]!
|
posts(ids: [String!]!): [Post!]!
|
||||||
|
|
||||||
|
|
||||||
# Find file by ID
|
# Find file by ID
|
||||||
file(id: String!): File
|
file(id: String!): File
|
||||||
|
|
||||||
# Files get all available files. If includePublic is set, it will return public files as well
|
# Find files
|
||||||
files(includePublic: Boolean, mimeTypes: [String!]): [File!]!
|
files(filter: FilesFilter): [File!]!
|
||||||
|
|
||||||
|
|
||||||
# Find story by ID
|
# Find story by ID
|
||||||
story(id: String!): Story
|
story(id: String!): Story
|
||||||
|
|
||||||
# Find stories
|
# Find stories
|
||||||
stories(input: StoriesQueryInput!): [Story!]!
|
stories(filter: StoriesFilter): [Story!]!
|
||||||
|
|
||||||
|
|
||||||
# Find story chapter by ID
|
# Find story chapter by ID
|
||||||
@@ -16,6 +16,18 @@ type Channel {
|
|||||||
locationName: String
|
locationName: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Filters for the channels query
|
||||||
|
input ChannelsFilter {
|
||||||
|
# Filter to either logged or unlogged channels
|
||||||
|
logged: Boolean
|
||||||
|
|
||||||
|
# Filter by event name
|
||||||
|
eventName: String
|
||||||
|
|
||||||
|
# Filter by location name
|
||||||
|
locationName: String
|
||||||
|
}
|
||||||
|
|
||||||
input ChannelAddInput {
|
input ChannelAddInput {
|
||||||
# The channel's name
|
# The channel's name
|
||||||
name: String!
|
name: String!
|
||||||
@@ -22,6 +22,24 @@ type Character {
|
|||||||
description: String!
|
description: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Filter for characters query
|
||||||
|
input CharactersFilter {
|
||||||
|
# Filter by character IDs
|
||||||
|
ids: [String!]
|
||||||
|
|
||||||
|
# Filter by nicks
|
||||||
|
nicks: [String!]
|
||||||
|
|
||||||
|
# Filter by names
|
||||||
|
names: [String!]
|
||||||
|
|
||||||
|
# Filter by author
|
||||||
|
author: String
|
||||||
|
|
||||||
|
# Filter by text search matching against the character's description
|
||||||
|
search: String
|
||||||
|
}
|
||||||
|
|
||||||
# Input for adding characters
|
# Input for adding characters
|
||||||
input CharacterAddInput {
|
input CharacterAddInput {
|
||||||
# The primary IRC nick name to recognize this character by
|
# The primary IRC nick name to recognize this character by
|
||||||
@@ -29,6 +29,15 @@ type File {
|
|||||||
url: String
|
url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Filter for the files quiery.
|
||||||
|
input FilesFilter {
|
||||||
|
# If set, this will limit the results to either public or private files.
|
||||||
|
public: Boolean
|
||||||
|
|
||||||
|
# Limit the MIME types of the files.
|
||||||
|
mimeTypes: [String!]
|
||||||
|
}
|
||||||
|
|
||||||
# Input for editFile mutation
|
# Input for editFile mutation
|
||||||
input EditFileInput {
|
input EditFileInput {
|
||||||
# The file's unique ID
|
# The file's unique ID
|
||||||
@@ -36,8 +36,8 @@ type Log {
|
|||||||
posts(kinds:[String!]): [Post!]!
|
posts(kinds:[String!]): [Post!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
# Input for logs query
|
# Filter for logs query
|
||||||
input LogQueryInput {
|
input LogsFilter {
|
||||||
# Channels to limit results to (inclusive)
|
# Channels to limit results to (inclusive)
|
||||||
channels: [String!]
|
channels: [String!]
|
||||||
|
|
||||||
@@ -35,7 +35,8 @@ type Story {
|
|||||||
updatedDate: String!
|
updatedDate: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input StoriesQueryInput {
|
# Filter for stories query.
|
||||||
|
input StoriesFilter {
|
||||||
# What author to query for
|
# What author to query for
|
||||||
author: String
|
author: String
|
||||||
|
|
||||||
@@ -109,13 +109,20 @@ func FindName(name string) (Channel, error) {
|
|||||||
|
|
||||||
// List finds channels, if logged is true it will be limited to logged
|
// List finds channels, if logged is true it will be limited to logged
|
||||||
// channels
|
// channels
|
||||||
func List(logged bool) ([]Channel, error) {
|
func List(logged *bool, eventName *string, locationName *string) ([]Channel, error) {
|
||||||
query := bson.M{}
|
query := bson.M{}
|
||||||
if logged {
|
|
||||||
query["logged"] = true
|
if logged != nil {
|
||||||
|
query["logged"] = *logged
|
||||||
|
}
|
||||||
|
if eventName != nil {
|
||||||
|
query["eventName"] = *eventName
|
||||||
|
}
|
||||||
|
if locationName != nil {
|
||||||
|
query["locationName"] = *locationName
|
||||||
}
|
}
|
||||||
|
|
||||||
channels := make([]Channel, 0, 32)
|
channels := make([]Channel, 0, 128)
|
||||||
err := collection.Find(query).All(&channels)
|
err := collection.Find(query).All(&channels)
|
||||||
|
|
||||||
return channels, err
|
return channels, err
|
||||||
|
|||||||
@@ -154,6 +154,29 @@ func ListIDs(ids ...string) ([]Character, error) {
|
|||||||
return list(bson.M{"_id": bson.M{"$in": ids}})
|
return list(bson.M{"_id": bson.M{"$in": ids}})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListFilter lists all logs matching the filters.
|
||||||
|
func ListFilter(ids []string, nicks []string, names []string, author *string, search *string) ([]Character, error) {
|
||||||
|
query := bson.M{}
|
||||||
|
|
||||||
|
if len(ids) > 0 {
|
||||||
|
query["_id"] = bson.M{"$in": ids}
|
||||||
|
}
|
||||||
|
if len(nicks) > 0 {
|
||||||
|
query["nicks"] = bson.M{"$in": nicks}
|
||||||
|
}
|
||||||
|
if len(names) > 0 {
|
||||||
|
query["name"] = bson.M{"$in": names}
|
||||||
|
}
|
||||||
|
if author != nil {
|
||||||
|
query["author"] = *author
|
||||||
|
}
|
||||||
|
if search != nil {
|
||||||
|
query["$text"] = bson.M{"$search": *search}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list(query)
|
||||||
|
}
|
||||||
|
|
||||||
// New creates a Character and pushes it to the database. It does some validation
|
// New creates a Character and pushes it to the database. It does some validation
|
||||||
// on nick, name, shortName and author. Leave the shortname blank to have it be the
|
// on nick, name, shortName and author. Leave the shortname blank to have it be the
|
||||||
// first name.
|
// first name.
|
||||||
@@ -227,5 +250,11 @@ func init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("init common.characters:", err)
|
log.Fatalln("init common.characters:", err)
|
||||||
}
|
}
|
||||||
|
err = collection.EnsureIndex(mgo.Index{
|
||||||
|
Key: []string{"$text:description"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("init common.characters:", err)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-7
@@ -168,21 +168,22 @@ func FindName(kind string, name string, author string) (File, error) {
|
|||||||
// List lists files according to the standard lookup. By default it's just the author's own files,
|
// List lists files according to the standard lookup. By default it's just the author's own files,
|
||||||
// but if `public` is true it will alos include files made public by other authors. If `mimeTypes` contains
|
// but if `public` is true it will alos include files made public by other authors. If `mimeTypes` contains
|
||||||
// any, it will limit the results to that. If `author` is empty, it will only list public files
|
// any, it will limit the results to that. If `author` is empty, it will only list public files
|
||||||
func List(author string, public bool, mimeTypes []string) ([]File, error) {
|
func List(author string, public *bool, mimeTypes []string) ([]File, error) {
|
||||||
query := bson.M{}
|
query := bson.M{}
|
||||||
|
|
||||||
if author != "" {
|
if author != "" {
|
||||||
if public {
|
if public != nil {
|
||||||
query["$or"] = []bson.M{
|
if *public == false {
|
||||||
bson.M{"author": author},
|
query["author"] = author
|
||||||
bson.M{"public": true},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query["public"] = *public
|
||||||
} else {
|
} else {
|
||||||
query["author"] = author
|
query["author"] = author
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !public {
|
if public != nil && *public == false {
|
||||||
return nil, errors.New("No author specified, and public is unset")
|
return nil, errors.New("You cannot")
|
||||||
}
|
}
|
||||||
|
|
||||||
query["public"] = true
|
query["public"] = true
|
||||||
|
|||||||
@@ -1,191 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
|
||||||
"git.aiterp.net/rpdata/api/model/channel"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ChannelResolver for the Channel graphql type
|
|
||||||
type ChannelResolver struct{ C channel.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) (*ChannelResolver, error) {
|
|
||||||
channel, err := channel.FindName(args.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &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) ([]*ChannelResolver, error) {
|
|
||||||
channels, err := channel.List(args.Logged != nil && *args.Logged)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvers := make([]*ChannelResolver, len(channels))
|
|
||||||
for i := range channels {
|
|
||||||
resolvers[i] = &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) (*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 &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) (*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 &ChannelResolver{C: channel}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveChannel resolves the editChannel mutation
|
|
||||||
func (r *MutationResolver) RemoveChannel(ctx context.Context, args ChannelArgs) (*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 &ChannelResolver{C: channel}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name resolves channel.name
|
|
||||||
func (r *ChannelResolver) Name() string {
|
|
||||||
return r.C.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logged resolves channel.logged
|
|
||||||
func (r *ChannelResolver) Logged() bool {
|
|
||||||
return r.C.Logged
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hub resolves channel.hub
|
|
||||||
func (r *ChannelResolver) Hub() bool {
|
|
||||||
return r.C.Hub
|
|
||||||
}
|
|
||||||
|
|
||||||
// EventName resolves channel.eventName
|
|
||||||
func (r *ChannelResolver) EventName() *string {
|
|
||||||
if r.C.Event == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &r.C.Event
|
|
||||||
}
|
|
||||||
|
|
||||||
// LocationName resolves channel.locationName
|
|
||||||
func (r *ChannelResolver) LocationName() *string {
|
|
||||||
if r.C.Location == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &r.C.Location
|
|
||||||
}
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ChapterResolver for the Chapter graphql type
|
|
||||||
type ChapterResolver struct{ C story.Chapter }
|
|
||||||
|
|
||||||
// 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) (*ChapterResolver, error) {
|
|
||||||
chapter, err := story.FindChapterID(args.ID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &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) (*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 &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) (*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 &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) (*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 &ChapterResolver{C: chapter}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID resolves Chapter.id
|
|
||||||
func (r *ChapterResolver) ID() string {
|
|
||||||
return r.C.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// StoryID resolves Chapter.storyId
|
|
||||||
func (r *ChapterResolver) StoryID() string {
|
|
||||||
return r.C.StoryID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Title resolves Chapter.title
|
|
||||||
func (r *ChapterResolver) Title() string {
|
|
||||||
return r.C.Title
|
|
||||||
}
|
|
||||||
|
|
||||||
// Author resolves Chapter.author
|
|
||||||
func (r *ChapterResolver) Author() string {
|
|
||||||
return r.C.Author
|
|
||||||
}
|
|
||||||
|
|
||||||
// Source resolves Chapter.source
|
|
||||||
func (r *ChapterResolver) Source() string {
|
|
||||||
return r.C.Source
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreatedDate resolves Chapter.createdDate
|
|
||||||
func (r *ChapterResolver) CreatedDate() string {
|
|
||||||
return r.C.CreatedDate.Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FictionalDate resolves Chapter.fictionalDate
|
|
||||||
func (r *ChapterResolver) FictionalDate() string {
|
|
||||||
return r.C.FictionalDate.Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EditedDate resolves Chapter.editedDate
|
|
||||||
func (r *ChapterResolver) EditedDate() string {
|
|
||||||
return r.C.EditedDate.Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
|
||||||
"git.aiterp.net/rpdata/api/loader"
|
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
|
||||||
"git.aiterp.net/rpdata/api/model/character"
|
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CharacterResolver for the Character graphql type
|
|
||||||
type CharacterResolver struct{ C character.Character }
|
|
||||||
|
|
||||||
// CharacterArgs is an arg
|
|
||||||
type CharacterArgs struct {
|
|
||||||
ID *string
|
|
||||||
Nick *string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Character resolver
|
|
||||||
func (r *QueryResolver) Character(ctx context.Context, args *CharacterArgs) (*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 &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) ([]*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([]*CharacterResolver, 0, len(chars))
|
|
||||||
for i := range chars {
|
|
||||||
if chars[i].ID == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvers = append(resolvers, &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 }) (*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 &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 }) (*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 &CharacterResolver{C: character}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveCharacterNick resolves the removeCharacterNick mutation
|
|
||||||
func (r *MutationResolver) RemoveCharacterNick(ctx context.Context, args struct{ Input *CharacterNickInput }) (*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 &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 }) (*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 &CharacterResolver{C: character}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveCharacter resolves the removeCharacter mutation
|
|
||||||
func (r *MutationResolver) RemoveCharacter(ctx context.Context, args struct{ ID string }) (*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 &CharacterResolver{C: character}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID is a property resolver
|
|
||||||
func (r *CharacterResolver) ID() string {
|
|
||||||
return r.C.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nick is a property resolver
|
|
||||||
func (r *CharacterResolver) Nick() *string {
|
|
||||||
if len(r.C.Nicks) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &r.C.Nicks[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nicks is a property resolver
|
|
||||||
func (r *CharacterResolver) Nicks() []string {
|
|
||||||
return r.C.Nicks
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name is a property resolver
|
|
||||||
func (r *CharacterResolver) Name() string {
|
|
||||||
return r.C.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShortName is a property resolver
|
|
||||||
func (r *CharacterResolver) ShortName() string {
|
|
||||||
return r.C.ShortName
|
|
||||||
}
|
|
||||||
|
|
||||||
// Author is a property resolver
|
|
||||||
func (r *CharacterResolver) Author() string {
|
|
||||||
return r.C.Author
|
|
||||||
}
|
|
||||||
|
|
||||||
// Description is a property resolver
|
|
||||||
func (r *CharacterResolver) Description() string {
|
|
||||||
return r.C.Description
|
|
||||||
}
|
|
||||||
@@ -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")
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
|
||||||
"git.aiterp.net/rpdata/api/model/file"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FileResolver for the File graphql type
|
|
||||||
type FileResolver struct{ F file.File }
|
|
||||||
|
|
||||||
// FileArgs is an arg
|
|
||||||
type FileArgs struct {
|
|
||||||
ID string
|
|
||||||
}
|
|
||||||
|
|
||||||
// File implements the file query
|
|
||||||
func (r *QueryResolver) File(ctx context.Context, args *FileArgs) (*FileResolver, error) {
|
|
||||||
file, err := file.FindID(args.ID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &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) ([]*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([]*FileResolver, len(files))
|
|
||||||
for i := range files {
|
|
||||||
resolvers[i] = &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) (*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 &FileResolver{F: file}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFile resolves the removeFIle mutation
|
|
||||||
func (r *MutationResolver) RemoveFile(ctx context.Context, args *FileArgs) (*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 &FileResolver{F: file}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID resolves File.id
|
|
||||||
func (f *FileResolver) ID() string {
|
|
||||||
return f.F.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Author resolves File.author
|
|
||||||
func (f *FileResolver) Author() string {
|
|
||||||
return f.F.Author
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kind resolves File.kind
|
|
||||||
func (f *FileResolver) Kind() string {
|
|
||||||
return f.F.Kind
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time resolves File.time
|
|
||||||
func (f *FileResolver) Time() string {
|
|
||||||
return f.F.Time.Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public resolves File.public
|
|
||||||
func (f *FileResolver) Public() bool {
|
|
||||||
return f.F.Public
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name resolves File.name
|
|
||||||
func (f *FileResolver) Name() string {
|
|
||||||
return f.F.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// MimeType resolves File.mimeType
|
|
||||||
func (f *FileResolver) MimeType() string {
|
|
||||||
return f.F.MimeType
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size resolves File.size
|
|
||||||
func (f *FileResolver) Size() int32 {
|
|
||||||
return int32(f.F.Size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// URL resolves File.url
|
|
||||||
func (f *FileResolver) URL() *string {
|
|
||||||
if f.F.URL == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &f.F.URL
|
|
||||||
}
|
|
||||||
-338
@@ -1,338 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/loader"
|
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LogResolver for the Log graphql type
|
|
||||||
type LogResolver struct{ L log.Log }
|
|
||||||
|
|
||||||
// LogArgs is an arg
|
|
||||||
type LogArgs struct {
|
|
||||||
ID *string
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogPostArgs is an arg
|
|
||||||
type LogPostArgs struct {
|
|
||||||
Kinds *[]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log finds log
|
|
||||||
func (r *QueryResolver) Log(ctx context.Context, args *LogArgs) (*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 &LogResolver{L: l}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogQueryArgs is args for the logs query
|
|
||||||
type LogQueryArgs struct {
|
|
||||||
Input *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) ([]*LogResolver, error) {
|
|
||||||
var logs []log.Log
|
|
||||||
var err error
|
|
||||||
|
|
||||||
input := args.Input
|
|
||||||
|
|
||||||
if input != nil {
|
|
||||||
// Parse input
|
|
||||||
limit := 100
|
|
||||||
search := ""
|
|
||||||
|
|
||||||
if input.Search != nil {
|
|
||||||
search = *input.Search
|
|
||||||
limit = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
channels := []string(nil)
|
|
||||||
if input.Channels != nil {
|
|
||||||
channels = *input.Channels
|
|
||||||
limit = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
characters := []string(nil)
|
|
||||||
if input.Characters != nil {
|
|
||||||
characters = *input.Characters
|
|
||||||
limit = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
events := []string(nil)
|
|
||||||
if input.Events != nil {
|
|
||||||
events = *input.Events
|
|
||||||
limit = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.Limit != nil {
|
|
||||||
limit = int(*input.Limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
open := input.Open != nil && *input.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([]*LogResolver, len(logs))
|
|
||||||
for i := range logs {
|
|
||||||
resolvers[i] = &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) (*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 &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) (*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 &LogResolver{L: log}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveLog resolves the removeLog mutation
|
|
||||||
func (r *MutationResolver) RemoveLog(ctx context.Context, args *struct{ ID string }) (*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 &LogResolver{L: log}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID resolves Log.id
|
|
||||||
func (r *LogResolver) ID() string {
|
|
||||||
return r.L.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShortID resolves Log.shortId
|
|
||||||
func (r *LogResolver) ShortID() string {
|
|
||||||
return r.L.ShortID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Date resolves Log.date
|
|
||||||
func (r *LogResolver) Date() string {
|
|
||||||
return r.L.Date.Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChannelName resolves Log.channelName
|
|
||||||
func (r *LogResolver) ChannelName() string {
|
|
||||||
return r.L.Channel
|
|
||||||
}
|
|
||||||
|
|
||||||
// Channel resolves Log.channe
|
|
||||||
func (r *LogResolver) Channel(ctx context.Context) (*ChannelResolver, error) {
|
|
||||||
loader := loader.FromContext(ctx)
|
|
||||||
if loader == nil {
|
|
||||||
return nil, errors.New("no loader")
|
|
||||||
}
|
|
||||||
|
|
||||||
channel, err := loader.Channel("name", r.L.Channel)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ChannelResolver{C: channel}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Title resolves Log.title
|
|
||||||
func (r *LogResolver) Title() string {
|
|
||||||
return r.L.Title
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event resolves Log.event
|
|
||||||
func (r *LogResolver) Event() string {
|
|
||||||
return r.L.Event
|
|
||||||
}
|
|
||||||
|
|
||||||
// Description resolves Log.description
|
|
||||||
func (r *LogResolver) Description() string {
|
|
||||||
return r.L.Description
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open resolves Log.open
|
|
||||||
func (r *LogResolver) Open() bool {
|
|
||||||
return r.L.Open
|
|
||||||
}
|
|
||||||
|
|
||||||
// Characters resolves Log.characters
|
|
||||||
func (r *LogResolver) Characters(ctx context.Context) ([]*CharacterResolver, error) {
|
|
||||||
loader := loader.FromContext(ctx)
|
|
||||||
if loader == nil {
|
|
||||||
return nil, errors.New("no loader")
|
|
||||||
}
|
|
||||||
|
|
||||||
chars, err := loader.Characters("id", r.L.CharacterIDs...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvers := make([]*CharacterResolver, 0, len(chars))
|
|
||||||
for i := range chars {
|
|
||||||
if chars[i].ID == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvers = append(resolvers, &CharacterResolver{C: chars[i]})
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolvers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Posts resolves Log.posts
|
|
||||||
func (r *LogResolver) Posts(ctx context.Context, args *LogPostArgs) ([]*PostResolver, error) {
|
|
||||||
var kinds []string
|
|
||||||
if args.Kinds != nil {
|
|
||||||
kinds = *args.Kinds
|
|
||||||
}
|
|
||||||
|
|
||||||
posts, err := r.L.Posts(kinds...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvers := make([]*PostResolver, len(posts))
|
|
||||||
for i := range posts {
|
|
||||||
resolvers[i] = &PostResolver{posts[i]}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolvers, nil
|
|
||||||
}
|
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
|
||||||
"git.aiterp.net/rpdata/api/model/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PostResolver for the Post graphql type
|
|
||||||
type PostResolver struct{ P log.Post }
|
|
||||||
|
|
||||||
// PostArgs is an arg
|
|
||||||
type PostArgs struct {
|
|
||||||
ID string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Post implements the post query
|
|
||||||
func (r *QueryResolver) Post(ctx context.Context, args *PostArgs) (*PostResolver, error) {
|
|
||||||
post, err := log.FindPostID(args.ID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &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) ([]*PostResolver, error) {
|
|
||||||
posts, err := log.ListPostIDs(args.IDs...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvers := make([]*PostResolver, len(posts))
|
|
||||||
for i := range resolvers {
|
|
||||||
resolvers[i] = &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) (*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 &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) (*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 &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) (*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 &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) (*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 &PostResolver{P: post}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID resolves Post.id
|
|
||||||
func (r *PostResolver) ID() string {
|
|
||||||
return r.P.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogID resolves Post.logId
|
|
||||||
func (r *PostResolver) LogID() string {
|
|
||||||
return r.P.LogID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time resolves Post.time
|
|
||||||
func (r *PostResolver) Time() string {
|
|
||||||
return r.P.Time.Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kind resolves Post.logId
|
|
||||||
func (r *PostResolver) Kind() string {
|
|
||||||
return r.P.Kind
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nick resolves Post.nick
|
|
||||||
func (r *PostResolver) Nick() string {
|
|
||||||
return r.P.Nick
|
|
||||||
}
|
|
||||||
|
|
||||||
// Text resolves Post.text
|
|
||||||
func (r *PostResolver) Text() string {
|
|
||||||
return r.P.Text
|
|
||||||
}
|
|
||||||
|
|
||||||
// Position resolves Post.text
|
|
||||||
func (r *PostResolver) Position() int32 {
|
|
||||||
return int32(r.P.Position)
|
|
||||||
}
|
|
||||||
@@ -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{}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"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) (*SessionResolver, error) {
|
|
||||||
return &SessionResolver{S: session.FromContext(ctx)}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Login resolves mutation.login
|
|
||||||
func (r *MutationResolver) Login(ctx context.Context, args *LoginArgs) (*SessionResolver, error) {
|
|
||||||
session := session.FromContext(ctx)
|
|
||||||
|
|
||||||
err := session.Login(args.Username, args.Password)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &SessionResolver{S: session}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logout resolves mutation.logout
|
|
||||||
func (r *MutationResolver) Logout(ctx context.Context) (*SessionResolver, error) {
|
|
||||||
session := session.FromContext(ctx)
|
|
||||||
session.Logout()
|
|
||||||
|
|
||||||
return &SessionResolver{S: session}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SessionResolver resolves Session
|
|
||||||
type SessionResolver struct{ S *session.Session }
|
|
||||||
|
|
||||||
// User resolves Session.user
|
|
||||||
func (r *SessionResolver) User() *UserResolver {
|
|
||||||
user := r.S.User()
|
|
||||||
if user == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &UserResolver{U: user}
|
|
||||||
}
|
|
||||||
@@ -1,401 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/internal/session"
|
|
||||||
"git.aiterp.net/rpdata/api/model/change"
|
|
||||||
"git.aiterp.net/rpdata/api/model/story"
|
|
||||||
)
|
|
||||||
|
|
||||||
// StoryResolver for the Story graphql type
|
|
||||||
type StoryResolver struct{ S story.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) (*StoryResolver, error) {
|
|
||||||
story, err := story.FindID(args.ID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &StoryResolver{S: story}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StoriesArg is args for stories query
|
|
||||||
type StoriesArg struct {
|
|
||||||
Input *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) ([]*StoryResolver, error) {
|
|
||||||
input := args.Input
|
|
||||||
|
|
||||||
author := ""
|
|
||||||
if input.Author != nil {
|
|
||||||
author = *input.Author
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
earliest := time.Time{}
|
|
||||||
err := error(nil)
|
|
||||||
if input.EarliestFictionalDate != nil {
|
|
||||||
earliest, err = time.Parse(time.RFC3339Nano, *input.EarliestFictionalDate)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
latest := time.Time{}
|
|
||||||
if input.LatestFictionalDate != nil {
|
|
||||||
latest, err = time.Parse(time.RFC3339Nano, *input.LatestFictionalDate)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
limit := 30
|
|
||||||
if input.Limit != nil {
|
|
||||||
limit = int(*input.Limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
stories, err := story.List(author, tags, earliest, latest, limit)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvers := make([]*StoryResolver, len(stories))
|
|
||||||
for i, story := range stories {
|
|
||||||
resolvers[i] = &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) (*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 &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) (*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 &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) (*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 &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) (*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 &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) (*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 &StoryResolver{S: story}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ID resolves Story.id
|
|
||||||
func (r *StoryResolver) ID() string {
|
|
||||||
return r.S.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Author resolves Story.author
|
|
||||||
func (r *StoryResolver) Author() string {
|
|
||||||
return r.S.Author
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name resolves Story.name
|
|
||||||
func (r *StoryResolver) Name() string {
|
|
||||||
return r.S.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Category resolves Story.category
|
|
||||||
func (r *StoryResolver) Category() string {
|
|
||||||
return r.S.Category
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open resolves Story.open
|
|
||||||
func (r *StoryResolver) Open() bool {
|
|
||||||
return r.S.Open
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listed resolves Story.listed
|
|
||||||
func (r *StoryResolver) Listed() bool {
|
|
||||||
return r.S.Listed
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tags resolves Story.tags
|
|
||||||
func (r *StoryResolver) Tags() []*TagResolver {
|
|
||||||
resolvers := make([]*TagResolver, len(r.S.Tags))
|
|
||||||
for i, tag := range r.S.Tags {
|
|
||||||
resolvers[i] = &TagResolver{T: tag}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolvers
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chapters resolves Story.chapters
|
|
||||||
func (r *StoryResolver) Chapters() ([]*ChapterResolver, error) {
|
|
||||||
chapters, err := r.S.Chapters()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvers := make([]*ChapterResolver, len(chapters))
|
|
||||||
for i, chapter := range chapters {
|
|
||||||
resolvers[i] = &ChapterResolver{C: chapter}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolvers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreatedDate resolves Story.createdDate
|
|
||||||
func (r *StoryResolver) CreatedDate() string {
|
|
||||||
return r.S.CreatedDate.Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FictionalDate resolves Story.fictionalDate
|
|
||||||
func (r *StoryResolver) FictionalDate() string {
|
|
||||||
return r.S.FictionalDate.Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdatedDate resolves Story.updatedDate
|
|
||||||
func (r *StoryResolver) UpdatedDate() string {
|
|
||||||
return r.S.UpdatedDate.Format(time.RFC3339Nano)
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package resolver
|
|
||||||
|
|
||||||
import "git.aiterp.net/rpdata/api/model/story"
|
|
||||||
|
|
||||||
// TagResolver for the Tag graphql type
|
|
||||||
type TagResolver struct{ T story.Tag }
|
|
||||||
|
|
||||||
// TagInput resolves the TagInput input
|
|
||||||
type TagInput struct {
|
|
||||||
Kind string
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tags implements the tags query
|
|
||||||
func (r *QueryResolver) Tags() ([]*TagResolver, error) {
|
|
||||||
tags, err := story.ListTags()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvers := make([]*TagResolver, len(tags))
|
|
||||||
for i, tag := range tags {
|
|
||||||
resolvers[i] = &TagResolver{T: tag}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolvers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kind resolves Tag.kind
|
|
||||||
func (r *TagResolver) Kind() string {
|
|
||||||
return r.T.Kind
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name resolves Tag.name
|
|
||||||
func (r *TagResolver) Name() string {
|
|
||||||
return r.T.Name
|
|
||||||
}
|
|
||||||
+7
-2437
File diff suppressed because it is too large
Load Diff
Generated
+402
-32
@@ -46,6 +46,15 @@
|
|||||||
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==",
|
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"graphql": {
|
||||||
|
"version": "0.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/graphql/-/graphql-0.9.6.tgz",
|
||||||
|
"integrity": "sha1-UUQh6dIlwp38j9MFRZq65YgV7yw=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"iterall": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"invariant": {
|
"invariant": {
|
||||||
"version": "2.2.2",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
|
||||||
@@ -69,6 +78,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/async": {
|
||||||
|
"version": "2.0.49",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/async/-/async-2.0.49.tgz",
|
||||||
|
"integrity": "sha512-Benr3i5odUkvpFkOpzGqrltGdbSs+EVCkEBGXbuR7uT0VzhXKIkhem6PDzHdx5EonA+rfbB3QvP6aDOw5+zp5Q==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/graphql": {
|
||||||
|
"version": "0.12.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.12.6.tgz",
|
||||||
|
"integrity": "sha512-wXAVyLfkG1UMkKOdMijVWFky39+OD/41KftzqfX1Oejd0Gm6dOIKjCihSVECg6X7PHjftxXmfOKA/d1H79ZfvQ=="
|
||||||
|
},
|
||||||
|
"@types/zen-observable": {
|
||||||
|
"version": "0.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.5.4.tgz",
|
||||||
|
"integrity": "sha512-sW6xN96wUak4tgc89d0tbTg7QDGYhGv5hvQIS6h4mRCd8h2btiZ80loPU8cyLwsBbA4ZeQt0FjvUhJ4rNhdsGg=="
|
||||||
|
},
|
||||||
"abab": {
|
"abab": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
|
||||||
@@ -139,14 +164,14 @@
|
|||||||
"integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg=="
|
"integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg=="
|
||||||
},
|
},
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "5.5.2",
|
"version": "6.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz",
|
||||||
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
"integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"co": "^4.6.0",
|
"fast-deep-equal": "^2.0.1",
|
||||||
"fast-deep-equal": "^1.0.0",
|
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
"json-schema-traverse": "^0.3.0"
|
"json-schema-traverse": "^0.4.1",
|
||||||
|
"uri-js": "^4.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ajv-keywords": {
|
"ajv-keywords": {
|
||||||
@@ -293,6 +318,54 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"apollo-boost": {
|
||||||
|
"version": "0.1.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-boost/-/apollo-boost-0.1.10.tgz",
|
||||||
|
"integrity": "sha512-Bevaab5xqmOuxVmn8DV+7suoKP/ADX8NKzvfZhD3LgbP72MzpFXxulnP5/xSIBKn08mZvloeYGYdQkoxa7q3/Q==",
|
||||||
|
"requires": {
|
||||||
|
"apollo-cache": "^1.1.12",
|
||||||
|
"apollo-cache-inmemory": "^1.2.5",
|
||||||
|
"apollo-client": "^2.3.5",
|
||||||
|
"apollo-link": "^1.0.6",
|
||||||
|
"apollo-link-error": "^1.0.3",
|
||||||
|
"apollo-link-http": "^1.3.1",
|
||||||
|
"apollo-link-state": "^0.4.0",
|
||||||
|
"graphql-tag": "^2.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apollo-cache": {
|
||||||
|
"version": "1.1.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-cache/-/apollo-cache-1.1.12.tgz",
|
||||||
|
"integrity": "sha512-D0BPiHvJ6vIrXRh6P4mwlxuUOvODGuJxJq+zIjP8fADIqwjYtH3U3d/PY8dQ2fn4bDbvIAWBUkADBuJLpLIIpg==",
|
||||||
|
"requires": {
|
||||||
|
"apollo-utilities": "^1.0.16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apollo-cache-inmemory": {
|
||||||
|
"version": "1.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-cache-inmemory/-/apollo-cache-inmemory-1.2.5.tgz",
|
||||||
|
"integrity": "sha512-D9KIT4bq7ORm0BVXjSIxU09SvTUunWKxM63Lvr81hR83I7B7RRM3uFBDUV9VG8rlIGkD+1obBNlW2ycerFV8wQ==",
|
||||||
|
"requires": {
|
||||||
|
"apollo-cache": "^1.1.12",
|
||||||
|
"apollo-utilities": "^1.0.16",
|
||||||
|
"graphql-anywhere": "^4.1.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apollo-client": {
|
||||||
|
"version": "2.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-client/-/apollo-client-2.3.5.tgz",
|
||||||
|
"integrity": "sha512-FYg+Mj/HWSaO/ZllT5JnyHGUhkFhZ+UOdEvJd/DYKjxHNPal/d3jyXtG947r4IhUqPmmxXsAXNwvJGPieBKJGg==",
|
||||||
|
"requires": {
|
||||||
|
"@types/async": "2.0.49",
|
||||||
|
"@types/zen-observable": "^0.5.3",
|
||||||
|
"apollo-cache": "^1.1.12",
|
||||||
|
"apollo-link": "^1.0.0",
|
||||||
|
"apollo-link-dedup": "^1.0.0",
|
||||||
|
"apollo-utilities": "^1.0.16",
|
||||||
|
"symbol-observable": "^1.0.2",
|
||||||
|
"zen-observable": "^0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"apollo-codegen": {
|
"apollo-codegen": {
|
||||||
"version": "0.10.13",
|
"version": "0.10.13",
|
||||||
"resolved": "https://registry.npmjs.org/apollo-codegen/-/apollo-codegen-0.10.13.tgz",
|
"resolved": "https://registry.npmjs.org/apollo-codegen/-/apollo-codegen-0.10.13.tgz",
|
||||||
@@ -308,6 +381,77 @@
|
|||||||
"node-fetch": "^1.5.3",
|
"node-fetch": "^1.5.3",
|
||||||
"source-map-support": "^0.4.2",
|
"source-map-support": "^0.4.2",
|
||||||
"yargs": "^7.0.1"
|
"yargs": "^7.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"graphql": {
|
||||||
|
"version": "0.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/graphql/-/graphql-0.9.6.tgz",
|
||||||
|
"integrity": "sha1-UUQh6dIlwp38j9MFRZq65YgV7yw=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"iterall": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apollo-link": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-Uk/BC09dm61DZRDSu52nGq0nFhq7mcBPTjy5EEH1eunJndtCaNXQhQz/BjkI2NdrfGI+B+i5he6YSoRBhYizdw==",
|
||||||
|
"requires": {
|
||||||
|
"@types/graphql": "0.12.6",
|
||||||
|
"apollo-utilities": "^1.0.0",
|
||||||
|
"zen-observable-ts": "^0.8.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apollo-link-dedup": {
|
||||||
|
"version": "1.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-link-dedup/-/apollo-link-dedup-1.0.9.tgz",
|
||||||
|
"integrity": "sha512-RbuEKpmSHVMtoREMPh2wUFTeh65q+0XPVeqgaOP/rGEAfvLyOMvX0vT2nVaejMohoMxuUnfZwpldXaDFWnlVbg==",
|
||||||
|
"requires": {
|
||||||
|
"apollo-link": "^1.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apollo-link-error": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-4Vu/IUn6Kn6+Fthym4iuqypCKcLdwTg3MaCvtLdaLbt9X2hNCq3y8mv6vuWIlAY51X8wKhCgYghQSOs5R/embQ==",
|
||||||
|
"requires": {
|
||||||
|
"apollo-link": "^1.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apollo-link-http": {
|
||||||
|
"version": "1.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-link-http/-/apollo-link-http-1.5.4.tgz",
|
||||||
|
"integrity": "sha512-e9Ng3HfnW00Mh3TI6DhNRfozmzQOtKgdi+qUAsHBOEcTP0PTAmb+9XpeyEEOueLyO0GXhB92HUCIhzrWMXgwyg==",
|
||||||
|
"requires": {
|
||||||
|
"apollo-link": "^1.2.2",
|
||||||
|
"apollo-link-http-common": "^0.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apollo-link-http-common": {
|
||||||
|
"version": "0.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-link-http-common/-/apollo-link-http-common-0.2.4.tgz",
|
||||||
|
"integrity": "sha512-4j6o6WoXuSPen9xh4NBaX8/vL98X1xY2cYzUEK1F8SzvHe2oFONfxJBTekwU8hnvapcuq8Qh9Uct+gelu8T10g==",
|
||||||
|
"requires": {
|
||||||
|
"apollo-link": "^1.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apollo-link-state": {
|
||||||
|
"version": "0.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-link-state/-/apollo-link-state-0.4.1.tgz",
|
||||||
|
"integrity": "sha512-69/til4ENfl/Fvf7br2xSsLSBcxcXPbOHVNkzLLejvUZickl93HLO4/fO+uvoBi4dCYRgN17Zr8FwI41ueRx0g==",
|
||||||
|
"requires": {
|
||||||
|
"apollo-utilities": "^1.0.8",
|
||||||
|
"graphql-anywhere": "^4.1.0-alpha.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"apollo-utilities": {
|
||||||
|
"version": "1.0.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.16.tgz",
|
||||||
|
"integrity": "sha512-5oKnElKqkV920KRbitiyISLeG63tUGAyNdotg58bQSX9Omr+smoNDTIRMRLbyIdKOYLaw3LpDaRepOPqljj0NQ==",
|
||||||
|
"requires": {
|
||||||
|
"fast-json-stable-stringify": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"append-transform": {
|
"append-transform": {
|
||||||
@@ -3203,6 +3347,17 @@
|
|||||||
"text-table": "~0.2.0"
|
"text-table": "~0.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"ajv": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
||||||
|
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
||||||
|
"requires": {
|
||||||
|
"co": "^4.6.0",
|
||||||
|
"fast-deep-equal": "^1.0.0",
|
||||||
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
|
"json-schema-traverse": "^0.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||||
@@ -3231,6 +3386,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
|
||||||
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
|
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
|
||||||
},
|
},
|
||||||
|
"fast-deep-equal": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
||||||
|
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
||||||
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "3.12.0",
|
"version": "3.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
|
||||||
@@ -3240,6 +3400,11 @@
|
|||||||
"esprima": "^4.0.0"
|
"esprima": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"json-schema-traverse": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
||||||
|
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
||||||
|
},
|
||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||||
@@ -3799,9 +3964,9 @@
|
|||||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
||||||
},
|
},
|
||||||
"fast-deep-equal": {
|
"fast-deep-equal": {
|
||||||
"version": "1.1.0",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||||
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
|
||||||
},
|
},
|
||||||
"fast-json-stable-stringify": {
|
"fast-json-stable-stringify": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -4078,8 +4243,7 @@
|
|||||||
},
|
},
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@@ -4114,8 +4278,7 @@
|
|||||||
},
|
},
|
||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
@@ -4123,8 +4286,7 @@
|
|||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@@ -4227,8 +4389,7 @@
|
|||||||
},
|
},
|
||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@@ -4238,7 +4399,6 @@
|
|||||||
"is-fullwidth-code-point": {
|
"is-fullwidth-code-point": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -4350,8 +4510,7 @@
|
|||||||
},
|
},
|
||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@@ -4466,7 +4625,6 @@
|
|||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
@@ -4484,7 +4642,6 @@
|
|||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^2.0.0"
|
||||||
}
|
}
|
||||||
@@ -4671,12 +4828,19 @@
|
|||||||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
|
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
|
||||||
},
|
},
|
||||||
"graphql": {
|
"graphql": {
|
||||||
"version": "0.9.6",
|
"version": "0.13.2",
|
||||||
"resolved": "https://registry.npmjs.org/graphql/-/graphql-0.9.6.tgz",
|
"resolved": "https://registry.npmjs.org/graphql/-/graphql-0.13.2.tgz",
|
||||||
"integrity": "sha1-UUQh6dIlwp38j9MFRZq65YgV7yw=",
|
"integrity": "sha512-QZ5BL8ZO/B20VA8APauGBg3GyEgZ19eduvpLWoq5x7gMmWnHoy8rlQWPLmWgFvo1yNgjSEFMesmS4R6pPr7xog==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"iterall": "^1.0.0"
|
"iterall": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"graphql-anywhere": {
|
||||||
|
"version": "4.1.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/graphql-anywhere/-/graphql-anywhere-4.1.14.tgz",
|
||||||
|
"integrity": "sha512-Wy4h9FWwxgrDRP16wXApP/VmNKXXTvY8jZLDtgxwDuC8Z6LSVkeCDjQSCyNKdgktky104UCbIQ3x+et9bQupDA==",
|
||||||
|
"requires": {
|
||||||
|
"apollo-utilities": "^1.0.16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graphql-language-service-config": {
|
"graphql-language-service-config": {
|
||||||
@@ -4699,6 +4863,17 @@
|
|||||||
"graphql-language-service-parser": "0.0.10",
|
"graphql-language-service-parser": "0.0.10",
|
||||||
"graphql-language-service-types": "0.0.16",
|
"graphql-language-service-types": "0.0.16",
|
||||||
"graphql-language-service-utils": "0.0.10"
|
"graphql-language-service-utils": "0.0.10"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"graphql": {
|
||||||
|
"version": "0.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/graphql/-/graphql-0.9.6.tgz",
|
||||||
|
"integrity": "sha1-UUQh6dIlwp38j9MFRZq65YgV7yw=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"iterall": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graphql-language-service-parser": {
|
"graphql-language-service-parser": {
|
||||||
@@ -4717,6 +4892,17 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"graphql": "^0.9.6"
|
"graphql": "^0.9.6"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"graphql": {
|
||||||
|
"version": "0.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/graphql/-/graphql-0.9.6.tgz",
|
||||||
|
"integrity": "sha1-UUQh6dIlwp38j9MFRZq65YgV7yw=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"iterall": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graphql-language-service-utils": {
|
"graphql-language-service-utils": {
|
||||||
@@ -4727,8 +4913,24 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"graphql": "^0.9.6",
|
"graphql": "^0.9.6",
|
||||||
"graphql-language-service-types": "0.0.16"
|
"graphql-language-service-types": "0.0.16"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"graphql": {
|
||||||
|
"version": "0.9.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/graphql/-/graphql-0.9.6.tgz",
|
||||||
|
"integrity": "sha1-UUQh6dIlwp38j9MFRZq65YgV7yw=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"iterall": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"graphql-tag": {
|
||||||
|
"version": "2.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.9.2.tgz",
|
||||||
|
"integrity": "sha512-qnNmof9pAqj/LUzs3lStP0Gw1qhdVCUS7Ab7+SUB6KD5aX1uqxWQRwMnOGTkhKuLvLNIs1TvNz+iS9kUGl1MhA=="
|
||||||
|
},
|
||||||
"growly": {
|
"growly": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
|
||||||
@@ -4816,6 +5018,29 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"ajv": "^5.1.0",
|
"ajv": "^5.1.0",
|
||||||
"har-schema": "^2.0.0"
|
"har-schema": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
||||||
|
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
||||||
|
"requires": {
|
||||||
|
"co": "^4.6.0",
|
||||||
|
"fast-deep-equal": "^1.0.0",
|
||||||
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
|
"json-schema-traverse": "^0.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fast-deep-equal": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
||||||
|
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
||||||
|
},
|
||||||
|
"json-schema-traverse": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
||||||
|
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"has": {
|
"has": {
|
||||||
@@ -4901,6 +5126,28 @@
|
|||||||
"upper-case": "^1.1.3"
|
"upper-case": "^1.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"history": {
|
||||||
|
"version": "4.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz",
|
||||||
|
"integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==",
|
||||||
|
"requires": {
|
||||||
|
"invariant": "^2.2.1",
|
||||||
|
"loose-envify": "^1.2.0",
|
||||||
|
"resolve-pathname": "^2.2.0",
|
||||||
|
"value-equal": "^0.4.0",
|
||||||
|
"warning": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"warning": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"hmac-drbg": {
|
"hmac-drbg": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||||
@@ -4911,6 +5158,11 @@
|
|||||||
"minimalistic-crypto-utils": "^1.0.1"
|
"minimalistic-crypto-utils": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hoist-non-react-statics": {
|
||||||
|
"version": "2.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
|
||||||
|
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
|
||||||
|
},
|
||||||
"home-or-tmp": {
|
"home-or-tmp": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
|
||||||
@@ -5867,8 +6119,7 @@
|
|||||||
"iterall": {
|
"iterall": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz",
|
||||||
"integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==",
|
"integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"version": "20.0.4",
|
"version": "20.0.4",
|
||||||
@@ -6499,9 +6750,9 @@
|
|||||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "0.3.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||||
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||||
},
|
},
|
||||||
"json-stable-stringify": {
|
"json-stable-stringify": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@@ -9100,6 +9351,18 @@
|
|||||||
"prop-types": "^15.6.0"
|
"prop-types": "^15.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-apollo": {
|
||||||
|
"version": "2.1.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-apollo/-/react-apollo-2.1.9.tgz",
|
||||||
|
"integrity": "sha512-o6otpfh/neSzNjaq2x1GL9+aFz13pxQ0si4h2XpE7ON1lXD24YwpdFF277s8h1KFSVRvZmpzLmrg9OyOU9mo+w==",
|
||||||
|
"requires": {
|
||||||
|
"fbjs": "^0.8.16",
|
||||||
|
"hoist-non-react-statics": "^2.5.0",
|
||||||
|
"invariant": "^2.2.2",
|
||||||
|
"lodash": "^4.17.10",
|
||||||
|
"prop-types": "^15.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-dev-utils": {
|
"react-dev-utils": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-5.0.1.tgz",
|
||||||
@@ -9141,6 +9404,33 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-4.0.0.tgz",
|
||||||
"integrity": "sha512-FlsPxavEyMuR6TjVbSSywovXSEyOg6ZDj5+Z8nbsRl9EkOzAhEIcS+GLoQDC5fz/t9suhUXWmUrOBrgeUvrMxw=="
|
"integrity": "sha512-FlsPxavEyMuR6TjVbSSywovXSEyOg6ZDj5+Z8nbsRl9EkOzAhEIcS+GLoQDC5fz/t9suhUXWmUrOBrgeUvrMxw=="
|
||||||
},
|
},
|
||||||
|
"react-router": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==",
|
||||||
|
"requires": {
|
||||||
|
"history": "^4.7.2",
|
||||||
|
"hoist-non-react-statics": "^2.5.0",
|
||||||
|
"invariant": "^2.2.4",
|
||||||
|
"loose-envify": "^1.3.1",
|
||||||
|
"path-to-regexp": "^1.7.0",
|
||||||
|
"prop-types": "^15.6.1",
|
||||||
|
"warning": "^4.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-router-dom": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==",
|
||||||
|
"requires": {
|
||||||
|
"history": "^4.7.2",
|
||||||
|
"invariant": "^2.2.4",
|
||||||
|
"loose-envify": "^1.3.1",
|
||||||
|
"prop-types": "^15.6.1",
|
||||||
|
"react-router": "^4.3.1",
|
||||||
|
"warning": "^4.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-scripts": {
|
"react-scripts": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-1.1.4.tgz",
|
||||||
@@ -9563,6 +9853,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
|
||||||
"integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY="
|
"integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY="
|
||||||
},
|
},
|
||||||
|
"resolve-pathname": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg=="
|
||||||
|
},
|
||||||
"resolve-url": {
|
"resolve-url": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
||||||
@@ -9700,6 +9995,29 @@
|
|||||||
"integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
|
"integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ajv": "^5.0.0"
|
"ajv": "^5.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
||||||
|
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
||||||
|
"requires": {
|
||||||
|
"co": "^4.6.0",
|
||||||
|
"fast-deep-equal": "^1.0.0",
|
||||||
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
|
"json-schema-traverse": "^0.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fast-deep-equal": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
||||||
|
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
||||||
|
},
|
||||||
|
"json-schema-traverse": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
||||||
|
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"select-hose": {
|
"select-hose": {
|
||||||
@@ -10375,6 +10693,11 @@
|
|||||||
"upper-case": "^1.1.1"
|
"upper-case": "^1.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"symbol-observable": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
|
||||||
|
},
|
||||||
"symbol-tree": {
|
"symbol-tree": {
|
||||||
"version": "3.2.2",
|
"version": "3.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
|
||||||
@@ -10959,6 +11282,11 @@
|
|||||||
"spdx-expression-parse": "^3.0.0"
|
"spdx-expression-parse": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"value-equal": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw=="
|
||||||
|
},
|
||||||
"vary": {
|
"vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
@@ -10995,6 +11323,14 @@
|
|||||||
"makeerror": "1.0.x"
|
"makeerror": "1.0.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"warning": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-rAVtTNZw+cQPjvGp1ox0XC5Q2IBFyqoqh+QII4J/oguyu83Bax1apbo2eqB8bHRS+fqYUBagys6lqUoVwKSmXQ==",
|
||||||
|
"requires": {
|
||||||
|
"loose-envify": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"watch": {
|
"watch": {
|
||||||
"version": "0.10.0",
|
"version": "0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz",
|
||||||
@@ -11052,6 +11388,17 @@
|
|||||||
"yargs": "^8.0.2"
|
"yargs": "^8.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"ajv": {
|
||||||
|
"version": "5.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
||||||
|
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
|
||||||
|
"requires": {
|
||||||
|
"co": "^4.6.0",
|
||||||
|
"fast-deep-equal": "^1.0.0",
|
||||||
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
|
"json-schema-traverse": "^0.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ajv-keywords": {
|
"ajv-keywords": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
|
||||||
@@ -11084,6 +11431,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fast-deep-equal": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
||||||
|
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
||||||
|
},
|
||||||
"has-flag": {
|
"has-flag": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
|
||||||
@@ -11097,6 +11449,11 @@
|
|||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"json-schema-traverse": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
|
||||||
|
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
|
||||||
|
},
|
||||||
"load-json-file": {
|
"load-json-file": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
|
||||||
@@ -11661,6 +12018,19 @@
|
|||||||
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
|
"integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"zen-observable": {
|
||||||
|
"version": "0.8.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.8.tgz",
|
||||||
|
"integrity": "sha512-HnhhyNnwTFzS48nihkCZIJGsWGFcYUz+XPDlPK5W84Ifji8SksC6m7sQWOf8zdCGhzQ4tDYuMYGu5B0N1dXTtg=="
|
||||||
|
},
|
||||||
|
"zen-observable-ts": {
|
||||||
|
"version": "0.8.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.9.tgz",
|
||||||
|
"integrity": "sha512-KJz2O8FxbAdAU5CSc8qZ1K2WYEJb1HxS6XDRF+hOJ1rOYcg6eTMmS9xYHCXzqZZzKw6BbXWyF4UpwSsBQnHJeA==",
|
||||||
|
"requires": {
|
||||||
|
"zen-observable": "^0.8.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,16 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"ajv": "^6.5.2",
|
||||||
|
"apollo-boost": "^0.1.10",
|
||||||
|
"graphql": "^0.13.2",
|
||||||
|
"graphql-tag": "^2.9.2",
|
||||||
|
"pluralize": "^7.0.0",
|
||||||
"react": "^16.4.1",
|
"react": "^16.4.1",
|
||||||
|
"react-apollo": "^2.1.9",
|
||||||
"react-dom": "^16.4.1",
|
"react-dom": "^16.4.1",
|
||||||
|
"react-router": "^4.3.1",
|
||||||
|
"react-router-dom": "^4.3.1",
|
||||||
"react-scripts": "1.1.4"
|
"react-scripts": "1.1.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -15,5 +23,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playlyfe/gql": "^2.6.0"
|
"@playlyfe/gql": "^2.6.0"
|
||||||
|
},
|
||||||
|
"proxy": {
|
||||||
|
"/graphql": {
|
||||||
|
"target": "http://127.0.0.1:17000"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
@@ -1,3 +0,0 @@
|
|||||||
.App {
|
|
||||||
|
|
||||||
}
|
|
||||||
+12
-3
@@ -1,14 +1,23 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react'
|
||||||
import './App.css';
|
import { Route, Router, Redirect, Switch } from "react-router-dom";
|
||||||
|
|
||||||
|
import StoryRoot from './routes/story/StoryRoot';
|
||||||
|
import LogsIndex from './routes/logs/LogsIndex';
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<p>Hi</p>
|
<Switch>
|
||||||
|
<Redirect exact path="/" to="/story/" />
|
||||||
|
<Route path="/story/" component={StoryRoot}/>
|
||||||
|
<Route path="/logs/" component={LogsIndex}/>
|
||||||
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
||||||
|
/* See ./common/Menu.js to change the top navbar */
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { ApolloClient } from "apollo-client"
|
||||||
|
import { HttpLink } from "apollo-link-http"
|
||||||
|
import { InMemoryCache } from "apollo-cache-inmemory"
|
||||||
|
|
||||||
|
const client = new ApolloClient({
|
||||||
|
link: new HttpLink({
|
||||||
|
uri: "/graphql"
|
||||||
|
}),
|
||||||
|
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
})
|
||||||
|
|
||||||
|
export default client
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/* /story/ */
|
||||||
|
.theme-story .color-menu {
|
||||||
|
color: #789;
|
||||||
|
}
|
||||||
|
.theme-story .MenuLink.selected {
|
||||||
|
background-color: rgba(34, 187, 255, 0.125);
|
||||||
|
}
|
||||||
|
.theme-story .MenuLink:hover, .theme-story .Menu > .head-menu > a:hover {
|
||||||
|
background-color: rgba(34, 187, 255, 0.25);
|
||||||
|
}
|
||||||
|
.theme-story .color-primary {
|
||||||
|
color: #1CF;
|
||||||
|
}
|
||||||
|
.theme-story .color-text {
|
||||||
|
color: #ABC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* /logs/ */
|
||||||
|
.theme-logs .color-menu {
|
||||||
|
color: #998;
|
||||||
|
}
|
||||||
|
.theme-logs .MenuLink.selected {
|
||||||
|
background-color: rgba(255, 187, 34, 0.125);
|
||||||
|
}
|
||||||
|
.theme-logs .MenuLink:hover, .theme-logs .Menu > .head-menu > a:hover {
|
||||||
|
background-color: rgba(255, 187, 34, 0.25);
|
||||||
|
}
|
||||||
|
.theme-logs .color-primary {
|
||||||
|
color: #FC1;
|
||||||
|
}
|
||||||
|
.theme-logs .color-text {
|
||||||
|
color: #CCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* /data/ */
|
||||||
|
.theme-data .color-menu {
|
||||||
|
color: #898;
|
||||||
|
}
|
||||||
|
.theme-data .MenuLink.selected {
|
||||||
|
background-color: rgba(35, 255, 128, 0.125);
|
||||||
|
}
|
||||||
|
.theme-data .MenuLink:hover, .theme-data .Menu > .head-menu > a:hover {
|
||||||
|
background-color: rgba(35, 255, 128, 0.25);
|
||||||
|
}
|
||||||
|
.theme-data .color-primary {
|
||||||
|
color: #1F8;
|
||||||
|
}
|
||||||
|
.theme-data .color-text {
|
||||||
|
color: #ACB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tag colors */
|
||||||
|
.color-tag-event {
|
||||||
|
color: #B77;
|
||||||
|
}
|
||||||
|
.color-tag-location {
|
||||||
|
color: #7B7;
|
||||||
|
}
|
||||||
|
.color-tag-organization {
|
||||||
|
color: #B7B;
|
||||||
|
}
|
||||||
|
.color-tag-series {
|
||||||
|
color: #BB7;
|
||||||
|
}
|
||||||
|
.color-tag-character {
|
||||||
|
color: #37B;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Danger */
|
||||||
|
.color-danger {
|
||||||
|
color: #FA3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuLink:hover, .MenuLink:hover .text, .Menu > .head-menu > a:hover {
|
||||||
|
color: #EEE !important;
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import './css/Background.css';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Background renders a full-size image that detects whether the source is
|
||||||
|
* landscape or portrait. It's a react-ification of AiteStory's background.
|
||||||
|
*/
|
||||||
|
export default class Background extends Component {
|
||||||
|
/**
|
||||||
|
* @param {HTMLImageElement} img
|
||||||
|
*/
|
||||||
|
onRef(img) {
|
||||||
|
if (img == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (img.complete && typeof(img.naturalHeight) !== 'undefined' && img.naturalHeight !== 0) {
|
||||||
|
const width = img.clientWidth
|
||||||
|
const height = img.clientHeight
|
||||||
|
|
||||||
|
if(width > (height * 1.50)) {
|
||||||
|
img.className += ' landscape'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
img.onload = function () {
|
||||||
|
const width = img.clientWidth
|
||||||
|
const height = img.clientHeight
|
||||||
|
|
||||||
|
if(width > (height * 1.50)) {
|
||||||
|
img.className += ' landscape'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const src = this.props.src || "/assets/images/bg.png"
|
||||||
|
const opacity = this.props.opacity || 0.25
|
||||||
|
|
||||||
|
return <img style={{filter: `brightness(${(Number(opacity)) * 100}%)`}} ref={this.onRef.bind(this)} className="Background" src={src} />
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
import './css/Menu.css';
|
||||||
|
|
||||||
|
export default class Menu extends Component {
|
||||||
|
render() {
|
||||||
|
const { children } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav className="Menu">
|
||||||
|
<h1 className="color-primary">Aite RP</h1>
|
||||||
|
<div className="head-menu">
|
||||||
|
<HeadMenuLink to="/story/">Story</HeadMenuLink>
|
||||||
|
<HeadMenuLink to="/logs/">Logs</HeadMenuLink>
|
||||||
|
</div>
|
||||||
|
<div className="content">
|
||||||
|
{ children }
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MenuLink({ icon, children, tagType, to, onClick }) {
|
||||||
|
const isSelected = window.location.pathname === to
|
||||||
|
const className = isSelected ? "selected" : "not-selected"
|
||||||
|
const textClass = isSelected ? "color-primary" : `color-tag-${tagType||"none"}`
|
||||||
|
|
||||||
|
const body = (
|
||||||
|
<div className={`MenuLink color-menu ${className}`} onClick={onClick}>
|
||||||
|
<div className="icon color-primary">{icon}</div>
|
||||||
|
<div className={`text ${textClass}`}>{children}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
if (to == null) {
|
||||||
|
return body
|
||||||
|
} else {
|
||||||
|
return <Link to={to}>{body}</Link>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MenuGap() {
|
||||||
|
return <div className="MenuGap"></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MenuHeader({children}) {
|
||||||
|
return <div className="MenuHeader color-menu">{children}</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HeadMenuLink({to, children}) {
|
||||||
|
const className = (window.location.pathname.startsWith(to) ? "color-primary" : "color-menu")
|
||||||
|
|
||||||
|
return <Link className={className} to={to}>{children}</Link>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MenuBlurb({children}) {
|
||||||
|
return <div className="MenuBlurb">{children}</div>
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
img.Background {
|
||||||
|
/* Set rules to fill background */
|
||||||
|
width: 100%;
|
||||||
|
/* Set up proportionate scaling */
|
||||||
|
min-height: 100%;
|
||||||
|
height: auto;
|
||||||
|
/* Set up positioning */
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: -1;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.Background.landscape {
|
||||||
|
/* Set rules to fill background */
|
||||||
|
height: 100%;
|
||||||
|
/* Set up proportionate scaling */
|
||||||
|
min-width: 100%;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
.Menu {
|
||||||
|
position: sticky;
|
||||||
|
width: 28ch;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Menu > .head-menu {
|
||||||
|
padding: 0 2ch;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Menu > .head-menu > a {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.25em 1ch;
|
||||||
|
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Menu > h1 {
|
||||||
|
padding: 1em 0 0em 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 2.5em;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Menu > .content {
|
||||||
|
margin-top: 1em;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuLink {
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 0.5ch;
|
||||||
|
font-size: 1.1em;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuLink .icon {
|
||||||
|
display: inline-block;
|
||||||
|
width: 3ch;
|
||||||
|
padding: 0.15em 0.125em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuLink .text {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuGap {
|
||||||
|
padding: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuHeader {
|
||||||
|
opacity: 0.5;
|
||||||
|
user-select: none;
|
||||||
|
padding: 0.125em 1.5ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MenuBlurb {
|
||||||
|
opacity: 0.5;
|
||||||
|
padding: 0.25em 1.5ch;
|
||||||
|
}
|
||||||
@@ -2,4 +2,10 @@ body {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user