Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7d5059d60 | ||
|
|
9fbdc767ad | ||
|
|
daeaaf5fa9 | ||
|
|
d3277c7476 | ||
|
|
90681c67b0 | ||
|
|
bebd99833b | ||
|
|
34f86d5037 | ||
|
|
8a85313762 | ||
|
|
017e68eae7 | ||
|
|
1955ad0517 | ||
|
|
34ba5d5d3a | ||
|
|
8c8a251080 | ||
|
|
73fe125870 | ||
|
|
04ec85aadf | ||
|
|
59233ee549 | ||
|
|
7aa0de9135 | ||
|
|
6dfbee7ff2 | ||
|
|
8a07c2ffdb | ||
|
|
0e9536b0a8 | ||
|
|
b8e5ed5813 | ||
|
|
2317f66920 | ||
|
|
fc488b938d | ||
|
|
ceb2617571 | ||
|
|
aeb5b26627 | ||
|
|
6aafc67790 | ||
|
|
c6f8fd9faa | ||
|
|
efa98b80cc | ||
|
|
707dcb43eb | ||
|
|
9bcc28a0ea | ||
|
|
2fceaa62ed | ||
|
|
86125c7ce9 | ||
|
|
bb28795cd5 | ||
|
|
815f30597e | ||
|
|
cd1f122502 | ||
|
|
0e0d802a32 | ||
|
|
3c42043ab6 | ||
|
|
8388ee2446 | ||
|
|
260c2e7f76 | ||
|
|
a4034b0faa | ||
|
|
c3a6798050 | ||
|
|
2ab933149e | ||
|
|
07b94b3cab | ||
|
|
79171bf9a2 | ||
|
|
bac57bc378 | ||
|
|
875dac9ecb | ||
|
|
0768cfd0bd | ||
|
|
2b05d90f4a | ||
|
|
0444911e73 | ||
|
|
1be4088a8f | ||
|
|
9978d7380b | ||
|
|
2e5162a29b | ||
|
|
dac0060155 | ||
|
|
9d7fd498a9 | ||
|
|
e0af2685ee | ||
|
|
3184b60310 | ||
|
|
675c09ef04 | ||
|
|
9707320960 | ||
|
|
20e53b4f5e | ||
|
|
8bb4dea358 | ||
|
|
75b2382f09 | ||
|
|
1ca25eff8e | ||
|
|
bf10ed1fe3 | ||
|
|
54136be912 | ||
|
|
228c2bfeb4 | ||
|
|
2f98be5747 | ||
|
|
2a40f97282 | ||
|
|
e5b4184106 | ||
|
|
c348a90b70 | ||
|
|
132cf28f0f | ||
|
|
d5df624188 | ||
|
|
ca98648274 | ||
|
|
4642a8abec | ||
|
|
0ec923d686 | ||
|
|
388d5378e7 | ||
|
|
67e9e8f1e6 | ||
|
|
06bc7e5a1b | ||
|
|
237190e498 | ||
|
|
b9f0fef966 | ||
|
|
ba1c1e0a4b | ||
|
|
18e77b8205 | ||
|
|
d8871259a1 | ||
|
|
26d7e36631 | ||
|
|
51489ed901 | ||
|
|
ed3e384d55 |
+4
-4
@@ -6,16 +6,16 @@ pipeline:
|
||||
docker-release:
|
||||
image: plugins/docker
|
||||
repo: vmaple/rpdata
|
||||
tags: latest
|
||||
auto_tag: true
|
||||
secrets: [ docker_username, docker_password ]
|
||||
when:
|
||||
event: tag
|
||||
ref: refs/tags/*
|
||||
docker-dev:
|
||||
docker-release-latest:
|
||||
image: plugins/docker
|
||||
repo: vmaple/rpdata
|
||||
tags: trunk
|
||||
tags: latest
|
||||
secrets: [ docker_username, docker_password ]
|
||||
when:
|
||||
event: push
|
||||
event: tag
|
||||
ref: refs/tags/*
|
||||
+8
-2
@@ -1,7 +1,13 @@
|
||||
vendor
|
||||
schema/bindata.go
|
||||
graphql/schema/bindata.go
|
||||
config.json
|
||||
api
|
||||
debug
|
||||
build
|
||||
.vscode
|
||||
rpdata-graphiql
|
||||
rpdata-*
|
||||
!rpdata-*/
|
||||
.vscode
|
||||
|
||||
generated.gql
|
||||
generated.go
|
||||
+9
-22
@@ -1,41 +1,29 @@
|
||||
## 1. Server
|
||||
## 1. Build Server
|
||||
# Use Go 1.10
|
||||
FROM golang:1.10 AS build-server
|
||||
FROM golang:1.11 AS build-server
|
||||
|
||||
# Load repository into docker
|
||||
WORKDIR /go/src/git.aiterp.net/rpdata/api/
|
||||
COPY . .
|
||||
RUN rm -rf ./vendor
|
||||
|
||||
# Load build tools and dependencies
|
||||
RUN go get -u github.com/golang/dep/cmd/dep
|
||||
RUN go get -u github.com/vektah/gorunpkg
|
||||
RUN go get -u github.com/jteeuwen/go-bindata/...
|
||||
RUN dep ensure
|
||||
RUN go generate ./...
|
||||
|
||||
# Build server and tools (CGO disabled to make them 100% static)
|
||||
ENV CGO_ENABLED 0
|
||||
RUN go build -a -installsuffix cgo -ldflags="-s -w" -o /binaries/rpdata-graphiql ./cmd/rpdata-graphiql
|
||||
RUN go build -a -installsuffix cgo -ldflags="-s -w" -o /binaries/rpdata-server ./cmd/rpdata-server
|
||||
RUN go build -a -installsuffix cgo -ldflags="-s -w" -o /binaries/rpdata-lb2charimport ./cmd/rpdata-lb2charimport
|
||||
RUN go build -a -installsuffix cgo -ldflags="-s -w" -o /binaries/rpdata-lb2logimport ./cmd/rpdata-lb2logimport
|
||||
RUN go build -a -installsuffix cgo -ldflags="-s -w" -o /binaries/rpdata-wikifileimport ./cmd/rpdata-wikifileimport
|
||||
# TODO: RUN go build -a -installsuffix cgo -ldflags="-s -w" -o /binaries/rpdata-wikifileimport ./cmd/rpdata-wikifileimport
|
||||
RUN go build -a -installsuffix cgo -ldflags="-s -w" -o /binaries/rpdata-ensurechannels ./cmd/rpdata-ensurechannels
|
||||
RUN go build -a -installsuffix cgo -ldflags="-s -w" -o /binaries/rpdata-as2storyimport ./cmd/rpdata-as2storyimport
|
||||
|
||||
## 2. React UI
|
||||
# Use Node.JS 18
|
||||
FROM node:10.5-alpine AS build-id
|
||||
|
||||
# The content is already there
|
||||
WORKDIR /rpdata-ui
|
||||
COPY ./rpdata-ui /rpdata-ui
|
||||
|
||||
# Prepare dependencies
|
||||
RUN npm install
|
||||
|
||||
# Run build
|
||||
RUN npm run build
|
||||
|
||||
## 3. Regroup
|
||||
## 2. Distribute
|
||||
# Use alpine linux
|
||||
FROM alpine:3.7
|
||||
|
||||
@@ -44,7 +32,6 @@ RUN apk add --no-cache ca-certificates
|
||||
|
||||
# Copy build files into final container
|
||||
COPY --from=build-server /binaries/* /usr/local/bin/
|
||||
COPY --from=build-id /rpdata-ui/build /var/www/
|
||||
|
||||
# TODO: Use proper server instead of grapihql server
|
||||
CMD ["/usr/local/bin/rpdata-graphiql"]
|
||||
# The server is the main entry point
|
||||
CMD ["/usr/local/bin/rpdata-server"]
|
||||
|
||||
Generated
+83
-7
@@ -2,10 +2,32 @@
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "git.aiterp.net/aiterp/wikiauth"
|
||||
name = "github.com/99designs/gqlgen"
|
||||
packages = [
|
||||
".",
|
||||
"cmd",
|
||||
"codegen",
|
||||
"codegen/templates",
|
||||
"complexity",
|
||||
"graphql",
|
||||
"graphql/introspection",
|
||||
"handler",
|
||||
"internal/gopath"
|
||||
]
|
||||
revision = "636435b68700211441303f1a5ed92f3768ba5774"
|
||||
version = "v0.5.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/agnivade/levenshtein"
|
||||
packages = ["."]
|
||||
revision = "33860de804ddcec4fc17998745233b4ec477e7c2"
|
||||
revision = "3d21ba515fe27b856f230847e856431ae1724adc"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -37,6 +59,12 @@
|
||||
revision = "d523deb1b23d913de5bdada721a6071e71283618"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
packages = ["."]
|
||||
revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/graph-gophers/dataloader"
|
||||
packages = ["."]
|
||||
@@ -64,6 +92,15 @@
|
||||
]
|
||||
revision = "9ebf33af539ab8cb832c7107bc0a978ca8dbc0de"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/hashicorp/golang-lru"
|
||||
packages = [
|
||||
".",
|
||||
"simplelru"
|
||||
]
|
||||
revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768"
|
||||
version = "v0.5.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/jmoiron/sqlx"
|
||||
@@ -103,10 +140,10 @@
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sadbox/mediawiki"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
revision = "39fea8a1336076a961a300d1d95765dcd17e8a3c"
|
||||
version = "v0.1"
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sirupsen/logrus"
|
||||
@@ -114,6 +151,26 @@
|
||||
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
|
||||
version = "v1.0.5"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/urfave/cli"
|
||||
packages = ["."]
|
||||
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
|
||||
version = "v1.20.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/vektah/gqlparser"
|
||||
packages = [
|
||||
".",
|
||||
"ast",
|
||||
"gqlerror",
|
||||
"lexer",
|
||||
"parser",
|
||||
"validator",
|
||||
"validator/rules"
|
||||
]
|
||||
revision = "14e83ae06ec152e6d0afb9766a00e0c0918aa8fc"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
@@ -164,15 +221,34 @@
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/tools"
|
||||
packages = [
|
||||
"go/ast/astutil",
|
||||
"go/buildutil",
|
||||
"go/internal/cgo",
|
||||
"go/loader",
|
||||
"imports",
|
||||
"internal/fastwalk"
|
||||
]
|
||||
revision = "677d2ff680c188ddb7dcd2bfa6bc7d3f2f2f75b2"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/appengine"
|
||||
packages = ["cloudsql"]
|
||||
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "16fd84401bc5796ffeaa895f31d099e1a23b363b15b87386877de0829ac9575b"
|
||||
inputs-digest = "3c9430afa8b9260026925c8f496af934e2e573a2bd4587bb634fd12a20ce6c2c"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
+3
-1
@@ -24,6 +24,8 @@
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
required = [ "github.com/99designs/gqlgen" ]
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/globalsign/mgo"
|
||||
@@ -38,4 +40,4 @@
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/graph-gophers/graphql-go"
|
||||
name = "github.com/graph-gophers/graphql-go"
|
||||
@@ -1,18 +1,5 @@
|
||||
# RPData API
|
||||
|
||||
Project RPData aims to centralize the AiteRP applications, and partially involve the wiki, into a common API. This will allow for easy linking and inlining between them. The primary consumers of this API will be the Logbot and the upcoming RPData website.
|
||||
Project RPData aims to centralize the AiteRP applications, and partially involve the wiki into a common API. This will allow for easy linking and inlining between them. The primary consumers of this API will be the Logbot and the upcoming RPData website.
|
||||
|
||||
## Progress
|
||||
|
||||
### Complete
|
||||
* Session
|
||||
* Character
|
||||
* Log
|
||||
* Post
|
||||
* File
|
||||
|
||||
### Remaining
|
||||
* Story
|
||||
|
||||
### Future
|
||||
* User (manual DB edits will suffice for now)
|
||||
There is some renovation going on, and the packages `model` and `graphql` are going to be superceded by `models` and `graph2`
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/store"
|
||||
"git.aiterp.net/rpdata/api/model/story"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/chapters"
|
||||
"git.aiterp.net/rpdata/api/models/stories"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
@@ -71,14 +73,20 @@ func main() {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
tags := make([]story.Tag, 0, 8)
|
||||
tags := make([]models.Tag, 0, 8)
|
||||
for _, tagResult := range tagResults {
|
||||
if tagResult.PageID == result.ID {
|
||||
tags = append(tags, story.Tag{Kind: tagResult.Type, Name: tagResult.Name})
|
||||
tags = append(tags, models.Tag{Kind: models.TagKind(tagResult.Type), Name: tagResult.Name})
|
||||
}
|
||||
}
|
||||
|
||||
story, err := story.New(result.Name, result.Author[5:], result.Category, false, false, tags, publishDate, fictionalDate)
|
||||
category := models.StoryCategory(result.Category)
|
||||
if !category.IsValid() {
|
||||
log.Println(result.Name, "does not have a valid category:", result.Category)
|
||||
continue
|
||||
}
|
||||
|
||||
story, err := stories.Add(result.Name, result.Author[5:], category, true, false, tags, publishDate, fictionalDate)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
@@ -96,19 +104,11 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
chapter, err := story.AddChapter(title, result.Author[5:], result.Source, publishDate, fictionalDate)
|
||||
chapter, err := chapters.Add(story, title, result.Author[5:], result.Source, publishDate, &fictionalDate)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
if !result.Unlisted {
|
||||
listed := true
|
||||
err := story.Edit(nil, nil, &listed, nil, nil)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(result.ID, "->", story.ID, chapter.ID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,9 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.aiterp.net/rpdata/api/model/channel"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/store"
|
||||
"git.aiterp.net/rpdata/api/model/log"
|
||||
"git.aiterp.net/rpdata/api/models/channels"
|
||||
"git.aiterp.net/rpdata/api/models/logs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -17,7 +16,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
logs, err := log.List(32768)
|
||||
logs, err := logs.List(nil)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return
|
||||
@@ -25,18 +24,18 @@ func main() {
|
||||
|
||||
added := make(map[string]bool, 1024)
|
||||
for _, log := range logs {
|
||||
if added[log.Channel] {
|
||||
if added[log.ChannelName] {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := channel.Ensure(log.Channel, false)
|
||||
_, err := channels.Ensure(log.ChannelName, false)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, log.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
added[log.Channel] = true
|
||||
added[log.ChannelName] = true
|
||||
|
||||
fmt.Println(log.Channel, "ensured")
|
||||
fmt.Println(log.ChannelName, "ensured")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
config.json
|
||||
debug
|
||||
@@ -1,150 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"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/store"
|
||||
"git.aiterp.net/rpdata/api/model/change"
|
||||
"git.aiterp.net/rpdata/api/model/file"
|
||||
logModel "git.aiterp.net/rpdata/api/model/log"
|
||||
graphql "github.com/graph-gophers/graphql-go"
|
||||
"github.com/graph-gophers/graphql-go/relay"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := store.Init()
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to init store:", err)
|
||||
}
|
||||
|
||||
n, err := logModel.UpdateAllCharacters()
|
||||
if err != nil {
|
||||
log.Println("Charcter updated stopped:", err)
|
||||
}
|
||||
log.Println("Updated characters on", n, "logs")
|
||||
|
||||
schema, err := graphql.ParseSchema(schema.String(), &resolver.RootResolver{}, graphql.MaxParallelism(48))
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to parse schema:", err)
|
||||
}
|
||||
|
||||
http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(page)
|
||||
}))
|
||||
|
||||
relayHandler := &relay.Handler{Schema: schema}
|
||||
http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
|
||||
r = session.Load(w, r)
|
||||
|
||||
l := loader.New()
|
||||
r = r.WithContext(l.ToContext(r.Context()))
|
||||
|
||||
relayHandler.ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
|
||||
r = session.Load(w, r)
|
||||
sess := session.FromContext(r.Context())
|
||||
user := sess.User()
|
||||
if user == nil || !user.Permitted("file.upload") {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if err := r.ParseMultipartForm(16384); err != nil {
|
||||
http.Error(w, "Internal (1): "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
formFile, header, err := r.FormFile("file")
|
||||
if err != nil || header == nil || formFile == nil {
|
||||
http.Error(w, "No file provided", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
file, err := file.Upload(r.Context(), header.Filename, header.Header.Get("Content-Type"), user.ID, header.Size, formFile)
|
||||
if err != nil {
|
||||
http.Error(w, "Internal (2): "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
json, err := json.Marshal(file)
|
||||
if err != nil {
|
||||
http.Error(w, "Internal (3): "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(json)
|
||||
})
|
||||
|
||||
change.InitializeTimeline()
|
||||
go func() {
|
||||
index := int64(0)
|
||||
|
||||
for {
|
||||
index++
|
||||
ch, err := change.Timeline.Get(context.Background(), index)
|
||||
if err == change.ErrExpired {
|
||||
continue
|
||||
} else if err != nil {
|
||||
log.Println("Timeline:", err)
|
||||
break
|
||||
}
|
||||
|
||||
log.Printf("Change: time=%s model=%s op=%s id=%s author=%s\n", ch.Time.Local().Format("[Mon Jan 02 15:04 MST]"), ch.Model, ch.Op, ch.ObjectID, ch.Author)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Fatal(http.ListenAndServe(":17000", nil))
|
||||
}
|
||||
|
||||
var page = []byte(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.10.2/graphiql.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.1.0/fetch.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.10.2/graphiql.js"></script>
|
||||
</head>
|
||||
<body style="width: 100%; height: 100%; margin: 0; overflow: hidden;">
|
||||
<div id="graphiql" style="height: 100vh;">Loading...</div>
|
||||
<script>
|
||||
function graphQLFetcher(graphQLParams) {
|
||||
return fetch("/graphql", {
|
||||
method: "post",
|
||||
body: JSON.stringify(graphQLParams),
|
||||
credentials: "include",
|
||||
}).then(function (response) {
|
||||
return response.text();
|
||||
}).then(function (responseBody) {
|
||||
try {
|
||||
return JSON.parse(responseBody);
|
||||
} catch (error) {
|
||||
return responseBody;
|
||||
}
|
||||
});
|
||||
}
|
||||
ReactDOM.render(
|
||||
React.createElement(GraphiQL, {fetcher: graphQLFetcher}),
|
||||
document.getElementById("graphiql")
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"os"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/store"
|
||||
"git.aiterp.net/rpdata/api/model/character"
|
||||
"git.aiterp.net/rpdata/api/models/characters"
|
||||
)
|
||||
|
||||
var fileName = flag.String("file", "./characters.json", "json file to load")
|
||||
@@ -31,12 +31,12 @@ func main() {
|
||||
nicksAdded, nicksFailed := 0, 0
|
||||
|
||||
for _, info := range infos {
|
||||
char, err := character.New(info.Nicks[0], info.Name, info.ShortName, info.Author, "")
|
||||
char, err := characters.Add(info.Nicks[0], info.Name, info.ShortName, info.Author, "")
|
||||
if err != nil {
|
||||
log.Println(info.Nicks[0], "failed to insert:", err)
|
||||
charsFailed++
|
||||
|
||||
char, err = character.FindNick(info.Nicks[0])
|
||||
char, err = characters.FindNick(info.Nicks[0])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func main() {
|
||||
}
|
||||
|
||||
for _, alt := range info.Nicks[1:] {
|
||||
err := char.AddNick(alt)
|
||||
char, err = characters.AddNick(char, alt)
|
||||
if err != nil {
|
||||
log.Println(info.Nicks[0], "failed to add nick", alt, "error:", err)
|
||||
nicksFailed++
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models/posts"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/store"
|
||||
logModel "git.aiterp.net/rpdata/api/model/log"
|
||||
"git.aiterp.net/rpdata/api/models/logs"
|
||||
)
|
||||
|
||||
var prefixReplacer = strings.NewReplacer("+", "", "@", "", "!", "", "%", "")
|
||||
@@ -47,13 +49,13 @@ func main() {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
l, err := logModel.New(date, channel, title, event, "", false)
|
||||
l, err := logs.Add(date, channel, title, event, "", false)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = l.NewPost(time.Now(), "annotation.info", "rpdata-lb2logimport", "This logfile is imported from aitelogs2 and may contain errors or wrong timestamps.")
|
||||
_, err = posts.Add(l, time.Now(), "annotation.info", "rpdata-lb2logimport", "This logfile is imported from aitelogs2 and may contain errors or wrong timestamps.")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
@@ -63,7 +65,7 @@ func main() {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = l.NewPost(l.Date, "chars", prefixReplacer.Replace(line.Args[0]), line.Text)
|
||||
_, err = posts.Add(l, l.Date, "chars", prefixReplacer.Replace(line.Args[0]), line.Text)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
@@ -92,13 +94,13 @@ func main() {
|
||||
line.Verb = "SCENE"
|
||||
}
|
||||
|
||||
_, err = l.NewPost(postTime, strings.ToLower(line.Verb), prefixReplacer.Replace(line.Args[0]), line.Text)
|
||||
_, err = posts.Add(l, postTime, strings.ToLower(line.Verb), prefixReplacer.Replace(line.Args[0]), line.Text)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
err = l.UpdateCharacters()
|
||||
l, err = logs.UpdateCharacters(l)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models/logs"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graph2"
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"git.aiterp.net/rpdata/api/internal/loader"
|
||||
"git.aiterp.net/rpdata/api/internal/store"
|
||||
"github.com/99designs/gqlgen/handler"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := store.Init()
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to init store:", err)
|
||||
}
|
||||
|
||||
http.Handle("/", handler.Playground("RPData API", "/graphql"))
|
||||
http.Handle("/graphql", queryHandler())
|
||||
|
||||
go func() {
|
||||
err := logs.RunFullUpdate()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
log.Println("Characters updated")
|
||||
}()
|
||||
|
||||
log.Fatal(http.ListenAndServe(":8081", nil))
|
||||
}
|
||||
|
||||
func queryHandler() http.HandlerFunc {
|
||||
handler := handler.GraphQL(
|
||||
graph2.New(),
|
||||
handler.RecoverFunc(func(ctx context.Context, err interface{}) error {
|
||||
// send this panic somewhere
|
||||
log.Println(err)
|
||||
log.Println(string(debug.Stack()))
|
||||
|
||||
return fmt.Errorf("shit")
|
||||
}),
|
||||
)
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := loader.New()
|
||||
r = r.WithContext(l.ToContext(r.Context()))
|
||||
|
||||
// >_>
|
||||
if strings.HasPrefix(r.Header.Get("Authorization"), "Bearer of the curse") {
|
||||
w.Header().Set("X-Emerald-Herald", "Seek souls. Larger, more powerful souls.")
|
||||
w.Header().Add("X-Emerald-Herald", "Seek the king, that is the only way.")
|
||||
w.Header().Add("X-Emerald-Herald", "Lest this land swallow you whole... As it has so many others.")
|
||||
}
|
||||
|
||||
r = auth.RequestWithToken(r)
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "# Generated by stiching together the files under schema/ – DO NOT EDIT" >generated.gql
|
||||
cat schema/root.gql schema/**/*.gql >>generated.gql
|
||||
@@ -0,0 +1,57 @@
|
||||
schema: generated.gql
|
||||
|
||||
exec:
|
||||
filename: generated.go
|
||||
package: graph2
|
||||
|
||||
model:
|
||||
filename: input/generated.go
|
||||
package: input
|
||||
|
||||
models:
|
||||
Tag:
|
||||
model: git.aiterp.net/rpdata/api/models.Tag
|
||||
TagInput: #It's the same as tags
|
||||
model: git.aiterp.net/rpdata/api/models.Tag
|
||||
TagKind:
|
||||
model: git.aiterp.net/rpdata/api/models.TagKind
|
||||
Character:
|
||||
model: git.aiterp.net/rpdata/api/models.Character
|
||||
CharactersFilter:
|
||||
model: git.aiterp.net/rpdata/api/models/characters.Filter
|
||||
Channel:
|
||||
model: git.aiterp.net/rpdata/api/models.Channel
|
||||
ChannelsFilter:
|
||||
model: git.aiterp.net/rpdata/api/models/channels.Filter
|
||||
Post:
|
||||
model: git.aiterp.net/rpdata/api/models.Post
|
||||
PostsFilter:
|
||||
model: git.aiterp.net/rpdata/api/models/posts.Filter
|
||||
Log:
|
||||
model: git.aiterp.net/rpdata/api/models.Log
|
||||
LogsFilter:
|
||||
model: git.aiterp.net/rpdata/api/models/logs.Filter
|
||||
Chapter:
|
||||
model: git.aiterp.net/rpdata/api/models.Chapter
|
||||
fields:
|
||||
fictionalDate:
|
||||
resolver: true
|
||||
Story:
|
||||
model: git.aiterp.net/rpdata/api/models.Story
|
||||
fields:
|
||||
fictionalDate:
|
||||
resolver: true
|
||||
StoryCategory:
|
||||
model: git.aiterp.net/rpdata/api/models.StoryCategory
|
||||
StoriesFilter:
|
||||
model: git.aiterp.net/rpdata/api/models/stories.Filter
|
||||
File:
|
||||
model: git.aiterp.net/rpdata/api/models.File
|
||||
FilesFilter:
|
||||
model: git.aiterp.net/rpdata/api/models/files.Filter
|
||||
Token:
|
||||
model: git.aiterp.net/rpdata/api/models.Token
|
||||
User:
|
||||
model: git.aiterp.net/rpdata/api/models.User
|
||||
Date:
|
||||
model: git.aiterp.net/rpdata/api/models/scalars.Date
|
||||
@@ -0,0 +1,47 @@
|
||||
package graph2
|
||||
|
||||
import (
|
||||
"git.aiterp.net/rpdata/api/graph2/queries"
|
||||
"git.aiterp.net/rpdata/api/graph2/types"
|
||||
graphql "github.com/99designs/gqlgen/graphql"
|
||||
)
|
||||
|
||||
//go:generate ./combine.sh
|
||||
//go:generate gorunpkg github.com/99designs/gqlgen -v
|
||||
|
||||
// New creates a new GraphQL schema.
|
||||
func New() graphql.ExecutableSchema {
|
||||
return NewExecutableSchema(Config{
|
||||
Resolvers: &rootResolver{},
|
||||
})
|
||||
}
|
||||
|
||||
type rootResolver struct{}
|
||||
|
||||
func (r *rootResolver) Query() QueryResolver {
|
||||
return &queries.Resolver
|
||||
}
|
||||
|
||||
func (r *rootResolver) Mutation() MutationResolver {
|
||||
return queries.MutationResolver
|
||||
}
|
||||
|
||||
func (r *rootResolver) Log() LogResolver {
|
||||
return &types.LogResolver
|
||||
}
|
||||
|
||||
func (r *rootResolver) Chapter() ChapterResolver {
|
||||
return &types.ChapterResolver
|
||||
}
|
||||
|
||||
func (r *rootResolver) Story() StoryResolver {
|
||||
return &types.StoryResolver
|
||||
}
|
||||
|
||||
func (r *rootResolver) File() FileResolver {
|
||||
return &types.FileResolver
|
||||
}
|
||||
|
||||
func (r *rootResolver) Token() TokenResolver {
|
||||
return &types.TokenResolver
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graph2/input"
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/changes"
|
||||
"git.aiterp.net/rpdata/api/models/channels"
|
||||
)
|
||||
|
||||
// Queries
|
||||
|
||||
func (r *resolver) Channel(ctx context.Context, name string) (models.Channel, error) {
|
||||
return channels.FindName(name)
|
||||
}
|
||||
|
||||
func (r *resolver) Channels(ctx context.Context, filter *channels.Filter) ([]models.Channel, error) {
|
||||
return channels.List(filter)
|
||||
}
|
||||
|
||||
// Mutations
|
||||
|
||||
func (r *mutationResolver) AddChannel(ctx context.Context, input input.ChannelAddInput) (models.Channel, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.Permitted("channel.add") {
|
||||
return models.Channel{}, errors.New("You are not permitted to add channels")
|
||||
}
|
||||
|
||||
logged := false
|
||||
if input.Logged != nil {
|
||||
logged = *input.Logged
|
||||
}
|
||||
hub := false
|
||||
if input.Hub != nil {
|
||||
hub = *input.Hub
|
||||
}
|
||||
eventName := ""
|
||||
if input.EventName != nil {
|
||||
eventName = *input.EventName
|
||||
}
|
||||
locationName := ""
|
||||
if input.LocationName != nil {
|
||||
locationName = *input.LocationName
|
||||
}
|
||||
|
||||
channel, err := channels.Add(input.Name, logged, hub, eventName, locationName)
|
||||
if err != nil {
|
||||
return models.Channel{}, errors.New("Failed to add channel: " + err.Error())
|
||||
}
|
||||
|
||||
go changes.Submit("Channel", "add", token.UserID, channel)
|
||||
|
||||
return channel, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) EditChannel(ctx context.Context, input input.ChannelEditInput) (models.Channel, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.Permitted("channel.edit") {
|
||||
return models.Channel{}, errors.New("You are not permitted to edit channels")
|
||||
}
|
||||
|
||||
channel, err := channels.FindName(input.Name)
|
||||
if err != nil {
|
||||
return models.Channel{}, errors.New("Channel not found")
|
||||
}
|
||||
|
||||
channel, err = channels.Edit(channel, input.Logged, input.Hub, input.EventName, input.LocationName)
|
||||
if err != nil {
|
||||
return models.Channel{}, errors.New("Failed to edit channel: " + err.Error())
|
||||
}
|
||||
|
||||
go changes.Submit("Channel", "edit", token.UserID, channel)
|
||||
|
||||
return channel, nil
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"git.aiterp.net/rpdata/api/models/stories"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graph2/input"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/chapters"
|
||||
)
|
||||
|
||||
// Queries
|
||||
|
||||
func (r *resolver) Chapter(ctx context.Context, id string) (models.Chapter, error) {
|
||||
return chapters.FindID(id)
|
||||
}
|
||||
|
||||
// Mutations
|
||||
|
||||
func (r *mutationResolver) AddChapter(ctx context.Context, input input.ChapterAddInput) (models.Chapter, error) {
|
||||
story, err := stories.FindID(input.StoryID)
|
||||
if err != nil {
|
||||
return models.Chapter{}, errors.New("Story not found")
|
||||
}
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member", "story.add") {
|
||||
return models.Chapter{}, errors.New("Unauthorized")
|
||||
}
|
||||
|
||||
author := token.UserID
|
||||
if input.Author != nil && *input.Author != author {
|
||||
if !token.Permitted("story.add") {
|
||||
return models.Chapter{}, errors.New("False pretender")
|
||||
}
|
||||
|
||||
author = *input.Author
|
||||
}
|
||||
|
||||
if !story.Open && story.Author != author {
|
||||
return models.Chapter{}, errors.New("Story is not open")
|
||||
}
|
||||
|
||||
return chapters.Add(story, input.Title, author, input.Source, time.Now(), input.FictionalDate)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) EditChapter(ctx context.Context, input input.ChapterEditInput) (models.Chapter, error) {
|
||||
chapter, err := chapters.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Chapter{}, errors.New("Chapter not found")
|
||||
}
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.PermittedUser(chapter.Author, "member", "chapter.edit") {
|
||||
return models.Chapter{}, errors.New("Unauthorized")
|
||||
}
|
||||
|
||||
if input.ClearFictionalDate != nil && *input.ClearFictionalDate == true {
|
||||
input.FictionalDate = &time.Time{}
|
||||
}
|
||||
|
||||
return chapters.Edit(chapter, input.Title, input.Source, input.FictionalDate)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) RemoveChapter(ctx context.Context, input input.ChapterRemoveInput) (models.Chapter, error) {
|
||||
chapter, err := chapters.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Chapter{}, errors.New("Chapter not found")
|
||||
}
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.PermittedUser(chapter.Author, "member", "chapter.remove") {
|
||||
return models.Chapter{}, errors.New("Unauthorized")
|
||||
}
|
||||
|
||||
return chapters.Remove(chapter)
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graph2/input"
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/changes"
|
||||
"git.aiterp.net/rpdata/api/models/characters"
|
||||
"git.aiterp.net/rpdata/api/models/logs"
|
||||
)
|
||||
|
||||
// Queries
|
||||
|
||||
func (r *resolver) Character(ctx context.Context, id *string, nick *string) (models.Character, error) {
|
||||
if id != nil {
|
||||
return characters.FindID(*id)
|
||||
} else if nick != nil {
|
||||
return characters.FindNick(*nick)
|
||||
} else {
|
||||
return models.Character{}, errors.New("You must specify either an ID or a nick")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *resolver) Characters(ctx context.Context, filter *characters.Filter) ([]models.Character, error) {
|
||||
return characters.List(filter)
|
||||
}
|
||||
|
||||
// Mutations
|
||||
|
||||
func (r *mutationResolver) AddCharacter(ctx context.Context, input input.CharacterAddInput) (models.Character, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member", "character.add") {
|
||||
return models.Character{}, errors.New("You are not permitted to add characters")
|
||||
}
|
||||
if len(input.Name) < 2 || len(input.Nick) < 2 {
|
||||
return models.Character{}, errors.New("You need to provide a name and a nick (min length: 2)")
|
||||
}
|
||||
|
||||
shortName := ""
|
||||
if input.ShortName != nil {
|
||||
shortName = *input.ShortName
|
||||
} else {
|
||||
shortName = strings.SplitN(input.Name, " ", 2)[0]
|
||||
}
|
||||
|
||||
description := ""
|
||||
if input.Description != nil {
|
||||
description = *input.Description
|
||||
}
|
||||
|
||||
author := token.UserID
|
||||
if input.Author != nil && *input.Author != author {
|
||||
if !token.Permitted("character.add") {
|
||||
return models.Character{}, errors.New("You are only permitted to add your own characters")
|
||||
}
|
||||
|
||||
author = *input.Author
|
||||
}
|
||||
|
||||
logs.ScheduleFullUpdate()
|
||||
|
||||
character, err := characters.Add(input.Nick, input.Name, shortName, author, description)
|
||||
if err != nil {
|
||||
return models.Character{}, errors.New("Adding character failed: " + err.Error())
|
||||
}
|
||||
|
||||
go changes.Submit("Character", "add", token.UserID, character)
|
||||
|
||||
return character, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) AddCharacterNick(ctx context.Context, input input.CharacterNickInput) (models.Character, error) {
|
||||
character, err := characters.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Character{}, errors.New("Character not found")
|
||||
}
|
||||
|
||||
if len(input.Nick) < 2 {
|
||||
return models.Character{}, errors.New("You need to provide a valid nick (min length: 2)")
|
||||
}
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.PermittedUser(character.Author, "member", "character.edit") {
|
||||
return models.Character{}, errors.New("You are not permitted to edit this character")
|
||||
}
|
||||
|
||||
logs.ScheduleFullUpdate()
|
||||
|
||||
character, err = characters.AddNick(character, input.Nick)
|
||||
if err != nil {
|
||||
return models.Character{}, errors.New("Failed to add nick: " + err.Error())
|
||||
}
|
||||
|
||||
go logs.ScheduleFullUpdate()
|
||||
go changes.Submit("Character", "edit", token.UserID, character)
|
||||
|
||||
return character, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) RemoveCharacterNick(ctx context.Context, input input.CharacterNickInput) (models.Character, error) {
|
||||
character, err := characters.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Character{}, errors.New("Character not found")
|
||||
}
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.PermittedUser(character.Author, "member", "character.edit") {
|
||||
return models.Character{}, errors.New("You are not permitted to edit this character")
|
||||
}
|
||||
|
||||
character, err = characters.RemoveNick(character, input.Nick)
|
||||
if err != nil {
|
||||
return models.Character{}, errors.New("Failed to remove nick: " + err.Error())
|
||||
}
|
||||
|
||||
go logs.ScheduleFullUpdate()
|
||||
go changes.Submit("Character", "edit", token.UserID, character)
|
||||
|
||||
return character, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) EditCharacter(ctx context.Context, input input.CharacterEditInput) (models.Character, error) {
|
||||
character, err := characters.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Character{}, errors.New("Character not found")
|
||||
}
|
||||
|
||||
if input.Name != nil && len(*input.Name) < 2 {
|
||||
return models.Character{}, errors.New("You need to provide a valid name (min length: 2)")
|
||||
}
|
||||
if input.ShortName != nil && len(*input.ShortName) < 2 {
|
||||
return models.Character{}, errors.New("You need to provide a valid short name (min length: 2)")
|
||||
}
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.PermittedUser(character.Author, "member", "character.edit") {
|
||||
return models.Character{}, errors.New("You are not permitted to edit this character")
|
||||
}
|
||||
|
||||
character, err = characters.Edit(character, input.Name, input.ShortName, input.Description)
|
||||
if err != nil {
|
||||
return models.Character{}, errors.New("Failed to edit character: " + err.Error())
|
||||
}
|
||||
|
||||
go changes.Submit("Character", "edit", token.UserID, character)
|
||||
|
||||
return character, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) RemoveCharacter(ctx context.Context, input input.CharacterRemoveInput) (models.Character, error) {
|
||||
character, err := characters.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Character{}, errors.New("Character not found")
|
||||
}
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.PermittedUser(character.Author, "member", "character.remove") {
|
||||
return models.Character{}, errors.New("You are not permitted to remove this character")
|
||||
}
|
||||
|
||||
character, err = characters.Remove(character)
|
||||
if err != nil {
|
||||
return models.Character{}, errors.New("Failed to remove character: " + err.Error())
|
||||
}
|
||||
|
||||
go changes.Submit("Character", "remove", token.UserID, character)
|
||||
|
||||
return character, nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/files"
|
||||
)
|
||||
|
||||
func (r *resolver) File(ctx context.Context, id string) (models.File, error) {
|
||||
return files.FindID(id)
|
||||
}
|
||||
|
||||
func (r *resolver) Files(ctx context.Context, filter *files.Filter) ([]models.File, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
|
||||
if filter == nil {
|
||||
filter = &files.Filter{}
|
||||
}
|
||||
|
||||
// Only allow users to view public files that are not their own.
|
||||
if token != nil {
|
||||
if filter.Public == nil || *filter.Public == false {
|
||||
filter.Author = &token.UserID
|
||||
}
|
||||
} else {
|
||||
filter.Public = &trueValue
|
||||
}
|
||||
|
||||
return files.List(filter)
|
||||
}
|
||||
|
||||
var trueValue = true
|
||||
@@ -0,0 +1,125 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graph2/input"
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"git.aiterp.net/rpdata/api/internal/loader"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/changes"
|
||||
"git.aiterp.net/rpdata/api/models/logs"
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
)
|
||||
|
||||
// Queries
|
||||
|
||||
func (r *resolver) Log(ctx context.Context, id string) (models.Log, error) {
|
||||
return logs.FindID(id)
|
||||
}
|
||||
|
||||
func (r *resolver) Logs(ctx context.Context, filter *logs.Filter) ([]models.Log, error) {
|
||||
logs, err := logs.List(filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reqCtx := graphql.GetRequestContext(ctx)
|
||||
maybeCharacters := strings.Contains(reqCtx.RawQuery, "characters")
|
||||
maybeChannels := strings.Contains(reqCtx.RawQuery, "channels")
|
||||
|
||||
if len(logs) >= 100 && (maybeCharacters || maybeChannels) {
|
||||
loader := loader.FromContext(ctx)
|
||||
if loader == nil {
|
||||
return nil, errors.New("no loader")
|
||||
}
|
||||
|
||||
for _, log := range logs {
|
||||
if maybeChannels {
|
||||
loader.PrimeChannels("name", log.ChannelName)
|
||||
}
|
||||
|
||||
if maybeCharacters {
|
||||
loader.PrimeCharacters("id", log.CharacterIDs...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
// Mutations
|
||||
|
||||
func (r *mutationResolver) AddLog(ctx context.Context, input input.LogAddInput) (models.Log, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.Permitted("log.add") {
|
||||
return models.Log{}, errors.New("You are not permitted to add logs")
|
||||
}
|
||||
|
||||
open := input.Open != nil && *input.Open == true
|
||||
title := ""
|
||||
if input.Title != nil {
|
||||
title = *input.Title
|
||||
}
|
||||
event := ""
|
||||
if input.Event != nil {
|
||||
event = *input.Event
|
||||
}
|
||||
description := ""
|
||||
if input.Description != nil {
|
||||
description = *input.Description
|
||||
}
|
||||
|
||||
log, err := logs.Add(input.Date, input.Channel, title, event, description, open)
|
||||
if !token.Authenticated() || !token.Permitted("log.add") {
|
||||
return models.Log{}, errors.New("Failed to create log: " + err.Error())
|
||||
}
|
||||
|
||||
go changes.Submit("Log", "add", token.UserID, log)
|
||||
|
||||
return log, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) EditLog(ctx context.Context, input input.LogEditInput) (models.Log, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.Permitted("log.edit") {
|
||||
return models.Log{}, errors.New("You are not permitted to edit logs")
|
||||
}
|
||||
|
||||
log, err := logs.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Log{}, errors.New("Log not found")
|
||||
}
|
||||
|
||||
log, err = logs.Edit(log, input.Title, input.Event, input.Description, input.Open)
|
||||
if err != nil {
|
||||
return models.Log{}, errors.New("Failed to edit log: " + err.Error())
|
||||
}
|
||||
|
||||
go changes.Submit("Log", "edit", token.UserID, log)
|
||||
|
||||
return log, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) RemoveLog(ctx context.Context, input input.LogRemoveInput) (models.Log, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.Permitted("log.remove") {
|
||||
return models.Log{}, errors.New("You are not permitted to remove logs")
|
||||
}
|
||||
|
||||
log, err := logs.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Log{}, errors.New("Log not found")
|
||||
}
|
||||
|
||||
log, err = logs.Remove(log)
|
||||
if err != nil {
|
||||
return models.Log{}, errors.New("Failed to remove log: " + err.Error())
|
||||
}
|
||||
|
||||
go changes.Submit("Log", "remove", token.UserID, log)
|
||||
|
||||
return log, nil
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models/changes"
|
||||
"git.aiterp.net/rpdata/api/models/logs"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graph2/input"
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/posts"
|
||||
)
|
||||
|
||||
// Queries
|
||||
|
||||
func (r *resolver) Post(ctx context.Context, id string) (models.Post, error) {
|
||||
return posts.FindID(id)
|
||||
}
|
||||
|
||||
func (r *resolver) Posts(ctx context.Context, filter *posts.Filter) ([]models.Post, error) {
|
||||
// Some sanity checks to avoid querying an insame amount of posts.
|
||||
if filter == nil {
|
||||
filter = &posts.Filter{Limit: 256}
|
||||
} else {
|
||||
if (filter.Limit <= 0 || filter.Limit > 256) && filter.LogID == nil {
|
||||
return nil, errors.New("a limit of 0 (no limit) or >256 without a logId is not allowed")
|
||||
}
|
||||
|
||||
if len(filter.Kind) > 32 {
|
||||
return nil, errors.New("You cannot specify more than 32 kinds")
|
||||
}
|
||||
|
||||
if len(filter.ID) > 32 {
|
||||
return nil, errors.New("You cannot specify more than 32 IDs")
|
||||
}
|
||||
}
|
||||
|
||||
return posts.List(filter)
|
||||
}
|
||||
|
||||
// Mutation
|
||||
|
||||
func (r *mutationResolver) AddPost(ctx context.Context, input input.PostAddInput) (models.Post, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.Permitted("post.add") {
|
||||
return models.Post{}, errors.New("You are not permitted to edit logs")
|
||||
}
|
||||
|
||||
log, err := logs.FindID(input.LogID)
|
||||
if err != nil {
|
||||
return models.Post{}, err
|
||||
}
|
||||
|
||||
post, err := posts.Add(log, input.Time, input.Kind, input.Nick, input.Text)
|
||||
if err != nil {
|
||||
return models.Post{}, err
|
||||
}
|
||||
|
||||
go logs.UpdateCharacters(log)
|
||||
go changes.Submit("Post", "add", token.UserID, post)
|
||||
|
||||
return post, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) EditPost(ctx context.Context, input input.PostEditInput) (models.Post, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.Permitted("post.edit") {
|
||||
return models.Post{}, errors.New("You are not permitted to edit logs")
|
||||
}
|
||||
|
||||
post, err := posts.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Post{}, errors.New("Post not found")
|
||||
}
|
||||
|
||||
if input.Nick != nil {
|
||||
go func() {
|
||||
log, err := logs.FindID(post.LogID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
logs.UpdateCharacters(log)
|
||||
}()
|
||||
}
|
||||
|
||||
post, err = posts.Edit(post, input.Time, input.Kind, input.Nick, input.Text)
|
||||
if err != nil {
|
||||
return models.Post{}, errors.New("Adding post failed: " + err.Error())
|
||||
}
|
||||
|
||||
go changes.Submit("Post", "edit", token.UserID, post)
|
||||
|
||||
return post, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) MovePost(ctx context.Context, input input.PostMoveInput) ([]models.Post, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.Permitted("post.move") {
|
||||
return nil, errors.New("You are not permitted to edit logs")
|
||||
}
|
||||
|
||||
post, err := posts.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, errors.New("Post not found")
|
||||
}
|
||||
|
||||
posts, err := posts.Move(post, input.ToPosition)
|
||||
if err != nil {
|
||||
return nil, errors.New("Moving posts failed: " + err.Error())
|
||||
}
|
||||
|
||||
posts2 := make([]interface{}, len(posts))
|
||||
for i := range posts {
|
||||
posts2[i] = posts[i]
|
||||
}
|
||||
go changes.Submit("Post", "move", token.UserID, posts2...)
|
||||
|
||||
return posts, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) RemovePost(ctx context.Context, input input.PostRemoveInput) (models.Post, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() || !token.Permitted("post.remove") {
|
||||
return models.Post{}, errors.New("You are not permitted to edit logs")
|
||||
}
|
||||
|
||||
post, err := posts.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Post{}, errors.New("Post not found (before removing, of course)")
|
||||
}
|
||||
|
||||
post, err = posts.Remove(post)
|
||||
if err != nil {
|
||||
return models.Post{}, errors.New("Could not remove post: " + err.Error())
|
||||
}
|
||||
|
||||
go func() {
|
||||
log, err := logs.FindID(post.LogID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
logs.UpdateCharacters(log)
|
||||
}()
|
||||
go changes.Submit("Post", "remove", token.UserID, post)
|
||||
|
||||
return post, nil
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package queries
|
||||
|
||||
type resolver struct{}
|
||||
type mutationResolver struct{}
|
||||
|
||||
// Resolver has all the queries
|
||||
var Resolver resolver
|
||||
|
||||
// MutationResolver brings the mutagens.
|
||||
var MutationResolver *mutationResolver
|
||||
@@ -0,0 +1,136 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graph2/input"
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/chapters"
|
||||
"git.aiterp.net/rpdata/api/models/stories"
|
||||
)
|
||||
|
||||
func (r *resolver) Story(ctx context.Context, id string) (models.Story, error) {
|
||||
return stories.FindID(id)
|
||||
}
|
||||
|
||||
func (r *resolver) Stories(ctx context.Context, filter *stories.Filter) ([]models.Story, error) {
|
||||
if filter != nil {
|
||||
if filter.Unlisted != nil && *filter.Unlisted == true {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() {
|
||||
return nil, errors.New("You are not permitted to view unlisted stories")
|
||||
}
|
||||
|
||||
if !token.Permitted("story.unlisted") {
|
||||
filter.Author = &token.UserID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stories.List(filter)
|
||||
}
|
||||
|
||||
// Mutations
|
||||
|
||||
func (r *mutationResolver) AddStory(ctx context.Context, input input.StoryAddInput) (models.Story, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if token == nil || !token.Permitted("member", "story.add") {
|
||||
return models.Story{}, errors.New("Permission denied")
|
||||
}
|
||||
|
||||
author := token.UserID
|
||||
if input.Author != nil && *input.Author != author {
|
||||
if !token.Permitted("story.add") {
|
||||
return models.Story{}, errors.New("You are not permitted to add a story in another author's name")
|
||||
}
|
||||
|
||||
author = *input.Author
|
||||
}
|
||||
|
||||
fictionalDate := time.Time{}
|
||||
if input.FictionalDate != nil {
|
||||
fictionalDate = *input.FictionalDate
|
||||
}
|
||||
|
||||
listed := input.Listed != nil && *input.Listed
|
||||
open := input.Open != nil && *input.Open
|
||||
|
||||
return stories.Add(input.Name, author, input.Category, listed, open, input.Tags, time.Now(), fictionalDate)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) AddStoryTag(ctx context.Context, input input.StoryTagAddInput) (models.Story, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
|
||||
story, err := stories.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Story{}, errors.New("Story not found")
|
||||
}
|
||||
|
||||
if !token.PermittedUser(story.Author, "member", "story.edit") {
|
||||
return models.Story{}, errors.New("You are not permitted to edit this story")
|
||||
}
|
||||
|
||||
return stories.AddTag(story, input.Tag)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) RemoveStoryTag(ctx context.Context, input input.StoryTagRemoveInput) (models.Story, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
|
||||
story, err := stories.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Story{}, errors.New("Story not found")
|
||||
}
|
||||
|
||||
if !token.PermittedUser(story.Author, "member", "story.edit") {
|
||||
return models.Story{}, errors.New("You are not permitted to edit this story")
|
||||
}
|
||||
|
||||
return stories.RemoveTag(story, input.Tag)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) EditStory(ctx context.Context, input input.StoryEditInput) (models.Story, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
|
||||
story, err := stories.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Story{}, errors.New("Story not found")
|
||||
}
|
||||
|
||||
if !token.PermittedUser(story.Author, "member", "story.edit") {
|
||||
return models.Story{}, errors.New("You are not permitted to remove this story")
|
||||
}
|
||||
|
||||
if input.ClearFictionalDate != nil && *input.ClearFictionalDate {
|
||||
input.FictionalDate = &time.Time{}
|
||||
}
|
||||
|
||||
return stories.Edit(story, input.Name, input.Category, input.Listed, input.Open, input.FictionalDate)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) RemoveStory(ctx context.Context, input input.StoryRemoveInput) (models.Story, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
|
||||
story, err := stories.FindID(input.ID)
|
||||
if err != nil {
|
||||
return models.Story{}, errors.New("Story not found")
|
||||
}
|
||||
|
||||
if !token.PermittedUser(story.Author, "member", "story.remove") {
|
||||
return models.Story{}, errors.New("You are not permitted to remove this story")
|
||||
}
|
||||
|
||||
story, err = stories.Remove(story)
|
||||
if err != nil {
|
||||
return models.Story{}, err
|
||||
}
|
||||
|
||||
err = chapters.RemoveStory(story)
|
||||
if err != nil {
|
||||
return models.Story{}, errors.New("Failed to remove chapters, but story is removed: " + err.Error())
|
||||
}
|
||||
|
||||
return story, nil
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/tags"
|
||||
)
|
||||
|
||||
func (r *resolver) Tags(ctx context.Context) ([]models.Tag, error) {
|
||||
return tags.List()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
)
|
||||
|
||||
func (r *resolver) Token(ctx context.Context) (models.Token, error) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Authenticated() {
|
||||
return models.Token{}, errors.New("No (valid) token")
|
||||
}
|
||||
|
||||
return *token, nil
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
schema {
|
||||
query: Query
|
||||
mutation: Mutation
|
||||
}
|
||||
|
||||
type Query {
|
||||
# Find character by either an ID or a nick.
|
||||
character(id: String, nick: String): Character!
|
||||
|
||||
# Find characters
|
||||
characters(filter: CharactersFilter): [Character!]!
|
||||
|
||||
|
||||
# Find channel by name
|
||||
channel(name: String!): Channel!
|
||||
|
||||
# Find channels
|
||||
channels(filter: ChannelsFilter): [Channel!]!
|
||||
|
||||
|
||||
# Find post by ID.
|
||||
post(id: String!): Post!
|
||||
|
||||
# Find posts
|
||||
posts(filter: PostsFilter): [Post!]!
|
||||
|
||||
|
||||
# Find log by ID
|
||||
log(id: String!): Log!
|
||||
|
||||
# Find logs
|
||||
logs(filter: LogsFilter): [Log!]!
|
||||
|
||||
|
||||
# Find story chapter by ID
|
||||
chapter(id: String!): Chapter!
|
||||
|
||||
|
||||
# Find all distinct tags used in stories
|
||||
tags: [Tag!]!
|
||||
|
||||
|
||||
# Find story by ID
|
||||
story(id: String!): Story!
|
||||
|
||||
# Find stories
|
||||
stories(filter: StoriesFilter): [Story!]!
|
||||
|
||||
|
||||
# Find file by ID
|
||||
file(id: String!): File!
|
||||
|
||||
# Find files
|
||||
files(filter: FilesFilter): [File!]!
|
||||
|
||||
|
||||
# Get information about the token, useful for debugging.
|
||||
token: Token!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
# Add a story
|
||||
addStory(input: StoryAddInput!): Story!
|
||||
|
||||
# Add a story tag
|
||||
addStoryTag(input: StoryTagAddInput!): Story!
|
||||
|
||||
# Remove a story tag
|
||||
removeStoryTag(input: StoryTagRemoveInput!): Story!
|
||||
|
||||
# Edit a story
|
||||
editStory(input: StoryEditInput!): Story!
|
||||
|
||||
# Remove a story
|
||||
removeStory(input: StoryRemoveInput!): Story!
|
||||
|
||||
|
||||
# Add a chapter to a story
|
||||
addChapter(input: ChapterAddInput!): Chapter!
|
||||
|
||||
# Edit a chapter
|
||||
editChapter(input: ChapterEditInput!): Chapter!
|
||||
|
||||
# Remove a chapter
|
||||
removeChapter(input: ChapterRemoveInput!): Chapter!
|
||||
|
||||
|
||||
# Add a new log
|
||||
addLog(input: LogAddInput!): Log!
|
||||
|
||||
# Edit a log
|
||||
editLog(input: LogEditInput!): Log!
|
||||
|
||||
# Remove a log
|
||||
removeLog(input: LogRemoveInput!): Log!
|
||||
|
||||
|
||||
# Add a post
|
||||
addPost(input: PostAddInput!): Post!
|
||||
|
||||
# Edit a post
|
||||
editPost(input: PostEditInput!): Post!
|
||||
|
||||
# Move a post. All affected posts will be returned.
|
||||
movePost(input: PostMoveInput!): [Post!]!
|
||||
|
||||
# Remove a post
|
||||
removePost(input: PostRemoveInput!): Post!
|
||||
|
||||
|
||||
# Add a new character
|
||||
addCharacter(input: CharacterAddInput!): Character!
|
||||
|
||||
# Add nick to character
|
||||
addCharacterNick(input: CharacterNickInput!): Character!
|
||||
|
||||
# Remove nick from character
|
||||
removeCharacterNick(input: CharacterNickInput!): Character!
|
||||
|
||||
# Edit character
|
||||
editCharacter(input: CharacterEditInput!): Character!
|
||||
|
||||
# Remove a character
|
||||
removeCharacter(input: CharacterRemoveInput!): Character!
|
||||
|
||||
|
||||
# Add a channel
|
||||
addChannel(input: ChannelAddInput!): Channel!
|
||||
|
||||
# Edit a channel
|
||||
editChannel(input: ChannelEditInput!): Channel!
|
||||
}
|
||||
|
||||
# A Date represents a RFC3339 encoded date with up to millisecond precision.
|
||||
scalar Date
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# Information about an IRC channel
|
||||
type Channel {
|
||||
# The channel's name
|
||||
name: String!
|
||||
|
||||
# Whether the channel should be logged
|
||||
logged: Boolean!
|
||||
|
||||
# Whether the channel is a hub channel
|
||||
hub: Boolean!
|
||||
|
||||
# The event name, or `null` if none is specified
|
||||
eventName: String
|
||||
|
||||
# The location name, or `null` if none is specified
|
||||
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 {
|
||||
# The channel's name
|
||||
name: String!
|
||||
|
||||
# Whether the channel should be logged
|
||||
logged: Boolean
|
||||
|
||||
# Whether the channel is a hub channel
|
||||
hub: Boolean
|
||||
|
||||
# The event name, or `null` if none is specified
|
||||
eventName: String
|
||||
|
||||
# The location name, or `null` if none is specified
|
||||
locationName: String
|
||||
}
|
||||
|
||||
input ChannelEditInput {
|
||||
# The channel's name
|
||||
name: String!
|
||||
|
||||
# Whether the channel should be logged
|
||||
logged: Boolean
|
||||
|
||||
# Whether the channel is a hub channel
|
||||
hub: Boolean
|
||||
|
||||
# The event name, or `null` if none is specified
|
||||
eventName: String
|
||||
|
||||
# The location name, or `null` if none is specified
|
||||
locationName: String
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
# A Chapter is the main content body of a story.
|
||||
type Chapter {
|
||||
# The chapter's ID
|
||||
id: String!
|
||||
|
||||
# The chapter's title
|
||||
title: String!
|
||||
|
||||
# The chapter's author
|
||||
author: String!
|
||||
|
||||
# The chapter's source
|
||||
source: String!
|
||||
|
||||
# When the chapter was posted initialy
|
||||
createdDate: Date!
|
||||
|
||||
# The in-universe date and time of the chapter
|
||||
fictionalDate: Date
|
||||
|
||||
# The date of edit.
|
||||
editedDate: Date!
|
||||
}
|
||||
|
||||
# Input for addChapter mutation
|
||||
input ChapterAddInput {
|
||||
# The story to add a chapter to
|
||||
storyId: String!
|
||||
|
||||
# The title to give the chapter. It can not be left empty
|
||||
title: String!
|
||||
|
||||
# The author to set for the chapter. It will use the logged in user ID, and only
|
||||
# users with appropriate permissions can post as another author. Even then, it's only
|
||||
# for importing/moving content. This author name will not be used when logging the
|
||||
# submission
|
||||
author: String
|
||||
|
||||
# The markdown source for the content
|
||||
source: String!
|
||||
|
||||
# Optionally, assign a fictional date for the chapter
|
||||
fictionalDate: Date
|
||||
}
|
||||
|
||||
# Input for editChapter mutation
|
||||
input ChapterEditInput {
|
||||
# The chapter to edit
|
||||
id: String!
|
||||
|
||||
# Change the chapter's title
|
||||
title: String
|
||||
|
||||
# Change the source
|
||||
source: String
|
||||
|
||||
# Set the fictional date for a chapter
|
||||
fictionalDate: Date
|
||||
|
||||
# Remove the fictional date for a chapter
|
||||
clearFictionalDate: Boolean
|
||||
}
|
||||
|
||||
# Input for removeChapter mutation
|
||||
input ChapterRemoveInput {
|
||||
# The chapter to remove
|
||||
id: String!
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
# A Character represents an RP character
|
||||
type Character {
|
||||
# A unique identifier for the character
|
||||
id: String!
|
||||
|
||||
# The primary IRC nick belonging to the character
|
||||
nick: String
|
||||
|
||||
# All IRC nicks associated with this character
|
||||
nicks: [String!]!
|
||||
|
||||
# The character's author
|
||||
author: String!
|
||||
|
||||
# The character's name
|
||||
name: String!
|
||||
|
||||
# The name to display when space is scarce, usually the first/given name
|
||||
shortName: String!
|
||||
|
||||
# A short description of the character
|
||||
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 CharacterAddInput {
|
||||
# The primary IRC nick name to recognize this character by
|
||||
nick: String!
|
||||
|
||||
# The character's name
|
||||
name: String!
|
||||
|
||||
# Optioanl shortened name. By default, it uses the first token in the name
|
||||
shortName: String
|
||||
|
||||
# Description for a character.
|
||||
description: String
|
||||
|
||||
# Optioanlly, specify another author. This needs special permissions if it's not
|
||||
# your own username
|
||||
author: String
|
||||
}
|
||||
|
||||
# Input for addNick and removeNick mutation
|
||||
input CharacterNickInput {
|
||||
# The ID of the character
|
||||
id: String!
|
||||
|
||||
# The nick to add or remove
|
||||
nick: String!
|
||||
}
|
||||
|
||||
# Inpuit for editCharacter mutation
|
||||
input CharacterEditInput {
|
||||
# The id for the character to edit
|
||||
id: String!
|
||||
|
||||
# The full name of the character -- not the salarian full name!
|
||||
name: String
|
||||
|
||||
# The character's short name that is used in compact lists
|
||||
shortName: String
|
||||
|
||||
# A short description for the character
|
||||
description: String
|
||||
}
|
||||
|
||||
# Input for removeCharacter mutation
|
||||
input CharacterRemoveInput {
|
||||
# The id for the character to edit
|
||||
id: String!
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# A File contains information about a file and where to download it.
|
||||
type File {
|
||||
# The file's unique ID
|
||||
id: String!
|
||||
|
||||
# The kind of file. Most will be "upload", but some that are ported from the wiki will have other values for this.
|
||||
kind: String!
|
||||
|
||||
# The time of uploading
|
||||
time: Date!
|
||||
|
||||
# Whether the file is publicly listable. Someone with knowledge of the ID
|
||||
# will still be able to view it, however.
|
||||
public: Boolean!
|
||||
|
||||
# The file's name
|
||||
name: String!
|
||||
|
||||
# The MIME type of the file
|
||||
mimeType: String!
|
||||
|
||||
# The file's size in bytes
|
||||
size: Int!
|
||||
|
||||
# The uploader
|
||||
author: String!
|
||||
|
||||
# The URL where the file is hosted
|
||||
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.
|
||||
mimeType: [String!]
|
||||
}
|
||||
|
||||
# Input for editFile mutation
|
||||
input EditFileInput {
|
||||
# The file's unique ID
|
||||
id: String!
|
||||
|
||||
# Whether the file is publicly listable. Someone with knowledge of the ID
|
||||
# will still be able to view it, however.
|
||||
public: Boolean
|
||||
|
||||
# The file's name
|
||||
name: String
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
# A Log is the "file" of an RP session
|
||||
type Log {
|
||||
# A unique identifier for the log.
|
||||
id: String!
|
||||
|
||||
# A secondary unique identifier for the log. This is a lot shorter and more suitable for storage when
|
||||
# the link doesn't need to be as expressive.
|
||||
shortId: String!
|
||||
|
||||
# The date for a log.
|
||||
date: Date!
|
||||
|
||||
# The channel of a log.
|
||||
channelName: String!
|
||||
|
||||
# Information about the channel this log is in.
|
||||
channel: Channel!
|
||||
|
||||
# The session's title.
|
||||
title: String!
|
||||
|
||||
# The log's event, which is the same as the tags in the previous logbot site.
|
||||
# Empty string means that it's no event.
|
||||
eventName: String!
|
||||
|
||||
# The description of a session, which is empty if unset.
|
||||
description: String!
|
||||
|
||||
# Whether the log session is open.
|
||||
open: Boolean!
|
||||
|
||||
# The characters involved in the log file.
|
||||
characters: [Character!]!
|
||||
|
||||
# The posts of the logfile, which can be filtered by kinds.
|
||||
posts(kinds:[String!]): [Post!]!
|
||||
}
|
||||
|
||||
# Filter for logs query
|
||||
input LogsFilter {
|
||||
# Channels to limit results to (inclusive)
|
||||
channels: [String!]
|
||||
|
||||
# Events to limit results to (inclusive)
|
||||
events: [String!]
|
||||
|
||||
# Characters to limit results to (exclusive)
|
||||
characters: [String!]
|
||||
|
||||
# Search post content
|
||||
search: String
|
||||
|
||||
# Limit by whether it's open or not
|
||||
open: Boolean
|
||||
|
||||
# Limit the amount of results you get back
|
||||
limit: Int
|
||||
}
|
||||
|
||||
# Input for addLog mutation
|
||||
input LogAddInput {
|
||||
# The date of the log.
|
||||
date: Date!
|
||||
|
||||
# The channel where the log is set
|
||||
channel: String!
|
||||
|
||||
# Optional: The log title
|
||||
title: String
|
||||
|
||||
# Optional: Whether the log is open
|
||||
open: Boolean
|
||||
|
||||
# Optional: The log event name
|
||||
event: String
|
||||
|
||||
# Optional: A short description of the log
|
||||
description: String
|
||||
}
|
||||
|
||||
# Input for addLog mutation
|
||||
input LogEditInput {
|
||||
# The id of the log
|
||||
id: String!
|
||||
|
||||
# The log title
|
||||
title: String
|
||||
|
||||
# The log event name
|
||||
event: String
|
||||
|
||||
# A short description of the log
|
||||
description: String
|
||||
|
||||
# Open/close the log
|
||||
open: Boolean
|
||||
}
|
||||
|
||||
# Input for removeLog mutation
|
||||
input LogRemoveInput {
|
||||
# The id of the log to remove
|
||||
id: String!
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
# A Post is a part of a log
|
||||
type Post {
|
||||
# The post's ID
|
||||
id: String!
|
||||
|
||||
# The post's Log ID. This is the closest thing to a link back since this API graph doesn't have any cycles.
|
||||
logId: String!
|
||||
|
||||
# The date and time of posting
|
||||
time: Date!
|
||||
|
||||
# The kind of post this is. Only "text", "scene" and "action" are RP, while others are annotations and 'commands'.
|
||||
kind: String!
|
||||
|
||||
# The character nick
|
||||
nick: String!
|
||||
|
||||
# The post's text, which purpose depends on the kind
|
||||
text: String!
|
||||
|
||||
# The post's position, used for reordering
|
||||
position: Int!
|
||||
}
|
||||
|
||||
# Input for the addPost mutation
|
||||
input PostAddInput {
|
||||
# The log's ID that this post should be a part of
|
||||
logId: String!
|
||||
|
||||
# The date and time of posting, in a RFC3339 format with up to a nanosecond's precision
|
||||
time: Date!
|
||||
|
||||
# The kind of post this is. Only "text", "scene" and "action" are RP, while others are annotations and 'commands'.
|
||||
kind: String!
|
||||
|
||||
# The character nick, or command invoker for non-RP stuff
|
||||
nick: String!
|
||||
|
||||
# The post's text, which purpose depends on the kind
|
||||
text: String!
|
||||
}
|
||||
|
||||
# Input for the editPost mutation
|
||||
input PostEditInput {
|
||||
# The Post ID
|
||||
id: String!
|
||||
|
||||
# The date and time of posting, in a RFC3339 format with up to a nanosecond's precision
|
||||
time: Date
|
||||
|
||||
# The kind of post this is. Only "text", "scene" and "action" are RP, while others are annotations and 'commands'.
|
||||
kind: String
|
||||
|
||||
# The character nick, or command invoker for non-RP stuff
|
||||
nick: String
|
||||
|
||||
# The post's text, which purpose depends on the kind
|
||||
text: String
|
||||
}
|
||||
|
||||
# Input for the movePost mutation
|
||||
input PostMoveInput {
|
||||
# The Post ID
|
||||
id: String!
|
||||
|
||||
# Target index
|
||||
toPosition: Int!
|
||||
}
|
||||
|
||||
# Input for the removePost mutation
|
||||
input PostRemoveInput {
|
||||
# The Post ID
|
||||
id: String!
|
||||
}
|
||||
|
||||
# Filter for posts query
|
||||
input PostsFilter {
|
||||
id: [String!]
|
||||
kind: [String!]
|
||||
logId: String
|
||||
limit: Int
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
# A Story is a piece of content that, unlike wiki articles, are not something that should be ordered by time instead of title. It can
|
||||
# contain multiple chapters by one or more autohrs
|
||||
type Story {
|
||||
# The story's ID
|
||||
id: String!
|
||||
|
||||
# The story's name, which will show up in the lists.
|
||||
name: String!
|
||||
|
||||
# The story's author
|
||||
author: String!
|
||||
|
||||
# Whether other users may add/edit chapters to the story.
|
||||
open: Boolean!
|
||||
|
||||
# Whether users without a direct link can find this story.
|
||||
listed: Boolean!
|
||||
|
||||
# The category of the story
|
||||
category: StoryCategory!
|
||||
|
||||
# The tags for this tory
|
||||
tags: [Tag!]!
|
||||
|
||||
# The chapters of this story
|
||||
chapters: [Chapter!]!
|
||||
|
||||
# The date the story was created.
|
||||
createdDate: Date!
|
||||
|
||||
# The date the story is set in.
|
||||
fictionalDate: Date
|
||||
|
||||
# The date of the last major update to the story. This being bumped means a new chapter has been added.
|
||||
updatedDate: Date!
|
||||
}
|
||||
|
||||
# Filter for stories query.
|
||||
input StoriesFilter {
|
||||
# What author to query for
|
||||
author: String
|
||||
|
||||
# What category to query for
|
||||
category: StoryCategory
|
||||
|
||||
# What tags to query for
|
||||
tags: [TagInput!]
|
||||
|
||||
# If true, it will only show unlisted page you have access to
|
||||
unlisted: Boolean
|
||||
|
||||
# Whether the page is open for additions by other users
|
||||
open: Boolean
|
||||
|
||||
# The earliest fictionalDate
|
||||
earliestFictionalDate: Date
|
||||
|
||||
# The latest fictionalDate
|
||||
latestFictionalDate: Date
|
||||
|
||||
# The max amount of stories to get (default: 30)
|
||||
limit: Int
|
||||
}
|
||||
|
||||
# Input for the addStory mutation
|
||||
input StoryAddInput {
|
||||
# Set the name of the story, which will show up as the title, and as a suggestion for
|
||||
# the first chapter being added.
|
||||
name: String!
|
||||
|
||||
# Set the category for the new story.
|
||||
category: StoryCategory!
|
||||
|
||||
# Add the story under another name. This requires the story.add permission, and should not be
|
||||
# abused. The action will be logged with the actual creator's user ID.
|
||||
author: String
|
||||
|
||||
# Allow other users to post chapters to the story.
|
||||
open: Boolean
|
||||
|
||||
# Allow other users to see this page in any lists or search results.
|
||||
listed: Boolean
|
||||
|
||||
# Set which tags the story should have.
|
||||
tags: [TagInput!]
|
||||
|
||||
# Set the fictional date of the story.
|
||||
fictionalDate: Date
|
||||
}
|
||||
|
||||
# Input for the editStory mutation
|
||||
input StoryEditInput {
|
||||
# What story to edit
|
||||
id: String!
|
||||
|
||||
# Set the name of the story, which will show up as the title, and as a suggestion for
|
||||
# the first chapter being added.
|
||||
name: String
|
||||
|
||||
# Set the category for the new story.
|
||||
category: StoryCategory
|
||||
|
||||
# Add the story under another name. This requires the story.add permission, and should not be
|
||||
# abused. The action will be logged with the actual creator's user ID.
|
||||
author: String
|
||||
|
||||
# Change whether to allow others to add chapters
|
||||
open: Boolean
|
||||
|
||||
# Change whether to show this story in the list and search results
|
||||
listed: Boolean
|
||||
|
||||
# Set the fictional date of the story.
|
||||
fictionalDate: Date
|
||||
|
||||
# Clear the fictional date of the story.
|
||||
clearFictionalDate: Boolean
|
||||
}
|
||||
|
||||
# Input for the addStoryTag mutation
|
||||
input StoryTagAddInput {
|
||||
# What story to add the tag to.
|
||||
id: String!
|
||||
|
||||
# The tag to add.
|
||||
tag: TagInput!
|
||||
}
|
||||
|
||||
# Input for the removeStoryTag mutation
|
||||
input StoryTagRemoveInput {
|
||||
# What story to remove the tag from.
|
||||
id: String!
|
||||
|
||||
# The tag to remove.
|
||||
tag: TagInput!
|
||||
}
|
||||
|
||||
# Input for the removeStory mutation
|
||||
input StoryRemoveInput {
|
||||
# What story to remove.
|
||||
id: String!
|
||||
}
|
||||
|
||||
# Possible values for Story.category
|
||||
enum StoryCategory {
|
||||
# General information
|
||||
Info
|
||||
|
||||
# News stories
|
||||
News
|
||||
|
||||
# Description and content of a document or item
|
||||
Document
|
||||
|
||||
# Information about something going on in the background that may or may not inform RP
|
||||
Background
|
||||
|
||||
# A short story
|
||||
Story
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# A Tag is a means of associating stories that have details in common with one another.
|
||||
type Tag {
|
||||
# The tag's kind
|
||||
kind: TagKind!
|
||||
|
||||
# The tag's name
|
||||
name: String!
|
||||
}
|
||||
|
||||
# A Tag is a means of associating stories that have details in common with one another.
|
||||
input TagInput {
|
||||
# The tag's kind
|
||||
kind: TagKind!
|
||||
|
||||
# The tag's name
|
||||
name: String!
|
||||
}
|
||||
|
||||
# Allowed values for Tag.kind
|
||||
enum TagKind {
|
||||
# An organization is a catch all term for in-universe corporations, teams, groups, cults, forces, etc...
|
||||
Organization
|
||||
|
||||
# A character tag should have the exact full name of the character.
|
||||
Character
|
||||
|
||||
# A location is anything from a planet to an establishment. This may overlap with an organization, and if so, both
|
||||
# kinds of tags should be used.
|
||||
Location
|
||||
|
||||
# An event is a plot or a part of a plot.
|
||||
Event
|
||||
|
||||
# None of the above, but it does still tie multiple stories together. The new story/chapter format may obsolete this tag kind.
|
||||
Series
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Token represents the data parsed and validated from the bearer token.
|
||||
type Token {
|
||||
# The user represented in the token.
|
||||
user: User!
|
||||
|
||||
# The permissions for the token.
|
||||
permissions: [String!]!
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
# A user represents a member on the RPData platform.
|
||||
type User {
|
||||
# The user's unique ID / username
|
||||
id: String!
|
||||
|
||||
# What the user is permitted to do.
|
||||
permissions: [String!]!
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
)
|
||||
|
||||
type chapterResolver struct{}
|
||||
|
||||
func (r *chapterResolver) FictionalDate(ctx context.Context, chapter *models.Chapter) (*time.Time, error) {
|
||||
if chapter.FictionalDate.IsZero() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &chapter.FictionalDate, nil
|
||||
}
|
||||
|
||||
// ChapterResolver is a resolver
|
||||
var ChapterResolver chapterResolver
|
||||
@@ -0,0 +1,16 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
)
|
||||
|
||||
type fileResolver struct{}
|
||||
|
||||
func (r *fileResolver) Size(ctx context.Context, file *models.File) (int, error) {
|
||||
return int(file.Size), nil
|
||||
}
|
||||
|
||||
// FileResolver is a resolver
|
||||
var FileResolver fileResolver
|
||||
@@ -0,0 +1,41 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/loader"
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/posts"
|
||||
)
|
||||
|
||||
type logResolver struct{}
|
||||
|
||||
func (r *logResolver) Channel(ctx context.Context, log *models.Log) (models.Channel, error) {
|
||||
loader := loader.FromContext(ctx)
|
||||
if loader == nil {
|
||||
return models.Channel{}, errors.New("no loader")
|
||||
}
|
||||
|
||||
return loader.Channel("name", log.ChannelName)
|
||||
}
|
||||
|
||||
func (r *logResolver) Characters(ctx context.Context, log *models.Log) ([]models.Character, error) {
|
||||
loader := loader.FromContext(ctx)
|
||||
if loader == nil {
|
||||
return nil, errors.New("no loader")
|
||||
}
|
||||
|
||||
return loader.Characters("id", log.CharacterIDs...)
|
||||
}
|
||||
|
||||
func (r *logResolver) Posts(ctx context.Context, log *models.Log, kinds []string) ([]models.Post, error) {
|
||||
return posts.List(&posts.Filter{
|
||||
LogID: &log.ShortID,
|
||||
Kind: kinds,
|
||||
Limit: 0,
|
||||
})
|
||||
}
|
||||
|
||||
// LogResolver is a resolver
|
||||
var LogResolver logResolver
|
||||
@@ -0,0 +1,27 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models/chapters"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
)
|
||||
|
||||
type storyResolver struct{}
|
||||
|
||||
func (r *storyResolver) FictionalDate(ctx context.Context, story *models.Story) (*time.Time, error) {
|
||||
if story.FictionalDate.IsZero() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &story.FictionalDate, nil
|
||||
}
|
||||
|
||||
func (r *storyResolver) Chapters(ctx context.Context, story *models.Story) ([]models.Chapter, error) {
|
||||
return chapters.ListStoryID(story.ID)
|
||||
}
|
||||
|
||||
// StoryResolver is a resolver
|
||||
var StoryResolver storyResolver
|
||||
@@ -0,0 +1,17 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.aiterp.net/rpdata/api/models"
|
||||
"git.aiterp.net/rpdata/api/models/users"
|
||||
)
|
||||
|
||||
type tokenResolver struct{}
|
||||
|
||||
func (r *tokenResolver) User(ctx context.Context, token *models.Token) (models.User, error) {
|
||||
return users.Find(token.UserID)
|
||||
}
|
||||
|
||||
// TokenResolver is a resolver
|
||||
var TokenResolver tokenResolver
|
||||
@@ -1,156 +0,0 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/internal/session"
|
||||
"git.aiterp.net/rpdata/api/model/change"
|
||||
"git.aiterp.net/rpdata/api/model/channel"
|
||||
)
|
||||
|
||||
// ChannelArgs is args for channel query
|
||||
type ChannelArgs struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
// Channel implements the channel query
|
||||
func (r *QueryResolver) Channel(ctx context.Context, args *ChannelArgs) (*types.ChannelResolver, error) {
|
||||
channel, err := channel.FindName(args.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.ChannelResolver{C: channel}, nil
|
||||
}
|
||||
|
||||
// ChannelsArgs is args for channel query
|
||||
type ChannelsArgs struct {
|
||||
Logged *bool
|
||||
}
|
||||
|
||||
// Channels implements the channels query
|
||||
func (r *QueryResolver) Channels(ctx context.Context, args *ChannelsArgs) ([]*types.ChannelResolver, error) {
|
||||
channels, err := channel.List(args.Logged != nil && *args.Logged)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolvers := make([]*types.ChannelResolver, len(channels))
|
||||
for i := range channels {
|
||||
resolvers[i] = &types.ChannelResolver{C: channels[i]}
|
||||
}
|
||||
|
||||
return resolvers, nil
|
||||
}
|
||||
|
||||
// ChannelAddArgs is input for the addChannel mutation
|
||||
type ChannelAddArgs struct {
|
||||
Input *struct {
|
||||
Name string
|
||||
Logged *bool
|
||||
Hub *bool
|
||||
EventName *string
|
||||
LocationName *string
|
||||
}
|
||||
}
|
||||
|
||||
// AddChannel resolves the addChannel mutation
|
||||
func (r *MutationResolver) AddChannel(ctx context.Context, args *ChannelAddArgs) (*types.ChannelResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("channel.add") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
logged := input.Logged != nil && *input.Logged
|
||||
|
||||
hub := input.Hub != nil && *input.Hub
|
||||
|
||||
eventName := ""
|
||||
if input.EventName != nil {
|
||||
eventName = *input.EventName
|
||||
}
|
||||
|
||||
locationName := ""
|
||||
if input.LocationName != nil {
|
||||
locationName = *input.LocationName
|
||||
}
|
||||
|
||||
channel, err := channel.New(input.Name, logged, hub, eventName, locationName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Channel", "add", user.ID, channel.Name, map[string]interface{}{
|
||||
"logged": channel.Logged,
|
||||
"hub": channel.Hub,
|
||||
"location": input.LocationName,
|
||||
"event": input.EventName,
|
||||
})
|
||||
|
||||
return &types.ChannelResolver{C: channel}, nil
|
||||
}
|
||||
|
||||
// ChannelEditArgs is input for the editChannel mutation
|
||||
type ChannelEditArgs struct {
|
||||
Input *struct {
|
||||
Name string
|
||||
Logged *bool
|
||||
Hub *bool
|
||||
EventName *string
|
||||
LocationName *string
|
||||
}
|
||||
}
|
||||
|
||||
// EditChannel resolves the editChannel mutation
|
||||
func (r *MutationResolver) EditChannel(ctx context.Context, args *ChannelEditArgs) (*types.ChannelResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("channel.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
channel, err := channel.FindName(input.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = channel.Edit(input.Logged, input.Hub, input.EventName, input.LocationName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Channel", "edit", user.ID, channel.Name, map[string]interface{}{
|
||||
"logged": input.Logged,
|
||||
"hub": input.Hub,
|
||||
"location": input.LocationName,
|
||||
"event": input.EventName,
|
||||
})
|
||||
|
||||
return &types.ChannelResolver{C: channel}, nil
|
||||
}
|
||||
|
||||
// RemoveChannel resolves the editChannel mutation
|
||||
func (r *MutationResolver) RemoveChannel(ctx context.Context, args ChannelArgs) (*types.ChannelResolver, error) {
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("channel.remove") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
channel, err := channel.FindName(args.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = channel.Remove()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Channel", "remove", user.ID, channel.Name, nil)
|
||||
|
||||
return &types.ChannelResolver{C: channel}, nil
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/internal/session"
|
||||
"git.aiterp.net/rpdata/api/model/change"
|
||||
"git.aiterp.net/rpdata/api/model/story"
|
||||
)
|
||||
|
||||
// ChapterArgs is args for chapter query
|
||||
type ChapterArgs struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
// Chapter implements the chapter query
|
||||
func (r *QueryResolver) Chapter(ctx context.Context, args *ChapterArgs) (*types.ChapterResolver, error) {
|
||||
chapter, err := story.FindChapterID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.ChapterResolver{C: chapter}, nil
|
||||
}
|
||||
|
||||
// AddChapterArgs is args for the addChapter mutation
|
||||
type AddChapterArgs struct {
|
||||
Input *struct {
|
||||
StoryID string
|
||||
Title string
|
||||
Author *string
|
||||
Source string
|
||||
FictionalDate *string
|
||||
}
|
||||
}
|
||||
|
||||
// AddChapter implements the addChapter mutation
|
||||
func (r *MutationResolver) AddChapter(ctx context.Context, args *AddChapterArgs) (*types.ChapterResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member", "chapter.add") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
story, err := story.FindID(input.StoryID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
author := user.ID
|
||||
if input.Author != nil {
|
||||
author = *input.Author
|
||||
|
||||
if user.ID != author && !user.Permitted("chapter.add") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
}
|
||||
|
||||
fictionalDate := time.Time{}
|
||||
if input.FictionalDate != nil {
|
||||
fictionalDate, err = time.Parse(time.RFC3339Nano, *input.FictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
chapter, err := story.AddChapter(input.Title, author, input.Source, time.Now(), fictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Chapter", "add", user.ID, chapter.ID, map[string]interface{}{
|
||||
"title": input.Title,
|
||||
"author": author,
|
||||
"fictionalDate": fictionalDate,
|
||||
})
|
||||
|
||||
return &types.ChapterResolver{C: chapter}, nil
|
||||
}
|
||||
|
||||
// EditChapterArgs is args for the editChapter mutation
|
||||
type EditChapterArgs struct {
|
||||
Input *struct {
|
||||
ID string
|
||||
Title *string
|
||||
Source *string
|
||||
FictionalDate *string
|
||||
}
|
||||
}
|
||||
|
||||
// EditChapter implements the editChapter mutation
|
||||
func (r *MutationResolver) EditChapter(ctx context.Context, args *EditChapterArgs) (*types.ChapterResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member", "chapter.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
chapter, err := story.FindChapterID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if chapter.Author != user.ID && !user.Permitted("chapter.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
var fictionalDate *time.Time
|
||||
if input.FictionalDate != nil {
|
||||
date, err := time.Parse(time.RFC3339Nano, *input.FictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fictionalDate = &date
|
||||
}
|
||||
|
||||
err = chapter.Edit(input.Title, input.Source, fictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Chapter", "edit", user.ID, chapter.ID, map[string]interface{}{
|
||||
"title": input.Title,
|
||||
"source": input.Source,
|
||||
"fictionalDate": fictionalDate,
|
||||
})
|
||||
|
||||
return &types.ChapterResolver{C: chapter}, nil
|
||||
}
|
||||
|
||||
// DeleteChapterArgs is args for the addChapter mutation
|
||||
type DeleteChapterArgs struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
// RemoveChapter implements the removeChapter mutation
|
||||
func (r *MutationResolver) RemoveChapter(ctx context.Context, args *DeleteChapterArgs) (*types.ChapterResolver, error) {
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member", "chapter.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
chapter, err := story.FindChapterID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = chapter.Remove()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Chapter", "remove", user.ID, chapter.ID, nil)
|
||||
|
||||
return &types.ChapterResolver{C: chapter}, nil
|
||||
}
|
||||
@@ -1,299 +0,0 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/loader"
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/internal/session"
|
||||
"git.aiterp.net/rpdata/api/model/change"
|
||||
"git.aiterp.net/rpdata/api/model/character"
|
||||
"git.aiterp.net/rpdata/api/model/log"
|
||||
)
|
||||
|
||||
// CharacterArgs is an arg
|
||||
type CharacterArgs struct {
|
||||
ID *string
|
||||
Nick *string
|
||||
}
|
||||
|
||||
// Character resolver
|
||||
func (r *QueryResolver) Character(ctx context.Context, args *CharacterArgs) (*types.CharacterResolver, error) {
|
||||
var char character.Character
|
||||
var err error
|
||||
|
||||
loader := loader.FromContext(ctx)
|
||||
if loader == nil {
|
||||
return nil, errors.New("no loader")
|
||||
}
|
||||
|
||||
switch {
|
||||
case args.ID != nil:
|
||||
char, err = character.FindID(*args.ID)
|
||||
case args.Nick != nil:
|
||||
char, err = character.FindNick(*args.Nick)
|
||||
default:
|
||||
err = ErrCannotResolve
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.CharacterResolver{C: char}, nil
|
||||
}
|
||||
|
||||
// CharactersArgs is an arg
|
||||
type CharactersArgs struct {
|
||||
IDs *[]string
|
||||
Nicks *[]string
|
||||
Author *string
|
||||
}
|
||||
|
||||
// Characters resolves the characters query
|
||||
func (r *QueryResolver) Characters(ctx context.Context, args *CharactersArgs) ([]*types.CharacterResolver, error) {
|
||||
var chars []character.Character
|
||||
var err error
|
||||
|
||||
loader := loader.FromContext(ctx)
|
||||
if loader == nil {
|
||||
return nil, errors.New("no loader")
|
||||
}
|
||||
|
||||
switch {
|
||||
case args.IDs != nil:
|
||||
chars, err = character.ListIDs(*args.IDs...)
|
||||
case args.Nicks != nil:
|
||||
chars, err = character.ListNicks(*args.Nicks...)
|
||||
case args.Author != nil:
|
||||
chars, err = character.ListAuthor(*args.Author)
|
||||
default:
|
||||
chars, err = character.List()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolvers := make([]*types.CharacterResolver, 0, len(chars))
|
||||
for i := range chars {
|
||||
if chars[i].ID == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
resolvers = append(resolvers, &types.CharacterResolver{C: chars[i]})
|
||||
}
|
||||
|
||||
return resolvers, nil
|
||||
}
|
||||
|
||||
// AddCharacterInput is args for the addCharacter mutation
|
||||
type AddCharacterInput struct {
|
||||
Nick string
|
||||
Name string
|
||||
ShortName *string
|
||||
Author *string
|
||||
Description *string
|
||||
}
|
||||
|
||||
// AddCharacter resolves the addCharacter mutation
|
||||
func (r *MutationResolver) AddCharacter(ctx context.Context, args struct{ Input *AddCharacterInput }) (*types.CharacterResolver, error) {
|
||||
input := args.Input
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member", "character.add") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
nick := input.Nick
|
||||
|
||||
name := input.Name
|
||||
|
||||
shortName := ""
|
||||
if input.ShortName != nil {
|
||||
shortName = *input.ShortName
|
||||
} else {
|
||||
shortName = strings.SplitN(input.Name, " ", 2)[0]
|
||||
}
|
||||
|
||||
author := user.ID
|
||||
if input.Author != nil {
|
||||
author = *input.Author
|
||||
|
||||
if author != user.ID && !user.Permitted("character.add") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
}
|
||||
|
||||
description := ""
|
||||
if input.Description != nil {
|
||||
description = *input.Description
|
||||
}
|
||||
|
||||
character, err := character.New(nick, name, shortName, author, description)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Character", "add", user.ID, character.ID, map[string]interface{}{
|
||||
"name": character.Name,
|
||||
"nick": character.Nicks[0],
|
||||
"author": character.Author,
|
||||
})
|
||||
|
||||
log.ScheduleCharacterUpdate()
|
||||
|
||||
return &types.CharacterResolver{C: character}, nil
|
||||
}
|
||||
|
||||
// CharacterNickInput is args for mutation addCharacterNick/removeCharacterNick
|
||||
type CharacterNickInput struct {
|
||||
ID string
|
||||
Nick string
|
||||
}
|
||||
|
||||
// AddCharacterNick resolves the addCharacterNick mutation
|
||||
func (r *MutationResolver) AddCharacterNick(ctx context.Context, args struct{ Input *CharacterNickInput }) (*types.CharacterResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
character, err := character.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if character.Author != user.ID && !user.Permitted("character.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = character.AddNick(input.Nick)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Character", "add.nick", user.ID, character.ID, map[string]interface{}{
|
||||
"nick": input.Nick,
|
||||
})
|
||||
|
||||
log.ScheduleCharacterUpdate()
|
||||
|
||||
return &types.CharacterResolver{C: character}, nil
|
||||
}
|
||||
|
||||
// RemoveCharacterNick resolves the removeCharacterNick mutation
|
||||
func (r *MutationResolver) RemoveCharacterNick(ctx context.Context, args struct{ Input *CharacterNickInput }) (*types.CharacterResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
character, err := character.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if character.Author != user.ID && !user.Permitted("character.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = character.RemoveNick(input.Nick)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Character", "remove.nick", user.ID, character.ID, map[string]interface{}{
|
||||
"nick": input.Nick,
|
||||
})
|
||||
|
||||
log.ScheduleCharacterUpdate()
|
||||
|
||||
return &types.CharacterResolver{C: character}, nil
|
||||
}
|
||||
|
||||
// CharacterEditInput is args for mutation addCharacterNick/removeCharacterNick
|
||||
type CharacterEditInput struct {
|
||||
ID string
|
||||
Name *string
|
||||
ShortName *string
|
||||
Description *string
|
||||
}
|
||||
|
||||
// EditCharacter resolves the editCharacter mutation
|
||||
func (r *MutationResolver) EditCharacter(ctx context.Context, args struct{ Input *CharacterEditInput }) (*types.CharacterResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
character, err := character.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if character.Author != user.ID && !user.Permitted("character.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
name := ""
|
||||
if input.Name != nil {
|
||||
name = *input.Name
|
||||
}
|
||||
|
||||
shortName := ""
|
||||
if input.ShortName != nil {
|
||||
shortName = *input.ShortName
|
||||
}
|
||||
|
||||
description := ""
|
||||
if input.Description != nil {
|
||||
description = *input.Description
|
||||
}
|
||||
|
||||
err = character.Edit(name, shortName, description)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Character", "edit", user.ID, character.ID, map[string]interface{}{
|
||||
"name": character.Name,
|
||||
"shortName": character.ShortName,
|
||||
"description": character.Description,
|
||||
})
|
||||
|
||||
return &types.CharacterResolver{C: character}, nil
|
||||
}
|
||||
|
||||
// RemoveCharacter resolves the removeCharacter mutation
|
||||
func (r *MutationResolver) RemoveCharacter(ctx context.Context, args struct{ ID string }) (*types.CharacterResolver, error) {
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
character, err := character.FindID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if character.Author != user.ID && !user.Permitted("character.remove") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = character.Remove()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Character", "remove", user.ID, character.ID, map[string]interface{}{
|
||||
"name": character.Name,
|
||||
"author": character.Author,
|
||||
"nicks": character.Nicks,
|
||||
})
|
||||
|
||||
return &types.CharacterResolver{C: character}, nil
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/internal/session"
|
||||
"git.aiterp.net/rpdata/api/model/file"
|
||||
)
|
||||
|
||||
// FileArgs is an arg
|
||||
type FileArgs struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
// File implements the file query
|
||||
func (r *QueryResolver) File(ctx context.Context, args *FileArgs) (*types.FileResolver, error) {
|
||||
file, err := file.FindID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.FileResolver{F: file}, nil
|
||||
}
|
||||
|
||||
// FilesArgs is an arg
|
||||
type FilesArgs struct {
|
||||
IncludePublic *bool
|
||||
MimeTypes *[]string
|
||||
}
|
||||
|
||||
// Files implements the file query
|
||||
func (r *QueryResolver) Files(ctx context.Context, args *FilesArgs) ([]*types.FileResolver, error) {
|
||||
user := session.FromContext(ctx).User()
|
||||
author := ""
|
||||
if user != nil {
|
||||
author = user.ID
|
||||
}
|
||||
|
||||
public := args.IncludePublic != nil && *args.IncludePublic == true
|
||||
|
||||
mimeTypes := []string(nil)
|
||||
if args.MimeTypes != nil {
|
||||
mimeTypes = *args.MimeTypes
|
||||
}
|
||||
|
||||
files, err := file.List(author, public, mimeTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolvers := make([]*types.FileResolver, len(files))
|
||||
for i := range files {
|
||||
resolvers[i] = &types.FileResolver{F: files[i]}
|
||||
}
|
||||
|
||||
return resolvers, nil
|
||||
}
|
||||
|
||||
// FileEditArgs is args for the editFile mutation
|
||||
type FileEditArgs struct {
|
||||
Input *struct {
|
||||
ID string
|
||||
Name *string
|
||||
Public *bool
|
||||
}
|
||||
}
|
||||
|
||||
// EditFile resolves the editFile mutation
|
||||
func (r *MutationResolver) EditFile(ctx context.Context, args *FileEditArgs) (*types.FileResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
file, err := file.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if file.Author != user.ID && !user.Permitted("file.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
err = file.Edit(input.Name, input.Public)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.FileResolver{F: file}, nil
|
||||
}
|
||||
|
||||
// RemoveFile resolves the removeFIle mutation
|
||||
func (r *MutationResolver) RemoveFile(ctx context.Context, args *FileArgs) (*types.FileResolver, error) {
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
file, err := file.FindID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if file.Author != user.ID && !user.Permitted("file.remove") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
err = file.Delete()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.FileResolver{F: file}, nil
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/model/change"
|
||||
|
||||
"git.aiterp.net/rpdata/api/internal/session"
|
||||
"git.aiterp.net/rpdata/api/model/log"
|
||||
)
|
||||
|
||||
// LogArgs is an arg
|
||||
type LogArgs struct {
|
||||
ID *string
|
||||
}
|
||||
|
||||
// Log finds log
|
||||
func (r *QueryResolver) Log(ctx context.Context, args *LogArgs) (*types.LogResolver, error) {
|
||||
var l log.Log
|
||||
var err error
|
||||
|
||||
switch {
|
||||
case args.ID != nil:
|
||||
l, err = log.FindID(*args.ID)
|
||||
default:
|
||||
err = ErrCannotResolve
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.LogResolver{L: l}, nil
|
||||
}
|
||||
|
||||
// LogQueryArgs is args for the logs query
|
||||
type LogQueryArgs struct {
|
||||
Filter *struct {
|
||||
Search *string
|
||||
Characters *[]string
|
||||
Channels *[]string
|
||||
Events *[]string
|
||||
Open *bool
|
||||
Limit *int32
|
||||
}
|
||||
}
|
||||
|
||||
// Logs resolves the logs query
|
||||
func (r *QueryResolver) Logs(ctx context.Context, args *LogQueryArgs) ([]*types.LogResolver, error) {
|
||||
var logs []log.Log
|
||||
var err error
|
||||
|
||||
filter := args.Filter
|
||||
|
||||
if filter != nil {
|
||||
limit := 100
|
||||
search := ""
|
||||
|
||||
if filter.Search != nil {
|
||||
search = *filter.Search
|
||||
limit = 0
|
||||
}
|
||||
|
||||
channels := []string(nil)
|
||||
if filter.Channels != nil {
|
||||
channels = *filter.Channels
|
||||
limit = 0
|
||||
}
|
||||
|
||||
characters := []string(nil)
|
||||
if filter.Characters != nil {
|
||||
characters = *filter.Characters
|
||||
limit = 0
|
||||
}
|
||||
|
||||
events := []string(nil)
|
||||
if filter.Events != nil {
|
||||
events = *filter.Events
|
||||
limit = 0
|
||||
}
|
||||
|
||||
if filter.Limit != nil {
|
||||
limit = int(*filter.Limit)
|
||||
}
|
||||
|
||||
open := filter.Open != nil && *filter.Open == true
|
||||
|
||||
logs, err = log.ListSearch(search, channels, characters, events, open, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
logs, err = log.List(100)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
resolvers := make([]*types.LogResolver, len(logs))
|
||||
for i := range logs {
|
||||
resolvers[i] = &types.LogResolver{L: logs[i]}
|
||||
}
|
||||
|
||||
return resolvers, nil
|
||||
}
|
||||
|
||||
// LogAddArgs is args for the addLog mutation
|
||||
type LogAddArgs struct {
|
||||
Input *struct {
|
||||
Date string
|
||||
Channel string
|
||||
Title *string
|
||||
Open *bool
|
||||
Event *string
|
||||
Description *string
|
||||
}
|
||||
}
|
||||
|
||||
// AddLog resolves the addLog mutation
|
||||
func (r *MutationResolver) AddLog(ctx context.Context, args *LogAddArgs) (*types.LogResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("log.add") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
date, err := time.Parse(time.RFC3339Nano, args.Input.Date)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
title := ""
|
||||
if input.Title != nil {
|
||||
title = *input.Title
|
||||
}
|
||||
|
||||
event := ""
|
||||
if input.Event != nil {
|
||||
event = *input.Event
|
||||
}
|
||||
|
||||
description := ""
|
||||
if input.Description != nil {
|
||||
description = *input.Description
|
||||
}
|
||||
|
||||
open := input.Open != nil && *input.Open == true
|
||||
|
||||
log, err := log.New(date, input.Channel, title, event, description, open)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Log", "add", user.ID, log.ID, map[string]interface{}{
|
||||
"channel": log.Channel,
|
||||
"title": log.Title,
|
||||
"event": log.Event,
|
||||
"description": log.Description,
|
||||
"open": log.Open,
|
||||
})
|
||||
|
||||
return &types.LogResolver{L: log}, nil
|
||||
}
|
||||
|
||||
// LogEditArgs is an input
|
||||
type LogEditArgs struct {
|
||||
Input *struct {
|
||||
ID string
|
||||
Title *string
|
||||
Event *string
|
||||
Description *string
|
||||
Open *bool
|
||||
}
|
||||
}
|
||||
|
||||
// EditLog resolves the editLog mutation
|
||||
func (r *MutationResolver) EditLog(ctx context.Context, args *LogEditArgs) (*types.LogResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("log.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
log, err := log.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = log.Edit(input.Title, input.Event, input.Description, input.Open)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Log", "edit", user.ID, log.ID, map[string]interface{}{
|
||||
"channel": log.Channel,
|
||||
"title": input.Title,
|
||||
"event": input.Event,
|
||||
"description": input.Description,
|
||||
"open": input.Open,
|
||||
})
|
||||
|
||||
return &types.LogResolver{L: log}, nil
|
||||
}
|
||||
|
||||
// RemoveLog resolves the removeLog mutation
|
||||
func (r *MutationResolver) RemoveLog(ctx context.Context, args *struct{ ID string }) (*types.LogResolver, error) {
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("log.remove") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
log, err := log.FindID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = log.Remove()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Log", "remove", user.ID, log.ID, nil)
|
||||
|
||||
return &types.LogResolver{L: log}, nil
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package mutations
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member", "chapter.add") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
story, err := story.FindID(input.StoryID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
author := token.UserID
|
||||
if input.Author != nil {
|
||||
author = *input.Author
|
||||
|
||||
if token.UserID != author && !token.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", token.UserID, 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/auth"
|
||||
"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
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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 := token.UserID
|
||||
if input.Author != nil {
|
||||
author = *input.Author
|
||||
|
||||
if author != token.UserID && !token.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", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
character, err := character.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if character.Author != token.UserID && !token.Permitted("character.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = character.AddNick(input.Nick)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Character", "add.nick", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member", "story.add") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
author := token.UserID
|
||||
if input.Author != nil {
|
||||
author = *input.Author
|
||||
|
||||
if token.UserID != author && !token.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", token.UserID, 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/auth"
|
||||
"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}
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member", "story.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
story, err := story.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story.Author != token.UserID && !token.Permitted("story.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = story.AddTag(tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Story", "add.tag", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member", "chapter.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
chapter, err := story.FindChapterID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if chapter.Author != token.UserID && !token.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", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
character, err := character.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if character.Author != token.UserID && !token.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", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
file, err := file.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if file.Author != token.UserID && !token.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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member", "story.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
story, err := story.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story.Author != token.UserID && !token.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", token.UserID, 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,45 @@
|
||||
package mutations
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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", token.UserID, 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/auth"
|
||||
"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) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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", token.UserID, 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/auth"
|
||||
"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) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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", token.UserID, 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/auth"
|
||||
"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) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
character, err := character.FindID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if character.Author != token.UserID && !token.Permitted("character.remove") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = character.Remove()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Character", "remove", token.UserID, 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/auth"
|
||||
"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
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
character, err := character.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if character.Author != token.UserID && !token.Permitted("character.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = character.RemoveNick(input.Nick)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Character", "remove.nick", token.UserID, 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/auth"
|
||||
"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) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
file, err := file.FindID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if file.Author != token.UserID && !token.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/auth"
|
||||
"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) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.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", token.UserID, 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/auth"
|
||||
"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) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("post.remove") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
post, err := log.RemovePost(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Post", "remove", token.UserID, 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/auth"
|
||||
"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) {
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member", "story.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
story, err := story.FindID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story.Author != token.UserID && !token.Permitted("story.remove") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = story.Remove()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Story", "remove", token.UserID, 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/auth"
|
||||
"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}
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
if !token.Permitted("member", "story.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
story, err := story.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story.Author != token.UserID && !token.Permitted("story.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = story.RemoveTag(tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Story", "remove.tag", token.UserID, 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")
|
||||
@@ -1,208 +0,0 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/internal/session"
|
||||
"git.aiterp.net/rpdata/api/model/change"
|
||||
"git.aiterp.net/rpdata/api/model/log"
|
||||
)
|
||||
|
||||
// PostArgs is an arg
|
||||
type PostArgs struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
// Post implements the post query
|
||||
func (r *QueryResolver) Post(ctx context.Context, args *PostArgs) (*types.PostResolver, error) {
|
||||
post, err := log.FindPostID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.PostResolver{P: post}, nil
|
||||
}
|
||||
|
||||
// PostsArgs is an arg
|
||||
type PostsArgs struct {
|
||||
IDs []string
|
||||
}
|
||||
|
||||
// Posts implements the posts query
|
||||
func (r *QueryResolver) Posts(ctx context.Context, args *PostsArgs) ([]*types.PostResolver, error) {
|
||||
posts, err := log.ListPostIDs(args.IDs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolvers := make([]*types.PostResolver, len(posts))
|
||||
for i := range resolvers {
|
||||
resolvers[i] = &types.PostResolver{P: posts[i]}
|
||||
}
|
||||
|
||||
return resolvers, nil
|
||||
}
|
||||
|
||||
// PostAddArgs is args for addPost mutation
|
||||
type PostAddArgs struct {
|
||||
Input *struct {
|
||||
LogID string
|
||||
Time string
|
||||
Kind string
|
||||
Nick string
|
||||
Text string
|
||||
}
|
||||
}
|
||||
|
||||
// AddPost resolves the addPost mutation
|
||||
func (r *MutationResolver) AddPost(ctx context.Context, args *PostAddArgs) (*types.PostResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("post.add") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
postTime, err := time.Parse(time.RFC3339Nano, input.Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log, err := log.FindID(input.LogID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
post, err := log.NewPost(postTime, input.Kind, input.Nick, input.Text)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Post", "add", user.ID, post.ID, map[string]interface{}{
|
||||
"logId": post.LogID,
|
||||
"time": post.Time,
|
||||
"kind": post.Kind,
|
||||
"nick": post.Nick,
|
||||
"text": post.Text,
|
||||
"position": post.Position,
|
||||
})
|
||||
|
||||
go log.UpdateCharacters()
|
||||
|
||||
return &types.PostResolver{P: post}, nil
|
||||
}
|
||||
|
||||
// PostEditArgs is args for the editPost mutation
|
||||
type PostEditArgs struct {
|
||||
Input *struct {
|
||||
ID string
|
||||
Time *string
|
||||
Kind *string
|
||||
Nick *string
|
||||
Text *string
|
||||
}
|
||||
}
|
||||
|
||||
// EditPost resolves the editPost mutation
|
||||
func (r *MutationResolver) EditPost(ctx context.Context, args *PostEditArgs) (*types.PostResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("post.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
postTime := (*time.Time)(nil)
|
||||
if args.Input.Time != nil {
|
||||
t, err := time.Parse(time.RFC3339Nano, *input.Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
postTime = &t
|
||||
}
|
||||
|
||||
post, err := log.FindPostID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = post.Edit(postTime, input.Kind, input.Nick, input.Text)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Post", "edit", user.ID, post.ID, map[string]interface{}{
|
||||
"time": postTime,
|
||||
"kind": input.Kind,
|
||||
"nick": input.Nick,
|
||||
"text": input.Text,
|
||||
})
|
||||
|
||||
go log.UpdateCharacters(post.LogID)
|
||||
|
||||
return &types.PostResolver{P: post}, nil
|
||||
}
|
||||
|
||||
// PostMoveArgs is args for movePost mutation
|
||||
type PostMoveArgs struct {
|
||||
Input *struct {
|
||||
ID string
|
||||
ToPosition int32
|
||||
}
|
||||
}
|
||||
|
||||
// MovePost resolves the movePost mutation
|
||||
func (r *MutationResolver) MovePost(ctx context.Context, args *PostMoveArgs) (*types.PostResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("post.move") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
post, err := log.FindPostID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = post.Move(int(input.ToPosition))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Post", "move", user.ID, post.ID, map[string]interface{}{
|
||||
"logId": post.LogID,
|
||||
"targetIndex": input.ToPosition,
|
||||
})
|
||||
|
||||
return &types.PostResolver{P: post}, nil
|
||||
}
|
||||
|
||||
// PostRemoveArgs is an arg
|
||||
type PostRemoveArgs struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
// RemovePost resolves the removePost mutation
|
||||
func (r *MutationResolver) RemovePost(ctx context.Context, args PostRemoveArgs) (*types.PostResolver, error) {
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("post.remove") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
post, err := log.RemovePost(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Post", "remove", user.ID, post.ID, map[string]interface{}{
|
||||
"logId": post.LogID,
|
||||
})
|
||||
|
||||
go log.UpdateCharacters(post.LogID)
|
||||
|
||||
return &types.PostResolver{P: post}, nil
|
||||
}
|
||||
@@ -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,60 @@
|
||||
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
|
||||
Logged *bool
|
||||
}
|
||||
}
|
||||
|
||||
// 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, filter.Logged)
|
||||
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/auth"
|
||||
"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
|
||||
token := auth.TokenFromContext(ctx)
|
||||
|
||||
author := ""
|
||||
if token != nil {
|
||||
author = token.UserID
|
||||
}
|
||||
|
||||
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,49 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/loader"
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/model/log"
|
||||
)
|
||||
|
||||
// LogsArgs is args for the logs query
|
||||
type LogsArgs struct {
|
||||
Filter *log.Filter
|
||||
}
|
||||
|
||||
// Logs resolves the logs query
|
||||
func (r *QueryResolver) Logs(ctx context.Context, args *LogsArgs) ([]*types.LogResolver, error) {
|
||||
var logs []log.Log
|
||||
|
||||
filter := args.Filter
|
||||
if filter == nil {
|
||||
filter = log.NewFilter().WithLimit(100)
|
||||
}
|
||||
|
||||
logs, err := log.List(filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(logs) >= 100 {
|
||||
loader := loader.FromContext(ctx)
|
||||
if loader == nil {
|
||||
return nil, errors.New("no loader")
|
||||
}
|
||||
|
||||
for _, log := range logs {
|
||||
loader.PrimeCharacters("id", log.CharacterIDs...)
|
||||
loader.PrimeChannels("name", log.Channel)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
package resolver
|
||||
// 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")
|
||||
|
||||
// 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")
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/internal/auth"
|
||||
"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
|
||||
Category *string
|
||||
Limit *int32
|
||||
Open *bool
|
||||
Unlisted *bool
|
||||
}
|
||||
}
|
||||
|
||||
// Stories resolves the stories query
|
||||
func (r *QueryResolver) Stories(ctx context.Context, args *StoriesArg) ([]*types.StoryResolver, error) {
|
||||
var err error
|
||||
|
||||
token := auth.TokenFromContext(ctx)
|
||||
|
||||
filter := args.Filter
|
||||
|
||||
author := ""
|
||||
category := ""
|
||||
tags := make([]story.Tag, 0, 8)
|
||||
earliest := time.Time{}
|
||||
latest := time.Time{}
|
||||
unlisted := false
|
||||
open := (*bool)(nil)
|
||||
limit := 0
|
||||
|
||||
if filter != nil {
|
||||
if filter.Author != nil {
|
||||
author = *filter.Author
|
||||
}
|
||||
|
||||
if filter.Category != nil {
|
||||
category = *filter.Category
|
||||
}
|
||||
|
||||
if filter.Tags != nil {
|
||||
for _, tagInput := range *filter.Tags {
|
||||
tags = append(tags, story.Tag{
|
||||
Kind: tagInput.Kind,
|
||||
Name: tagInput.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if filter.EarliestFictionalDate != nil {
|
||||
earliest, err = time.Parse(time.RFC3339Nano, *filter.EarliestFictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if filter.LatestFictionalDate != nil {
|
||||
latest, err = time.Parse(time.RFC3339Nano, *filter.LatestFictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if filter.Limit != nil {
|
||||
limit = int(*filter.Limit)
|
||||
}
|
||||
|
||||
unlisted = filter.Unlisted != nil && *filter.Unlisted == true
|
||||
if unlisted {
|
||||
if token == nil {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
if author != "" && author != token.UserID && !token.Permitted("story.unlisted") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
author = token.UserID
|
||||
}
|
||||
|
||||
open = filter.Open
|
||||
}
|
||||
|
||||
stories, err := story.List(author, category, tags, earliest, latest, unlisted, open, 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
|
||||
}
|
||||
@@ -1,17 +1,11 @@
|
||||
package resolver
|
||||
package queries
|
||||
|
||||
import (
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/model/story"
|
||||
)
|
||||
|
||||
// TagInput resolves the TagInput input
|
||||
type TagInput struct {
|
||||
Kind string
|
||||
Name string
|
||||
}
|
||||
|
||||
// Tags implements the tags query
|
||||
// Tags resolves the tags query
|
||||
func (r *QueryResolver) Tags() ([]*types.TagResolver, error) {
|
||||
tags, err := story.ListTags()
|
||||
if err != 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
|
||||
}
|
||||
@@ -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,39 +0,0 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/internal/session"
|
||||
)
|
||||
|
||||
// LoginArgs is args
|
||||
type LoginArgs struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// Session resolves query.session
|
||||
func (r *QueryResolver) Session(ctx context.Context) (*types.SessionResolver, error) {
|
||||
return &types.SessionResolver{S: session.FromContext(ctx)}, nil
|
||||
}
|
||||
|
||||
// Login resolves mutation.login
|
||||
func (r *MutationResolver) Login(ctx context.Context, args *LoginArgs) (*types.SessionResolver, error) {
|
||||
session := session.FromContext(ctx)
|
||||
|
||||
err := session.Login(args.Username, args.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.SessionResolver{S: session}, nil
|
||||
}
|
||||
|
||||
// Logout resolves mutation.logout
|
||||
func (r *MutationResolver) Logout(ctx context.Context) (*types.SessionResolver, error) {
|
||||
session := session.FromContext(ctx)
|
||||
session.Logout()
|
||||
|
||||
return &types.SessionResolver{S: session}, nil
|
||||
}
|
||||
@@ -1,329 +0,0 @@
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.aiterp.net/rpdata/api/graphql/resolver/types"
|
||||
"git.aiterp.net/rpdata/api/internal/session"
|
||||
"git.aiterp.net/rpdata/api/model/change"
|
||||
"git.aiterp.net/rpdata/api/model/story"
|
||||
)
|
||||
|
||||
// StoryArgs is args for story query
|
||||
type StoryArgs struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
// Story implements the story query
|
||||
func (r *QueryResolver) Story(ctx context.Context, args *StoryArgs) (*types.StoryResolver, error) {
|
||||
story, err := story.FindID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.StoryResolver{S: story}, nil
|
||||
}
|
||||
|
||||
// StoriesArg is args for stories query
|
||||
type StoriesArg struct {
|
||||
Filter *struct {
|
||||
Author *string
|
||||
Tags *[]TagInput
|
||||
EarliestFictionalDate *string
|
||||
LatestFictionalDate *string
|
||||
Limit *int32
|
||||
}
|
||||
}
|
||||
|
||||
// Stories implements the stories query
|
||||
func (r *QueryResolver) Stories(ctx context.Context, args *StoriesArg) ([]*types.StoryResolver, error) {
|
||||
filter := args.Filter
|
||||
|
||||
author := ""
|
||||
if filter != nil && filter.Author != nil {
|
||||
author = *filter.Author
|
||||
}
|
||||
|
||||
tags := make([]story.Tag, 0, 8)
|
||||
if filter != nil && filter.Tags != nil {
|
||||
for _, tagInput := range *filter.Tags {
|
||||
tags = append(tags, story.Tag{
|
||||
Kind: tagInput.Kind,
|
||||
Name: tagInput.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
earliest := time.Time{}
|
||||
err := error(nil)
|
||||
if filter != nil && filter.EarliestFictionalDate != nil {
|
||||
earliest, err = time.Parse(time.RFC3339Nano, *filter.EarliestFictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
latest := time.Time{}
|
||||
if filter != nil && filter.LatestFictionalDate != nil {
|
||||
latest, err = time.Parse(time.RFC3339Nano, *filter.LatestFictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
limit := 30
|
||||
if filter != nil && filter.Limit != nil {
|
||||
limit = int(*filter.Limit)
|
||||
}
|
||||
|
||||
stories, err := story.List(author, tags, earliest, latest, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolvers := make([]*types.StoryResolver, len(stories))
|
||||
for i, story := range stories {
|
||||
resolvers[i] = &types.StoryResolver{S: story}
|
||||
}
|
||||
|
||||
return resolvers, nil
|
||||
}
|
||||
|
||||
// StoryAddArgs is args for the addStory mutation
|
||||
type StoryAddArgs struct {
|
||||
Input *struct {
|
||||
Name string
|
||||
Category string
|
||||
Author *string
|
||||
Open *bool
|
||||
Listed *bool
|
||||
Tags *[]TagInput
|
||||
FictionalDate *string
|
||||
}
|
||||
}
|
||||
|
||||
// AddStory implements the addStory mutation
|
||||
func (r *MutationResolver) AddStory(ctx context.Context, args *StoryAddArgs) (*types.StoryResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member", "story.add") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
author := user.ID
|
||||
if input.Author != nil {
|
||||
author = *input.Author
|
||||
|
||||
if user.ID != author && !user.Permitted("story.add") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
}
|
||||
|
||||
listed := (input.Listed != nil && *input.Listed == true)
|
||||
|
||||
open := (input.Open != nil && *input.Open == true)
|
||||
|
||||
tags := make([]story.Tag, 0, 8)
|
||||
if input.Tags != nil {
|
||||
for _, tagInput := range *input.Tags {
|
||||
tags = append(tags, story.Tag{
|
||||
Kind: tagInput.Kind,
|
||||
Name: tagInput.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fictionalDate := time.Time{}
|
||||
if input.FictionalDate != nil {
|
||||
date, err := time.Parse(time.RFC3339Nano, *input.FictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fictionalDate = date
|
||||
}
|
||||
|
||||
story, err := story.New(input.Name, author, input.Category, listed, open, tags, time.Now(), fictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Story", "add", user.ID, story.ID, map[string]interface{}{
|
||||
"name": input.Name,
|
||||
"category": input.Category,
|
||||
"author": input.Author,
|
||||
})
|
||||
|
||||
return &types.StoryResolver{S: story}, nil
|
||||
}
|
||||
|
||||
// StoryTagAddArgs is args for the addStoryTag mutation
|
||||
type StoryTagAddArgs struct {
|
||||
Input *struct {
|
||||
ID string
|
||||
Tag TagInput
|
||||
}
|
||||
}
|
||||
|
||||
// AddStoryTag implements the addStoryTag mutation
|
||||
func (r *MutationResolver) AddStoryTag(ctx context.Context, args *StoryTagAddArgs) (*types.StoryResolver, error) {
|
||||
input := args.Input
|
||||
tag := story.Tag{Kind: input.Tag.Kind, Name: input.Tag.Name}
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member", "story.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
story, err := story.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story.Author != user.ID && !user.Permitted("story.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = story.AddTag(tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Story", "add.tag", user.ID, story.ID, map[string]interface{}{
|
||||
"kind": tag.Kind,
|
||||
"name": tag.Name,
|
||||
})
|
||||
|
||||
return &types.StoryResolver{S: story}, nil
|
||||
}
|
||||
|
||||
// StoryTagRemoveArgs is args for the removeStoryTag mutation
|
||||
type StoryTagRemoveArgs struct {
|
||||
Input *struct {
|
||||
ID string
|
||||
Tag TagInput
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveStoryTag implements the removeStoryTag mutation
|
||||
func (r *MutationResolver) RemoveStoryTag(ctx context.Context, args *StoryTagRemoveArgs) (*types.StoryResolver, error) {
|
||||
input := args.Input
|
||||
tag := story.Tag{Kind: input.Tag.Kind, Name: input.Tag.Name}
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member", "story.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
story, err := story.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story.Author != user.ID && !user.Permitted("story.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = story.RemoveTag(tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Story", "remove.tag", user.ID, story.ID, map[string]interface{}{
|
||||
"kind": tag.Kind,
|
||||
"name": tag.Name,
|
||||
})
|
||||
|
||||
return &types.StoryResolver{S: story}, nil
|
||||
}
|
||||
|
||||
// StoryEditArgs is args for the addStory mutation
|
||||
type StoryEditArgs struct {
|
||||
Input *struct {
|
||||
ID string
|
||||
Name *string
|
||||
Category *string
|
||||
Author *string
|
||||
Open *bool
|
||||
Listed *bool
|
||||
FictionalDate *string
|
||||
}
|
||||
}
|
||||
|
||||
// EditStory implements the editStory mutation
|
||||
func (r *MutationResolver) EditStory(ctx context.Context, args *StoryEditArgs) (*types.StoryResolver, error) {
|
||||
input := args.Input
|
||||
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member", "story.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
story, err := story.FindID(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story.Author != user.ID && !user.Permitted("story.edit") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
var fictionalDate *time.Time
|
||||
if input.FictionalDate != nil {
|
||||
date, err := time.Parse(time.RFC3339Nano, *input.FictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fictionalDate = &date
|
||||
}
|
||||
|
||||
err = story.Edit(input.Name, input.Category, input.Listed, input.Open, fictionalDate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Story", "edit", user.ID, story.ID, map[string]interface{}{
|
||||
"name": input.Name,
|
||||
"category": input.Category,
|
||||
"author": input.Author,
|
||||
"open": input.Open,
|
||||
"listed": input.Listed,
|
||||
"fictionalDate": input.FictionalDate,
|
||||
})
|
||||
|
||||
return &types.StoryResolver{S: story}, nil
|
||||
}
|
||||
|
||||
// StoryRemoveArgs is args for the removeStory mutation
|
||||
type StoryRemoveArgs struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
// RemoveStory implements the removeStory mutation
|
||||
func (r *MutationResolver) RemoveStory(ctx context.Context, args *StoryRemoveArgs) (*types.StoryResolver, error) {
|
||||
user := session.FromContext(ctx).User()
|
||||
if user == nil || !user.Permitted("member", "story.edit") {
|
||||
return nil, ErrUnauthorized
|
||||
}
|
||||
|
||||
story, err := story.FindID(args.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if story.Author != user.ID && !user.Permitted("story.remove") {
|
||||
return nil, ErrPermissionDenied
|
||||
}
|
||||
|
||||
err = story.Remove()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go change.Submit("Story", "remove", user.ID, story.ID, nil)
|
||||
|
||||
return &types.StoryResolver{S: story}, nil
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
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}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package types
|
||||
|
||||
import "git.aiterp.net/rpdata/api/internal/session"
|
||||
|
||||
// UserResolver resulves the user type
|
||||
type UserResolver struct{ U *session.User }
|
||||
|
||||
// ID resolves User.id
|
||||
func (r *UserResolver) ID() string {
|
||||
return r.U.ID
|
||||
}
|
||||
|
||||
// Permissions resolves User.permissions
|
||||
func (r *UserResolver) Permissions() []string {
|
||||
return r.U.Permissions
|
||||
}
|
||||
@@ -1,490 +0,0 @@
|
||||
// Code generated by go-bindata.
|
||||
// sources:
|
||||
// root.graphql
|
||||
// types/change.graphql
|
||||
// types/channel.graphql
|
||||
// types/chapter.graphql
|
||||
// types/character.graphql
|
||||
// types/file.graphql
|
||||
// types/log.graphql
|
||||
// types/post.graphql
|
||||
// types/session.graphql
|
||||
// types/story.graphql
|
||||
// types/tag.graphql
|
||||
// types/user.graphql
|
||||
// DO NOT EDIT!
|
||||
|
||||
package schema
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, gz)
|
||||
clErr := gz.Close()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||
}
|
||||
if clErr != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
type asset struct {
|
||||
bytes []byte
|
||||
info os.FileInfo
|
||||
}
|
||||
|
||||
type bindataFileInfo struct {
|
||||
name string
|
||||
size int64
|
||||
mode os.FileMode
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
func (fi bindataFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
func (fi bindataFileInfo) Size() int64 {
|
||||
return fi.size
|
||||
}
|
||||
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||
return fi.mode
|
||||
}
|
||||
func (fi bindataFileInfo) ModTime() time.Time {
|
||||
return fi.modTime
|
||||
}
|
||||
func (fi bindataFileInfo) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
func (fi bindataFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _rootGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x57\xcd\x6e\xeb\x38\x0f\xdd\xfb\x29\x18\x74\xd1\x14\x08\xf2\x00\xd9\xf5\xeb\xbd\xc5\x17\x20\x9d\xe9\x4c\x32\xab\xa2\xc0\x55\x6d\xc6\x26\xaa\x48\x1e\x51\x6e\x10\x5c\xdc\x77\x1f\x50\xf2\x8f\xec\x3a\x1d\x60\x76\xa6\x4c\x1e\x1e\x52\xf4\x61\x72\x03\x87\x0a\xe1\x8f\x06\xdd\x05\xfc\xa5\x46\x70\x58\x3b\x64\x34\x9e\xc1\x57\x62\xaa\x02\xd0\x78\x77\x81\xda\x92\x9c\x92\xf1\x36\xbc\xba\x7f\xde\xae\xb3\x10\x13\xc3\x7f\x66\x00\x37\xf0\x48\xa6\x80\xbc\x52\x4e\xe5\x1e\x1d\xbc\x5d\x00\xc9\x57\xe8\x40\x19\xd8\x7e\x03\xeb\x40\x81\xa1\xfc\x7d\x9d\xc1\xe0\xb6\xa4\x62\x03\x7b\xef\xc8\x94\xab\xf0\xb6\xb3\xee\x36\xf0\xd0\x39\x65\x33\xf8\x9c\x26\x00\x4d\xec\xc1\x1e\x81\x0a\x8e\x30\x1c\xf2\x19\x50\x8d\xaf\xac\x5b\xc3\xef\x46\x5f\xc0\x1a\x84\x5a\x39\x75\x42\x21\xa8\x3c\x28\xf0\x74\xc2\x94\x0f\x2f\xa9\xe0\x0d\xbc\x44\x12\x8b\xd7\x16\x6d\x74\x12\x31\x13\xa2\x2f\x3d\xd3\xc5\xeb\x22\x03\x18\xf3\x35\x06\xb5\x90\x35\xaa\x4b\x25\x27\x4b\x31\x3b\x8c\x45\xac\x56\xce\x93\x58\xa5\x75\xe7\xcd\x6b\xd8\xd7\x98\xd3\xf1\x42\xa6\x84\x1f\xda\x96\x25\x16\x1b\xf0\xae\xc1\x1f\xe0\x90\xbd\xa3\xbc\xbd\x37\x46\xe5\xf2\x0a\xbc\x05\x2b\x35\x47\xd7\xf5\x90\x98\x97\x5d\xf4\xff\xac\xd5\xa8\x4c\x5b\x80\xbc\x5b\xbc\x2e\x00\xc6\x05\x68\x5b\x0a\xf9\xed\xb7\x0c\xe4\x39\xb9\xaf\xbb\x0d\xec\x6c\x39\x76\xe5\xe8\xc5\xcb\x23\x69\x8f\x2e\x78\xf0\x63\x78\x96\x34\x3b\x5b\xfe\x1f\x55\x11\xfb\x94\x44\xd6\x96\x7d\xcc\x22\x44\xc5\x4a\xf2\x48\x73\x9e\x2d\xfb\x89\x3f\xc7\x00\x5e\xc3\xd6\xdf\x32\x9c\x50\x19\x2f\x55\x2b\xad\xed\x19\x6c\x18\x8c\x5a\x39\xcf\x32\x17\xd2\x98\xbf\xb6\xf2\x5a\x93\x79\x0f\x6e\x90\xeb\x86\x65\x0e\xec\x31\xe2\xad\x00\xd7\xe5\x1a\x8e\x61\x50\x9d\xb5\x27\x28\x90\x73\x47\xb5\x27\x6b\xc2\xb1\xaf\x30\x70\x78\x52\x75\x0d\x5c\xd9\x46\x17\x40\x1e\xf0\x43\xc6\x1d\x73\x7b\x42\x99\xa8\x8a\x4c\xb9\x86\x43\x45\x0c\x85\x45\x06\x63\x3d\x54\xea\x43\xde\xc5\xae\xac\x80\xc9\xe4\x08\x34\xe2\xfd\x86\xf0\x77\x83\x8e\xb0\x00\x32\x81\xb0\x34\xf2\x56\x6e\xb7\xb6\x86\xf1\x96\x81\x51\x63\x1e\xd8\x30\xfa\xae\x53\xd3\x89\x95\x76\xbd\x48\xbf\x26\x3d\x3e\x92\xc6\xfe\x26\xc5\x98\xb4\xf8\x91\x34\x76\xee\x1a\x19\x4a\xf4\x61\x02\xd5\x87\x22\xad\xde\x34\x86\x20\x69\xf7\x11\xc8\xe4\xba\x29\xf0\xb9\x79\xd3\x94\x03\x09\x33\xbf\x92\x56\x9c\x49\x6b\x70\xe8\x1b\x67\xa0\x8e\x6f\x43\x14\x28\x86\x33\x6a\xdd\xa6\xe6\xe5\x08\xa1\x1f\xc5\x15\x9c\xe8\x84\x87\x4b\x8d\x69\x45\x52\x90\x70\x9a\x14\xc4\xde\xba\x4b\x5f\x51\xb0\x26\x25\xed\xe5\x6c\x12\x41\xc8\xad\x37\xe1\x30\xa6\xfb\x68\x0f\x93\x1a\x42\x67\x13\xe6\x95\xaa\x5b\x7d\x0b\x89\x5b\x7b\x92\xfa\x21\x9e\x66\x93\xcf\xb9\x20\xf6\x64\x72\x0f\x5e\x95\x0c\x0d\xc7\xcb\x1e\x78\xc9\xf1\x06\x5e\x0e\xaa\x9c\xe4\xce\x1b\xe7\xd0\x78\x60\x64\x26\x6b\xa4\x84\xf8\xb4\x81\x7d\x7c\x58\x64\xbf\xb2\x2c\x8a\xfa\x53\xe3\x55\x18\x93\xa9\xae\x9f\x1d\x79\xfc\x57\x51\xef\xc3\xa3\xae\xdf\x17\x85\x28\x37\x9e\x07\x95\xcc\x00\x54\x51\x3c\x0c\x22\x6e\xea\xc6\x27\x82\x7d\x5f\x14\x5b\x39\x5a\xa4\x2a\xbe\xc8\x7a\x38\xd1\x54\x99\xf9\x6b\x80\xbf\x51\xfe\xfe\x09\x54\x0e\xe7\x50\x83\x62\xdd\xc0\x9f\x78\xb2\x1f\x18\xa1\x8f\xce\x9e\x46\xe0\x2e\xbc\xfc\x6f\xf8\x01\xfd\x7b\x41\x7e\x84\x88\x05\xf9\xeb\x0d\x10\xf7\xab\x58\x2d\x53\xf5\x15\xc3\xcf\xe3\xd4\x43\x24\x97\xd2\x4a\x7a\xdf\xbd\xb0\x58\x06\x2e\x62\x4e\xae\x22\xa8\x7c\x52\x52\x8a\xd1\x96\x34\x03\x32\x2d\x27\x41\x49\x8b\x69\x71\xfa\x52\xbe\xda\x73\xe3\x42\x64\xba\xb4\x2d\x63\x21\x3b\x59\x33\x31\xff\xce\x96\x69\x01\x3b\x5b\x8e\xc9\xc7\x18\x21\x3e\x0e\x1a\x11\x1e\xa2\x7a\xb2\x31\x2e\x12\xdd\x8d\xb6\xda\x10\x90\xd0\x13\x9d\x8d\xdc\x9e\xc3\x6e\x8a\x79\xee\xa3\xd9\xe7\x09\xa2\x3b\xa2\xd7\xc6\x09\xbf\x34\xf0\x7b\x6b\xcf\x45\x3e\x45\x82\x6d\xa4\xf0\x4b\x23\x9f\x5a\x7b\x2e\xb2\x2f\xae\x8d\x8d\xd5\x3d\xcf\x2f\xd3\xae\xbe\x96\xa8\x88\x72\x4b\xf4\x31\xac\x86\x81\xa8\xd8\x7d\xba\x20\xc3\x93\x74\x6d\x6c\x4c\xf7\x38\xbf\x58\xc6\xed\x0c\x42\x1a\xfb\xb9\x8f\xb2\x1d\xd3\x05\x23\xbd\xef\xa8\xc2\xdd\x17\x9e\x04\x8b\x50\x26\x00\x07\x55\x8e\x30\x0e\xaa\xbc\x0e\xd3\x13\x4f\x91\x22\xfb\x6b\x60\x31\xe4\x0a\x5e\xdb\xc2\xae\x28\xe9\xe1\xe7\xaa\x46\x03\xf9\x15\x9f\x31\x97\xb9\x85\xf6\x49\x02\xc2\x3a\x0a\x3f\x69\x92\xc6\x3e\x74\x6b\xa9\xff\x90\xeb\xcf\xc2\x5c\x4f\x04\xae\x87\x1b\xd4\x60\x06\x64\xaa\x06\xf5\xbc\xb4\xd5\x13\x61\xbb\xbe\x25\xbb\x8a\x76\xb6\x04\x32\xf1\x27\x24\x99\x65\xc3\xe8\x46\xea\xb1\x82\x5a\x31\x9f\xad\x1b\x37\xa5\xdb\x7f\x6d\x3f\x05\xc5\x36\x3e\xc2\xd8\xc6\x2f\xef\xc6\x3b\x92\xf3\x0a\x4f\x0a\x7e\x8a\xb7\xfc\xe2\xba\x6c\xe2\xdf\x18\xf9\xdc\xda\xcd\xb7\xe9\x77\x60\xf6\xeb\x9f\x00\x00\x00\xff\xff\x7a\x45\x45\x35\x28\x0d\x00\x00")
|
||||
|
||||
func rootGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_rootGraphql,
|
||||
"root.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func rootGraphql() (*asset, error) {
|
||||
bytes, err := rootGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "root.graphql", size: 3368, mode: os.FileMode(420), modTime: time.Unix(1531585622, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesChangeGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x34\xcc\x21\xae\x02\x31\x18\x85\x51\xdf\x55\x7c\x2f\xcf\xb3\x00\x1c\x41\xb1\x8c\x9f\xe9\x85\x36\x90\xb6\x99\xde\x11\x13\xc2\xde\x09\x02\x7b\xc4\xf9\xe7\xc4\xb9\x44\xbb\x8b\x3a\x09\x46\xac\xa6\xdf\x70\x11\xa5\x4e\xf7\x75\xc7\x25\xcc\x12\x8d\xab\xd8\xa6\x32\xee\x3c\xa4\xc1\xf2\xac\x6a\x9e\x6c\xe3\x4b\x39\xac\x43\xf2\x3e\xf4\x1b\x5f\x09\x6a\x3e\x72\x69\xfe\x4b\xef\x4f\x00\x00\x00\xff\xff\xac\xbf\xc1\xe6\x6b\x00\x00\x00")
|
||||
|
||||
func typesChangeGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesChangeGraphql,
|
||||
"types/change.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesChangeGraphql() (*asset, error) {
|
||||
bytes, err := typesChangeGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/change.graphql", size: 107, mode: os.FileMode(420), modTime: time.Unix(1525610729, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesChannelGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x90\x31\x4b\xc4\x40\x10\x85\xfb\xfd\x15\x4f\xae\xb0\xf1\x17\x5c\xa7\x87\x45\x1a\x0b\x15\x6c\x6f\x93\x9d\x64\x07\xf6\x66\x42\x76\x56\x10\xf1\xbf\x4b\xf6\x8c\xa7\x16\x72\x78\x95\x70\x55\xf2\xd8\x37\x8f\x8f\x6f\x85\x46\x7a\x9d\x76\xde\x58\x05\xbe\xd5\x62\xf0\x82\xe6\x7e\x83\x2e\x7a\x11\x4a\xce\x5e\x46\xc2\x66\x1f\xf0\xea\x80\x15\x1e\x23\x2d\xcf\x97\x19\xe2\x77\xe4\x50\x3f\x6b\x3c\xd8\xc4\x32\x5c\xb8\xda\x7b\x8a\x64\x91\x26\xd8\xa1\x8f\x1c\xb5\xa4\x80\x96\x90\x74\x18\x28\x38\x7c\xfc\xac\x71\xa3\x9a\xc8\xcb\x2f\xc7\x9c\xe1\x11\x4b\xfb\x09\x87\x39\xfd\xbc\x9c\xf1\xe8\x99\xc4\x2a\xd3\x15\x74\xc2\x56\x4a\x4a\x5b\x70\x0f\x51\xa1\x79\x27\x8f\xd4\x71\xcf\x15\xa0\x96\xef\xbe\xf0\x1f\x76\x92\x76\x7b\x37\x47\x4e\x2d\xfd\x6f\x6b\x6f\xce\xb1\x8c\xc5\x16\x8d\xd7\x21\x34\x35\x1f\xad\x13\x38\x41\xe8\x9f\x7d\xfe\x13\x9d\xb7\x81\xed\xec\xf3\x04\x9f\xef\x01\x00\x00\xff\xff\xed\x4a\x80\xd4\x06\x04\x00\x00")
|
||||
|
||||
func typesChannelGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesChannelGraphql,
|
||||
"types/channel.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesChannelGraphql() (*asset, error) {
|
||||
bytes, err := typesChannelGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/channel.graphql", size: 1030, mode: os.FileMode(420), modTime: time.Unix(1529172367, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesChapterGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x54\xb1\x6e\xdb\x30\x10\xdd\xf9\x15\xaf\xf0\x90\x25\x75\xf7\x6e\x41\x92\xc1\x53\x87\x04\xe8\x7c\x31\xcf\xd2\xa1\xd2\x51\x20\x4f\x36\x84\xa2\xff\x5e\x90\x94\xa3\x54\xb1\xdd\x49\xc2\xe9\xdd\xe3\xdd\x7b\x4f\xdc\xe0\x01\x8f\x2d\x0d\xc6\x11\x92\x60\x2d\xa3\x27\x51\xec\x83\x1a\xab\xe1\x2d\xf8\x09\xe1\x00\x42\xb2\x10\xa7\xad\xb3\x69\xe0\xf7\x8e\xdf\x0e\xd8\xe0\xb5\x65\xec\x6b\xe5\x2e\x61\xf7\xe4\x00\xf1\xdf\xf1\x62\x51\xb4\xf9\xe2\x2e\x60\x4c\xac\x63\x87\xfa\xbc\x89\xa4\xd1\xda\x10\x1d\xe6\x97\x9b\xd8\x14\xc6\xb8\xcf\xb4\xf5\x65\x85\xfd\xd9\xb2\x96\xfd\xe6\x06\x9c\x28\x61\x08\xc9\xd8\x43\x54\x4c\xa8\x9b\x1c\xb0\x8f\x4c\xc6\xfe\x89\xec\xd2\x60\xa2\x5f\x47\x95\x23\xc7\xc4\xf0\x64\x0c\x52\x0f\x93\x9e\xb3\x46\x1f\xc8\x1d\x70\x90\xbd\x49\x50\xea\xae\x50\x95\xf6\x70\x00\x7b\xb1\xad\x43\x79\xae\xcf\xfd\xe3\xdc\x06\x3b\x1d\x46\xc3\x21\x44\x90\xf7\x67\xe5\xfb\xd1\x28\xd3\x3b\x29\x5f\xe7\xf2\x83\xf7\x15\xbd\x18\x53\x6c\x83\x85\xdc\x0c\x7a\x5f\xde\x42\xd6\x29\x7f\xdb\x5d\xb2\xaa\x18\x93\xbb\x1a\x39\xf2\xc7\xc5\xb6\xd8\x19\xf6\xa4\xd0\x60\x78\x63\x74\x7c\x30\x70\x3f\xd8\x74\xc3\xce\xea\x5d\xa6\x4b\x5c\x37\x59\x33\x9e\xa4\xeb\x30\xa6\x7a\x54\x17\x9a\xa6\x98\x92\x2b\x11\xbb\xa7\xfb\x22\x73\xd0\x62\xd0\xa6\x54\x13\x4e\x62\x2d\x68\x18\x62\x18\xa2\x64\x2d\x07\x8e\xbd\xa4\x24\x41\x53\x99\x30\x7b\x0b\x4a\x20\x0d\xd6\x72\x9c\xa7\xd8\xe2\xf9\x58\x83\xa0\xf7\x10\xbb\x4b\x0b\x6f\x1e\x4c\xfa\x21\x44\x13\x6d\xbe\xf5\xe1\x28\xda\x9c\x7f\x84\x2d\x5e\x5b\x39\xc7\x11\x4a\x3d\xd7\x99\x67\x19\xc6\xc4\x1e\xa7\x9c\xb0\x3c\x7c\xee\xcb\x8b\x14\xd6\x34\xbe\xcd\x63\x7d\x4a\xf1\xa2\x50\x4f\xf1\x97\x0f\x27\x9d\xa3\xbb\x68\x54\x4f\xbf\x96\xe9\x1f\x43\x8d\x58\x37\xdd\x83\x52\x92\x46\x41\x4b\xf0\x6a\xc4\x56\x72\x5f\x4b\xe6\x3a\x6b\x39\x8e\xb7\xc3\xf6\xec\xc5\xd6\x69\x5b\xe2\x55\x08\x2e\xdd\x04\x8f\x2d\x69\xf3\x4f\xa6\xae\x5d\x08\x9f\xf0\x57\x7e\xf0\x8a\x7b\x61\x2b\xa0\x0b\xeb\xd3\xff\x97\xff\x1b\x00\x00\xff\xff\x48\xf2\x61\xf4\x08\x05\x00\x00")
|
||||
|
||||
func typesChapterGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesChapterGraphql,
|
||||
"types/chapter.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesChapterGraphql() (*asset, error) {
|
||||
bytes, err := typesChapterGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/chapter.graphql", size: 1288, mode: os.FileMode(420), modTime: time.Unix(1530984073, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesCharacterGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x54\xbd\x72\xdc\x3c\x0c\xec\xf5\x14\xeb\x71\xf1\x35\xb6\xbf\xde\xdd\xc5\x4e\xe1\xc6\xc9\x38\xee\x32\x29\x60\x11\x3a\x61\x4c\x91\x0a\x01\xda\xa3\x78\xee\xdd\x33\x94\xee\xcf\x3a\x5d\x91\xee\x8e\x5c\x2c\x80\xdd\xa5\x2e\xb1\xc2\x5d\x4b\x89\x6a\xe3\x84\xc4\x7d\x62\xe5\x60\x0a\x0a\x78\xfa\x8e\x7a\x77\x55\xd9\xd0\xf3\x11\xf2\xa3\x02\x4a\x6d\x0e\xf2\x3b\x33\xc4\x71\x30\x69\x84\x13\x9a\x98\x60\x2d\x1f\x95\x02\xe2\x6e\xf1\xc3\x92\x84\xf5\x45\x35\x16\x3e\xb7\x8c\x3e\x49\x47\x69\xc0\xc3\xd3\x1d\x82\xd4\xaf\x78\x61\x1f\xc3\x5a\xc2\x1a\x16\x4f\x28\x0a\x62\x47\x32\x71\xac\xbc\xdf\xd7\x2a\x48\x35\xd6\x42\xc6\x0e\xef\x62\x2d\xac\x15\x3d\x21\xd0\x5b\xfc\xdc\xce\xf1\xeb\x68\x92\x3d\xec\x3f\x05\x65\x6b\x63\xc1\x4f\x3f\x16\xe6\x3e\x46\x07\xea\xb8\x70\x53\xc7\x0b\xc8\x72\x5c\x76\x71\xa2\xbd\xa7\x01\xef\x2d\x07\x68\x4f\x35\x43\x14\x5a\x53\xaa\xf9\x0a\x59\x33\x79\x3f\x8c\x1b\x37\x92\xd4\xfe\x5f\xcb\x1b\x87\x1d\xb7\xb6\x31\xd9\xe3\x69\x83\xd5\x74\x03\xc7\x5a\x27\xe9\x4d\x62\x40\x6c\x4e\x74\x3b\xba\x3e\x10\x6c\xaa\xea\x12\x0f\xa1\xcf\x36\xda\x45\xce\x15\xd5\xf7\x65\x5a\xc9\x78\xb7\xb7\x7b\xe5\xdc\x84\xfe\x38\xef\xde\x6e\xd9\xc4\x75\x5c\x07\xf9\xc3\x33\x0b\xf0\x32\xcc\x6c\xfc\x67\x4d\xbf\x95\x35\x28\xf8\x69\x73\x0e\xec\x46\xd4\x0d\xbe\x0c\x70\xdc\x50\xf6\x76\x05\x31\x64\x65\x3d\xc8\x09\x8b\xaf\x1c\x20\x61\x3c\x3a\xa7\xea\xd4\xe1\xfe\x48\xcc\x51\x99\xc3\x64\x37\xcb\x62\x7e\x9e\xcc\x0f\x57\xd0\x9e\x6b\x69\x06\x50\x88\xd6\x72\xda\x06\xe9\x06\xcf\x45\x8e\xc0\xec\x74\x82\x90\x47\xcf\xa9\x13\x55\x89\x41\x21\x0d\xc4\xca\xfa\xd1\x46\xca\x21\xe6\x84\xf8\x1e\xca\x36\x69\x3b\xf5\xe7\x4c\x2e\xd8\xf8\x58\x9c\xa0\xe0\x90\xb8\x8b\x6f\x3c\xfe\xed\xb2\x51\x99\x78\x6e\x6a\xb9\x9c\xbb\xfa\x70\xbf\x94\xa1\xc5\xe7\x3b\x9a\x6e\xb1\x74\x45\x4c\xdb\x86\x27\x0e\x6f\xaa\x79\xdb\xaf\x4e\x6c\xde\x56\xdc\xe9\x67\xa3\x70\xb3\x13\x3b\xd7\xbf\xc9\xde\x4f\xa1\x9b\x4f\x8c\xeb\xeb\xa2\xe2\x78\xa8\xe4\x29\x09\x85\x03\xfc\x62\x96\xad\xe5\x10\x4e\x6f\x6b\xca\x74\x4b\x56\xde\x6b\x56\x76\x25\x45\x75\xec\x7a\xaa\x0d\x5e\xd4\xf4\x7c\x94\x96\xde\xe7\xd2\xb7\x71\x29\x53\x9b\xbf\x01\x00\x00\xff\xff\x54\xc3\xda\x87\x97\x05\x00\x00")
|
||||
|
||||
func typesCharacterGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesCharacterGraphql,
|
||||
"types/character.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesCharacterGraphql() (*asset, error) {
|
||||
bytes, err := typesCharacterGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/character.graphql", size: 1431, mode: os.FileMode(420), modTime: time.Unix(1526204279, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesFileGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\x52\xb1\x8e\x13\x31\x10\xed\xfd\x15\x8f\x4b\x41\x73\xca\x07\xa4\x03\x71\x48\x91\x48\xc3\x1d\xa2\xf6\x9e\x67\xe3\x51\x6c\xcf\x62\x8f\xb3\x0a\xa7\xfb\x77\x64\xef\x1e\x8a\x50\x0a\xe8\xa8\x56\x3b\x7e\xef\xcd\x9b\x37\xb3\xc1\x07\x7c\xe6\x40\x78\x96\xa4\x96\x53\x01\xa7\x51\x72\xb4\xca\x92\x60\x07\xa9\x0a\x8b\xb1\x21\x6c\x72\x98\x3d\x65\x82\x0a\x9c\xcc\x29\x88\x75\x60\xdd\x1a\xbd\x4c\xb4\xa8\xbc\x18\x60\x83\x27\x4f\x9d\xf2\xbe\xa0\x26\xfe\x51\x09\xfb\x4f\x06\x60\xb7\xc3\xa3\x66\x4e\xc7\x77\xe6\x37\xee\xc4\xc9\x41\xc6\x8e\xdf\xe2\x20\x45\x31\x73\x08\x18\x08\x77\x75\x6a\x2d\xee\xee\x31\x54\x45\x91\x48\x50\x6f\x15\x36\x13\x26\xc9\x4a\x0e\x63\x96\x08\xf5\x84\x99\x4f\xbc\x10\xbd\x3d\x13\x44\x3d\x65\x9c\x6d\xa8\x54\x30\x4a\x86\x7a\x2e\x5b\x83\xde\xee\x86\x0b\xe5\x48\xcd\xc5\xd2\x91\xd3\xd1\xa0\xd7\xfe\x80\x7e\xf7\xd4\x85\x75\x1d\x10\x5c\x30\xd5\x21\xf0\x73\xb8\x20\x70\x51\x3b\xb4\x29\x1e\x25\x92\xa4\x66\x4a\x3d\x4e\x49\xe6\x40\xee\xd8\xf5\x1b\xb1\x67\xb1\x59\xcc\x16\x5d\x67\x6d\xc4\x96\xeb\x99\x69\x06\xeb\x3d\xbc\xcc\x74\xa6\xdc\x3c\x2f\x1d\x76\xf8\x28\x12\xc8\xa6\x2b\xdb\x6b\xc8\xc9\x46\x32\xe8\x9f\x1b\xb3\x1d\xf6\x87\x07\xf4\x15\xad\x06\x1a\xcb\x00\x91\x23\x3d\x5d\xa6\x5b\x94\x55\xb7\xf0\x4f\x02\x27\x0c\x17\xa5\x62\xd0\xff\x77\xd8\x27\xbd\x82\x2e\x89\x51\x36\x80\xad\xea\x25\xdf\x90\xfb\xf6\xf5\xcb\xdb\xe5\x5c\x05\xe7\xa5\x28\x39\x03\xd4\x1c\xde\x48\xe6\xd5\x98\x0d\xf6\x69\xaa\xda\xd7\x46\x8e\xb5\x1f\x56\xac\xda\x4f\xd2\x70\x7f\x7b\x58\xeb\x0b\xf2\xc5\xfc\xc3\xd1\xfd\x17\x3b\xfc\x9b\x15\x9a\xd7\x5f\x01\x00\x00\xff\xff\xe4\xc2\x5b\xa8\x9d\x03\x00\x00")
|
||||
|
||||
func typesFileGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesFileGraphql,
|
||||
"types/file.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesFileGraphql() (*asset, error) {
|
||||
bytes, err := typesFileGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/file.graphql", size: 925, mode: os.FileMode(420), modTime: time.Unix(1528836115, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesLogGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x56\xc1\x6e\xdc\x46\x0c\xbd\xeb\x2b\x98\xf8\xe0\x04\x48\xd3\x83\x4f\xdd\x9b\x6b\x24\xa8\x81\xa0\x0d\x92\x00\x3d\x18\x39\xcc\x6a\xb8\x2b\x22\x23\x52\x99\xa1\x76\xb3\x08\xf2\xef\x05\x29\xc9\x5e\x29\x5b\x64\xd1\x43\x91\x83\x4f\x9e\x1d\x93\x8f\xe4\x23\xf9\x46\x17\x70\x0d\x6f\x64\x0b\x54\x40\x1b\x84\xa7\x1b\x4a\xf8\x14\x64\x03\x81\xe1\xdd\x5b\x28\x58\x0a\x09\x57\x7a\xe8\xd0\xed\xbe\x56\x00\xe6\xd3\x33\x7d\xee\x11\x28\x22\x2b\x6d\x08\x33\x6c\x24\x3b\x44\x92\xed\xcb\x0a\x80\xe2\x0a\xde\x6b\x26\xde\x3e\xa9\x46\x9f\x82\xb5\x70\x0c\xf9\xf0\x03\x6f\xf8\xd0\x50\xb1\x8c\x02\x24\x51\x28\x8d\x64\xc5\x0c\x81\x23\xb4\x92\x11\x4a\x4f\x1a\xd6\x09\xdd\xa9\xa8\xe4\xb0\x45\xd8\x37\xc8\x1e\xc7\x51\x88\x3f\x41\x14\x2c\x7c\xa9\xc0\x88\x11\x54\x60\x8d\x10\x0a\xe0\x97\x2e\x5b\x51\x3b\xb4\x2c\x1d\xfb\x76\x99\xea\x87\x06\x21\x06\x1d\x02\x84\xa9\x22\xbb\x39\x61\x58\x37\x81\x19\x93\x73\x36\x99\x8e\x77\x7f\x86\x76\xe9\x71\xcb\x1b\xc9\x6d\x50\x12\x86\xb0\x96\x5e\x3d\xdf\x09\x43\xad\xf0\x34\xb4\x83\xf8\x08\x69\x05\x37\xc3\xe1\x28\xf0\xd8\x9b\xcb\x02\x4a\x9a\xbc\x1c\x3f\x9c\xc8\x31\xc9\xf6\xb2\x00\xee\x90\xf5\x05\xec\x1b\xaa\x9b\xa9\xe1\x25\xb4\x4e\x8b\x9d\x35\x6c\x2d\xac\x9f\xbb\x8c\x3b\x92\xde\xb3\x59\x5b\x13\x48\x3d\xc2\x05\xbc\x6a\x3b\x3d\x40\xf1\x10\xd0\x62\x60\x73\x0e\x0a\xa4\x97\x05\x58\x86\x28\x66\xea\x87\x53\xcc\x62\xa9\x33\x75\x4e\x81\x93\x36\x16\x72\x94\x19\x7a\x0c\xda\x40\xcf\x05\x1d\xec\xc8\x69\x01\xf9\x77\x83\xda\xe0\xfd\xf4\x4c\x68\x06\x23\x1d\x3a\x89\xf6\x77\x05\xbf\x8b\x24\x0c\x3c\x6f\x5d\x0e\xb5\x62\xb6\xb2\x77\x92\x76\x18\xa7\xfa\x0d\xc9\x76\x61\xec\xc1\x68\xb6\x82\xbb\x9b\xe9\xc7\x93\x8f\x47\x48\x9d\x14\x2d\x56\xcd\xe8\x6b\xae\x53\x3d\x75\x60\x9b\xbd\x0d\x25\xc5\x8c\x11\xd6\x07\xf8\x44\x1c\x8b\x41\xbb\xdf\x33\xff\xb9\xba\x1b\xcb\xfa\xf8\x7c\x05\x77\x6f\xa5\xa8\x45\xf8\x56\x55\x17\xf0\xda\x5d\x7d\x1a\x93\x6c\x0b\x7c\xee\x31\x1f\x2a\xe2\xae\x57\x5b\xca\x32\xfe\x7f\xd8\xcd\x71\x50\x8a\x8d\x7c\xa2\x96\x14\x32\x96\x3e\xa9\x5f\x3c\x23\xae\x53\x6f\xd3\xff\xfc\x61\xb8\xac\xac\x29\x76\x05\x30\x74\xd9\x9a\x77\x0e\x86\x77\x79\x86\x30\x65\x31\x51\x7b\x12\x03\xbf\xcc\xf3\x78\x20\x78\x8e\xf3\x1e\x43\xae\x1b\xe7\x09\x6a\x61\x45\x56\x5b\x5b\xbf\x9d\x06\x61\xb0\x7c\xe3\x31\x54\x40\x38\x1d\xbc\xe5\x4e\xd6\xb2\xfd\x33\xe3\x06\x21\xb4\xd2\xb3\x5a\xeb\xbc\x17\x15\x0c\xc9\xae\xe0\x96\x75\x60\xff\xd6\x79\x76\x29\x88\xd1\x34\xb0\xed\xd5\x17\xf8\xa1\x03\xd7\x31\x0e\x56\x5f\xe7\xfa\xf1\x30\x10\x2f\x6c\xb0\xde\xbd\xbe\xb9\xba\xba\xfa\x0d\x06\x09\x80\x3d\x69\x03\x7d\x67\x39\x73\x60\x19\xe4\xd1\x36\xaf\x26\x17\xdd\x1f\x4a\xce\xbe\xc1\x8c\xf7\xe3\x4a\x05\x0a\xea\xb1\x66\xcc\x1c\xff\xf2\xe5\x09\x69\x35\x29\xc2\xa0\x16\x4b\xd5\x58\x1a\x2f\xd7\x6b\x5c\xab\xd3\xb4\x7e\x1f\xc3\xc7\x03\x38\xb4\xb8\x54\x84\xa5\xc7\xf5\x20\xc6\x4b\x79\x18\xe3\x9e\x96\x80\xb3\x1b\xf4\x2a\x92\x2e\x3b\x44\x71\x8e\xff\xdd\x8b\x75\x06\x4f\xe7\x96\xf9\x9f\x8a\x1b\x09\x42\xfe\xb5\x4e\x52\xf0\xc8\x7a\x4e\xbd\x93\xe0\xcf\xf8\x1f\x18\x22\xe6\xe1\xe9\xac\x7b\xfd\x25\xca\x9e\x61\x87\xb9\x8c\xf1\x8c\x1c\x17\x6b\x7b\x1b\x81\x45\x21\xa4\x24\x7b\xd8\xa2\xaa\xc9\xb9\x2f\x44\xad\x7d\x48\xc3\x36\xbc\xbc\x7f\xf8\x47\xe4\xc7\xe7\xff\xdf\x76\xd1\x7a\xff\xbf\x7d\x03\x8c\x22\xfd\xf8\x15\xf0\x53\x7c\x05\x7c\xab\xfe\x09\x00\x00\xff\xff\xd3\x31\x19\xf7\x46\x0b\x00\x00")
|
||||
|
||||
func typesLogGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesLogGraphql,
|
||||
"types/log.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesLogGraphql() (*asset, error) {
|
||||
bytes, err := typesLogGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/log.graphql", size: 2886, mode: os.FileMode(420), modTime: time.Unix(1531585338, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesPostGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x54\xc1\x6a\xdc\x40\x0c\xbd\xfb\x2b\x5e\x36\x87\xbd\x6c\x73\xc9\xa9\xb9\x85\xa6\x05\x43\x4b\x97\x34\x3f\x30\x99\xd1\x7a\x86\xb5\x25\x33\x92\x93\x2c\xa5\xff\x5e\x66\xbc\x21\x10\xbc\x87\x96\x04\xda\x93\x41\x7a\xa3\xf7\xa4\xf7\xf0\x39\xae\xb1\x15\x35\x24\x85\xc3\xe8\xb2\x41\x76\x70\xe8\xa5\x6b\xec\x30\xd2\xdc\xfc\xd9\x00\xe7\xb8\x8b\x84\x51\xd4\xd6\x8a\xf6\xa6\x01\x52\xb8\xc2\x0f\xcb\x89\xbb\xb3\xe6\x35\xe0\xab\x74\x68\x6f\x2e\x70\x17\x93\x96\xd9\x16\x09\xbe\x17\x25\x35\x58\x4c\xdc\xc1\xa4\xd0\x24\xde\xe3\xde\xf9\x3d\x34\xb1\xa7\xd2\x52\x5c\x6f\x5b\x74\xd9\x8d\x11\x41\x48\x79\x6d\x88\xee\x81\xe0\xf8\x00\x7f\xf0\x3d\xe9\x45\x83\x22\xb0\x5d\xe2\x0f\xce\x0a\x34\xc0\xd2\x40\x65\x97\x22\x28\x71\xd7\xa0\x56\x16\x5e\xec\x13\x87\x67\xe0\x2c\x20\xe9\x05\xbe\x73\x7f\xc0\xca\xe8\xc9\x56\x1b\xac\xd4\x13\xd3\xaa\xce\x5d\x39\x6f\x49\x78\x05\x97\x09\xb7\xdb\x0d\x1e\x63\xea\x09\x62\x91\xb2\xd6\xa2\x63\x16\x73\x05\xa4\xf5\xc5\xda\xcb\x30\x38\x0e\xba\x2e\xc2\x0b\xdd\x82\x0a\x1f\x5d\x76\xde\x28\x83\x93\xdf\x37\xa8\x9f\xd3\xf7\x2d\xc2\x2a\xb5\x8f\x18\xa7\x3c\x8a\x12\x02\x8d\xc4\x41\x21\x5c\xcf\x5d\x88\xca\xd6\xf4\x64\xa7\xe7\x8c\xa2\xa9\x28\xdd\x60\x52\x0a\xd8\x49\x46\x26\xc9\x81\xf2\x7c\xb3\xe7\xfe\x15\x5a\xb6\xb3\xe6\x57\xd3\x9c\xa3\xe5\x71\xb2\x0a\x2d\x34\x2e\x84\x9a\x91\x61\x9a\x77\x6e\x52\x6d\x5f\xcf\xe5\x19\xfb\x92\x9f\x5e\xba\x1a\x1f\x58\x74\xc7\x6b\xd7\xbb\x6b\x94\xa9\x0f\xb8\xa7\x97\x14\xfe\x85\xc9\x1b\x24\x86\xc3\xed\x97\x4f\x97\x97\x97\x1f\x8b\xc4\xc1\x19\x1e\x93\x45\x4c\xe3\x9c\x38\x76\x2c\x4a\x5e\x38\x94\xed\x33\xf9\xa4\x45\xf4\x7f\x95\x8e\x0d\x24\xe3\xf8\x0c\x89\x1f\x64\x4f\xb9\xfa\xc1\xc2\x1f\x6e\xb7\x50\x9b\x76\xbb\x77\x8b\xd0\x42\x06\x28\x24\x5b\x0a\xc1\xe7\x63\xfd\x75\x0a\x2a\xf6\xf4\x3f\xe4\xbd\xed\xfd\x27\xdc\x7d\x4b\x73\xdf\xc8\xdb\x25\x6b\x07\x79\xa0\x25\x6b\xbf\x1d\xeb\x7f\x62\xad\xcb\x1d\x19\x12\x07\x7a\x2a\xcc\xb2\x7d\xf5\x73\xf9\x1d\x00\x00\xff\xff\x60\x35\xc5\x5a\x8d\x06\x00\x00")
|
||||
|
||||
func typesPostGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesPostGraphql,
|
||||
"types/post.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesPostGraphql() (*asset, error) {
|
||||
bytes, err := typesPostGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/post.graphql", size: 1677, mode: os.FileMode(420), modTime: time.Unix(1530961143, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesSessionGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x44\xcc\x4b\x0a\x02\x31\x10\x06\xe1\x7d\x4e\x51\xe0\xd6\x13\x78\x0d\xf5\x00\x83\xfe\x4e\x02\xa1\x33\x74\x77\x16\x22\xde\x5d\x7c\x80\xdb\xe2\xa3\x76\x9c\xaa\x08\x45\xb4\x61\xb8\x36\x57\xc8\x32\xc8\x2a\x2e\xd3\x5d\x96\xf4\xb1\x36\x23\x72\x49\x95\xbc\x6f\xe2\xf8\xf3\x8f\x02\xdf\xc3\x0c\x39\x59\x97\xa4\xc5\xdb\xaf\xba\xd2\x6c\x8f\xcd\xde\x69\x37\x6c\xe4\x3f\x17\x3e\xfe\xc0\x39\xe4\xe5\xf9\x0a\x00\x00\xff\xff\x3a\x24\x24\xaf\x84\x00\x00\x00")
|
||||
|
||||
func typesSessionGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesSessionGraphql,
|
||||
"types/session.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesSessionGraphql() (*asset, error) {
|
||||
bytes, err := typesSessionGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/session.graphql", size: 132, mode: os.FileMode(420), modTime: time.Unix(1525515204, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesStoryGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x57\x4f\x6f\xe3\xb6\x13\xbd\xeb\x53\x4c\x90\xc3\xee\x02\x81\x7f\x3f\x20\xa7\xfa\x96\x4d\x9a\xc2\x97\x62\x91\x04\xe8\x61\xb1\x87\xb1\x38\x96\xd8\x50\xa4\x96\x1c\xc6\x35\x82\xfd\xee\xc5\x90\x94\x64\x3b\xb2\xd3\x43\x0b\xb4\x17\xc3\x12\x87\xf3\xf7\xbd\x47\xea\x12\x6e\xe0\x91\x9d\xdf\x81\x0e\x80\xd0\x6b\xaa\x09\xdc\x06\x6a\x67\x99\x2c\x03\xb7\xc8\x57\x10\xad\xd1\xcf\x04\x5b\xfd\xac\x01\x3d\xeb\xda\x50\xb8\x02\xf4\x04\xd6\x31\x04\xd7\x11\xb7\xda\x36\xc9\x1a\x42\xeb\xa2\x51\xb0\x26\x70\x5e\x91\x27\x05\xeb\x1d\xb0\xee\x08\xb4\x0d\x4c\xa8\xc4\x3f\x6b\x36\xb4\x80\x15\x43\x8d\xb6\xba\x4c\xf1\x50\x5b\xe8\xa2\x61\xdd\x1b\x82\xba\xc5\x9e\xc9\x07\xd9\xec\xac\xf8\x82\xce\x79\x02\x8c\xec\x5a\x1f\x2a\xde\xf5\x54\x32\x7f\xad\x00\x2e\xe1\xa9\x25\x08\xf2\xfc\x21\xc0\xea\xae\x02\xd0\x6a\x09\x8f\xec\xb5\x6d\x2e\xaa\x37\x16\x16\x3b\xba\x82\x6d\xab\xeb\x16\xb6\xda\x18\xc9\x7a\x0b\xb1\x07\x6d\x81\x5b\x02\xa3\x03\x87\x45\x05\xc9\xf0\x8c\x1f\x8c\xdc\x3a\x5f\x41\xf9\x73\x64\xf9\x5b\x4b\xdc\x92\x07\x97\x7e\x63\x90\x7a\x3a\xdc\x01\x2a\xf5\x3f\x52\x9a\xa7\x2a\xd9\xa5\xb0\xc9\xad\x84\x75\x3d\xd9\x25\x7c\x76\xce\x10\xda\x23\x6f\xd9\xcf\x56\x73\xeb\x22\x03\x82\xd2\x9e\x6a\x06\xa3\xed\xb3\x74\x13\x36\xda\x2a\xe0\x56\x87\xc9\x9d\x94\x43\xea\xd8\xa1\x14\x52\x23\x53\x23\x5d\x94\xa1\x0c\x19\x54\x30\xbe\x5f\xe6\x26\xdf\x96\xc7\xbd\x9d\x8c\x4d\x80\x8d\xf3\x39\x54\xd9\x26\x2f\x97\xf0\xf5\x09\x9b\x8b\x6f\xfb\x51\x86\x3a\x53\x94\x21\x33\x09\x53\x16\x96\xf0\xf5\x36\xff\x3d\xd8\xa7\x90\x69\x4a\x0b\xb6\x18\xa0\xf6\x84\x4c\x0a\x3e\x3e\xdc\xdf\x5e\x5f\x5f\xff\x24\x29\x74\xc8\x9f\xa4\xcc\xb2\x76\x87\x3c\x37\xb3\x23\x67\x92\x05\xb1\x0c\x7c\xce\xd5\x46\xd7\xac\x9d\x45\x73\xce\x59\xe9\x99\xc1\xc0\xd0\xe1\xef\xce\x43\xec\x73\x94\xbd\x71\xbe\x75\x0f\x4f\xd2\x82\x35\x09\x65\xd6\xb1\xeb\x49\x41\x47\x68\x85\x80\x96\xb6\x43\x4f\xa0\x45\x31\x22\x2b\x70\x21\x25\x49\x65\xef\x47\xf5\xfd\xa8\xaa\x4b\xb8\xd7\x46\xb6\xc8\x38\x24\xa8\xa6\x00\xdf\x23\xc9\xf0\xb5\xed\x23\xa7\x21\x6a\x0a\xc5\xec\xb5\xe0\x09\xb9\xe0\x56\x12\x4e\xf6\xe2\xe1\x0d\x9a\xab\xc9\x3c\x0d\xfd\xc8\x78\x9a\xf9\x4a\x62\x5d\x7c\x9b\xba\x44\xe8\x8d\xa6\xc0\x87\xed\xac\x60\x5c\xb8\x9f\x6b\xf3\xb4\xdf\x20\xcf\xed\xce\xaf\xdf\xd9\xdb\xe1\x1f\x80\x9d\x8b\x96\x65\x4e\x43\x57\xd8\x41\x43\x0c\x1f\x15\x6d\x30\x1a\x5e\xc2\xf5\xff\x3f\x25\x82\x74\x9a\x97\xb0\xb2\x9c\xfb\x99\x2a\x29\xe8\x26\x19\x40\x96\x9a\x2e\x32\x4a\xcc\xbd\xae\xee\x6e\x94\xca\xd6\xaf\x90\x62\x3f\x12\xa7\x4d\xa2\x1c\x07\xac\x9a\xd5\x1b\x0c\xc9\x20\xe9\xe1\x15\xa0\x55\xf2\x06\x21\xc4\xa6\xa1\x20\xa1\x4a\x93\x2f\x93\xd9\x46\xfb\x30\xaa\x46\x41\xd0\x88\x8e\x19\xa9\x1a\x72\x19\x59\x3e\x54\x24\x38\x1b\xd5\xe1\x3c\xd7\x6f\x94\xda\x03\x73\xb4\x8a\x3c\xa0\xcd\x92\x26\x21\x0b\x9c\x3d\x7d\x8f\xda\x53\xd8\xd3\x31\x54\x0a\x7a\xf2\x9d\x0e\x41\x3b\x9b\xab\x2b\xa7\x83\x9c\x1b\x6b\x4a\xfe\x71\x1d\x03\xa9\x45\x9a\x19\xa6\x89\xe6\x0e\xad\x09\x8c\x6b\x1a\x52\x49\xea\xf2\x1c\x6a\x8e\x68\x32\xcd\x9d\xff\x10\x92\x14\xc2\xea\x6e\x71\x02\xb2\x37\xc6\xb8\xed\x81\xfa\xb2\x83\xde\x85\xbf\x2a\xbc\x67\xbc\x04\xa2\xac\x64\x3d\x36\x72\xb2\x01\xda\x5d\x3e\x35\xe4\xa8\x0a\x84\xbe\x6e\xc1\x53\x88\x26\x9f\x23\x47\x0a\x3c\x8d\x27\x63\x22\xf3\x6a\xec\x72\xe9\x52\x8b\x2f\xb4\x38\xcd\xb0\x61\xba\x23\x3d\x0e\x54\xe9\x84\xf8\x9c\xd2\xb6\x39\xdc\xcb\x19\x75\x1a\xf8\x3f\x2b\xcd\x05\xf9\x93\x40\xe4\xa8\xec\xd2\xde\xb9\x53\xf8\x5f\x41\x8f\xbf\x81\x1d\xff\x79\x72\xdc\xb6\x68\x1b\x82\x6d\xb9\x55\xb0\x03\x9c\x80\x9e\x30\x2e\x29\x0e\x44\x99\xa7\xc6\x5b\x1f\x69\x70\xd3\x11\xbf\x7f\x9f\xca\x25\x1e\x30\xe3\x1c\x31\xfe\x51\x64\x0f\x8a\xfe\x84\xcd\x2c\xb6\x9f\xb0\x99\x74\x7d\x06\xdd\x58\xe6\xce\xd8\x00\xbb\xc5\xa9\xeb\x66\x5e\x16\xeb\x42\xe3\x25\x8c\x24\x9e\x4b\xcb\x53\xe7\x5e\xe8\xbd\xcc\x1e\x92\xd5\xe9\xe4\xb2\x97\x31\xbf\x8d\x77\xdd\x7b\x19\xe6\x2d\xa7\x92\xfc\xe2\x42\xd0\x6b\x43\xf0\x82\x26\x52\xbe\xf5\xa5\x64\x16\x03\x39\x2a\xb2\xb1\x3b\x24\x48\x49\xed\x8e\x42\xed\x75\x9f\xa0\x2b\x00\x18\xbe\x2c\xdc\x46\xae\xae\xae\x8e\x5d\x7a\xf2\xa0\x99\xba\x0a\xe0\xae\xbc\xca\x29\xfe\x4a\xdb\x30\x9c\xdd\x15\xa4\xc7\xbc\xb0\xb2\x79\xec\xc9\xed\x5a\x2e\xc2\xd3\x67\x48\xe3\xe4\xd7\xd9\x01\x7c\x6b\xac\x9f\x1b\xef\x62\xba\x16\x23\xa7\x2b\xb8\x7c\x4f\xe0\x2e\x51\x4d\x27\x57\xf0\xf0\xa5\x02\xf8\x3c\x9a\xe6\x30\xbf\x90\x25\x8f\xa6\xd8\xe4\x61\x40\x0a\x5e\xf8\x2f\x80\xf7\x3c\xde\x67\x53\x07\xaa\x1f\x7f\x06\x00\x00\xff\xff\x3b\xb1\x09\x16\x57\x0d\x00\x00")
|
||||
|
||||
func typesStoryGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesStoryGraphql,
|
||||
"types/story.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesStoryGraphql() (*asset, error) {
|
||||
bytes, err := typesStoryGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/story.graphql", size: 3415, mode: os.FileMode(420), modTime: time.Unix(1531585348, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesTagGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x52\x41\x73\xd5\x3c\x0c\xbc\xe7\x57\x6c\xa7\x87\xef\x92\xef\x71\xef\xad\xc3\x70\x60\x60\xe0\xd0\xfe\x01\x3d\x47\x89\x3d\xd8\x52\xc6\x52\x52\x1e\x4c\xff\x3b\x63\xa7\x8f\x02\x67\x38\xd9\x71\xa4\xd5\xee\x6a\x6f\x71\x8f\x47\x5a\x90\x0c\x84\xc2\x24\x06\x9d\x41\x66\x1a\x12\x79\x92\x05\xe6\x5a\x13\x1b\x3c\x92\x23\xd2\xce\x98\xd8\x29\x65\x43\x12\x04\x2d\x45\x05\x4f\xc9\x23\x54\x18\x24\xea\x91\xeb\x69\xf0\xcb\xca\x1d\xf8\xfb\x00\xdc\xe2\x31\x32\x9c\x96\xff\x0c\x5f\x92\x4c\x03\xfa\x71\xd7\x0a\x3e\x24\x99\x6e\x86\x3f\x8a\x84\x0a\x0f\xe8\xc7\x1d\x1e\xbc\x26\x59\x6e\x86\xe7\x61\xf8\x57\x6c\x93\xac\x9b\x37\xe4\xf7\xfd\xf2\xb7\x39\xe7\xac\x4f\x3c\x61\xa7\xbc\xb1\x61\xd6\xda\x40\x4e\x1d\x95\x65\x2b\x57\xc8\x97\xb9\xf7\x02\xad\x0b\x49\xfa\x46\x9e\x54\x0e\xb1\x81\x3c\x44\x50\xce\x70\xae\xa5\x63\x24\xf9\x7f\x93\xb4\x73\x35\x46\xd0\xba\x6a\xed\xf5\x36\xc2\x99\x8a\x8d\x58\xaa\x6e\xab\x8d\x08\x5b\x76\x1b\x5b\x4f\x60\x1b\xc1\x1e\x4e\xa7\xd3\x00\x7c\xfe\x65\xca\xa1\xe6\x1e\x21\x52\xa5\xe0\x5c\x9b\x2a\x58\xd4\x2d\x4f\x87\x8f\x1e\x19\xfc\x95\x82\x63\xde\x72\xee\x3a\x9b\xf9\xed\xf9\x67\x53\x43\x7d\x7b\xfd\xb8\x42\x66\x0d\xaf\x42\xe4\xe2\xb1\xed\x69\xae\x5a\x40\x58\x33\x09\x3b\x5c\x41\x02\x36\xa7\x73\x4e\x16\x0b\x8b\x9f\xf0\x18\x93\xa1\xd0\x05\xba\x73\xcd\xb4\x1e\x7b\xa3\xdf\xdd\x19\x41\x32\x21\xcd\x30\x1d\x71\x56\x8f\x7d\x68\xb3\xb6\x47\xc3\x69\xb1\xab\x8a\x33\x63\x33\x9e\x1a\xc7\x8f\x2f\x94\x86\xab\xe1\xbc\xb3\xf8\xe1\xf4\x9a\xd5\xa1\xb5\xdd\xa8\x7a\xcf\x57\x7f\x6b\x7d\xef\x5a\xd9\xd1\xf4\xa9\x05\xe8\x45\x3f\x9d\x75\xe7\x11\xe7\xcd\x91\x1c\x93\xb2\xc1\x3c\xb5\x5d\x25\x46\xd9\xb2\xa7\x35\xf3\x6b\x34\x75\xe1\x1e\xbb\x1e\x1e\xe1\xa7\xfe\xe7\xf2\x26\x44\x5a\x9b\xf1\xb3\xd6\x42\x7e\x28\x3f\x9b\x66\xf6\x66\x7e\xb2\xbe\x91\xa6\xac\x31\x79\xe0\x86\x35\x3c\xff\x08\x00\x00\xff\xff\x1f\xbf\x7a\x64\xc0\x03\x00\x00")
|
||||
|
||||
func typesTagGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesTagGraphql,
|
||||
"types/tag.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesTagGraphql() (*asset, error) {
|
||||
bytes, err := typesTagGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/tag.graphql", size: 960, mode: os.FileMode(420), modTime: time.Unix(1530963938, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _typesUserGraphql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4c\xcc\x41\x0a\xc2\x40\x0c\x85\xe1\x7d\x4e\xf1\x8a\xb7\xe8\x35\xd4\x95\xb8\x18\x6c\x6c\xdf\xa2\x99\x21\x89\x88\x88\x77\x97\x0e\x5d\x74\x19\xf2\xbd\xff\x84\xcb\xa2\xb8\x86\x3a\xf2\xd3\x14\x0c\x3c\xab\x83\x96\xea\xe5\x91\xb4\x19\x6f\xe6\x82\xd7\x26\x6a\x4b\x56\x0b\x14\x9b\x10\x9a\xdb\x37\xa4\xcf\x7a\xe0\x2b\x40\xef\xd1\xbb\xb7\xb2\xaa\x00\x9c\x46\x9c\xd3\x69\xf3\x20\x07\xd1\xd4\x57\x46\xb0\x9a\xe0\x70\xc4\x88\xdb\xae\xef\x83\xfc\xfe\x01\x00\x00\xff\xff\x74\x0a\x0a\x1c\xa0\x00\x00\x00")
|
||||
|
||||
func typesUserGraphqlBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
_typesUserGraphql,
|
||||
"types/user.graphql",
|
||||
)
|
||||
}
|
||||
|
||||
func typesUserGraphql() (*asset, error) {
|
||||
bytes, err := typesUserGraphqlBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "types/user.graphql", size: 160, mode: os.FileMode(420), modTime: time.Unix(1525514069, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Asset loads and returns the asset for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func Asset(name string) ([]byte, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.bytes, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
|
||||
// MustAsset is like Asset but panics when Asset would return an error.
|
||||
// It simplifies safe initialization of global variables.
|
||||
func MustAsset(name string) []byte {
|
||||
a, err := Asset(name)
|
||||
if err != nil {
|
||||
panic("asset: Asset(" + name + "): " + err.Error())
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
// AssetInfo loads and returns the asset info for the given name.
|
||||
// It returns an error if the asset could not be found or
|
||||
// could not be loaded.
|
||||
func AssetInfo(name string) (os.FileInfo, error) {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
if f, ok := _bindata[cannonicalName]; ok {
|
||||
a, err := f()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||
}
|
||||
return a.info, nil
|
||||
}
|
||||
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
||||
}
|
||||
|
||||
// AssetNames returns the names of the assets.
|
||||
func AssetNames() []string {
|
||||
names := make([]string, 0, len(_bindata))
|
||||
for name := range _bindata {
|
||||
names = append(names, name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||
var _bindata = map[string]func() (*asset, error){
|
||||
"root.graphql": rootGraphql,
|
||||
"types/change.graphql": typesChangeGraphql,
|
||||
"types/channel.graphql": typesChannelGraphql,
|
||||
"types/chapter.graphql": typesChapterGraphql,
|
||||
"types/character.graphql": typesCharacterGraphql,
|
||||
"types/file.graphql": typesFileGraphql,
|
||||
"types/log.graphql": typesLogGraphql,
|
||||
"types/post.graphql": typesPostGraphql,
|
||||
"types/session.graphql": typesSessionGraphql,
|
||||
"types/story.graphql": typesStoryGraphql,
|
||||
"types/tag.graphql": typesTagGraphql,
|
||||
"types/user.graphql": typesUserGraphql,
|
||||
}
|
||||
|
||||
// AssetDir returns the file names below a certain
|
||||
// directory embedded in the file by go-bindata.
|
||||
// For example if you run go-bindata on data/... and data contains the
|
||||
// following hierarchy:
|
||||
// data/
|
||||
// foo.txt
|
||||
// img/
|
||||
// a.png
|
||||
// b.png
|
||||
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||
// AssetDir("") will return []string{"data"}.
|
||||
func AssetDir(name string) ([]string, error) {
|
||||
node := _bintree
|
||||
if len(name) != 0 {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
pathList := strings.Split(cannonicalName, "/")
|
||||
for _, p := range pathList {
|
||||
node = node.Children[p]
|
||||
if node == nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.Func != nil {
|
||||
return nil, fmt.Errorf("Asset %s not found", name)
|
||||
}
|
||||
rv := make([]string, 0, len(node.Children))
|
||||
for childName := range node.Children {
|
||||
rv = append(rv, childName)
|
||||
}
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
type bintree struct {
|
||||
Func func() (*asset, error)
|
||||
Children map[string]*bintree
|
||||
}
|
||||
var _bintree = &bintree{nil, map[string]*bintree{
|
||||
"root.graphql": &bintree{rootGraphql, map[string]*bintree{}},
|
||||
"types": &bintree{nil, map[string]*bintree{
|
||||
"change.graphql": &bintree{typesChangeGraphql, map[string]*bintree{}},
|
||||
"channel.graphql": &bintree{typesChannelGraphql, map[string]*bintree{}},
|
||||
"chapter.graphql": &bintree{typesChapterGraphql, map[string]*bintree{}},
|
||||
"character.graphql": &bintree{typesCharacterGraphql, map[string]*bintree{}},
|
||||
"file.graphql": &bintree{typesFileGraphql, map[string]*bintree{}},
|
||||
"log.graphql": &bintree{typesLogGraphql, map[string]*bintree{}},
|
||||
"post.graphql": &bintree{typesPostGraphql, map[string]*bintree{}},
|
||||
"session.graphql": &bintree{typesSessionGraphql, map[string]*bintree{}},
|
||||
"story.graphql": &bintree{typesStoryGraphql, map[string]*bintree{}},
|
||||
"tag.graphql": &bintree{typesTagGraphql, map[string]*bintree{}},
|
||||
"user.graphql": &bintree{typesUserGraphql, map[string]*bintree{}},
|
||||
}},
|
||||
}}
|
||||
|
||||
// RestoreAsset restores an asset under the given directory
|
||||
func RestoreAsset(dir, name string) error {
|
||||
data, err := Asset(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := AssetInfo(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RestoreAssets restores an asset under the given directory recursively
|
||||
func RestoreAssets(dir, name string) error {
|
||||
children, err := AssetDir(name)
|
||||
// File
|
||||
if err != nil {
|
||||
return RestoreAsset(dir, name)
|
||||
}
|
||||
// Dir
|
||||
for _, child := range children {
|
||||
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func _filePath(dir, name string) string {
|
||||
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||
}
|
||||
|
||||
@@ -3,19 +3,19 @@ type Query {
|
||||
# Find character by either an ID or a nick.
|
||||
character(id: String, nick: String): Character
|
||||
|
||||
# Find characters by either a list of ids, nicks or an author. Only one parameter at a time
|
||||
characters(ids: [String!], nicks: [String!], author: String): [Character!]!
|
||||
# Find characters
|
||||
characters(filter: CharactersFilter): [Character!]!
|
||||
|
||||
|
||||
# Find channel by name
|
||||
channel(name: String!): Channel
|
||||
|
||||
# Find all channels. Specifying `logged: true` restricts the search to only logged.
|
||||
channels(logged: Boolean): [Channel!]!
|
||||
# Find channels
|
||||
channels(filter: ChannelsFilter): [Channel!]!
|
||||
|
||||
|
||||
# Find log by ID
|
||||
log(id: String): Log
|
||||
log(id: String!): Log
|
||||
|
||||
# Find logs
|
||||
logs(filter: LogsFilter): [LogHeader!]!
|
||||
@@ -32,8 +32,8 @@ type Query {
|
||||
# Find file by ID
|
||||
file(id: String!): File
|
||||
|
||||
# Files get all available files. If includePublic is set, it will return public files as well
|
||||
files(includePublic: Boolean, mimeTypes: [String!]): [File!]!
|
||||
# Find files
|
||||
files(filter: FilesFilter): [File!]!
|
||||
|
||||
|
||||
# Find story by ID
|
||||
@@ -49,10 +49,6 @@ type Query {
|
||||
|
||||
# Find all distinct tags used in stories
|
||||
tags: [Tag!]!
|
||||
|
||||
|
||||
# Find current session
|
||||
session: Session!
|
||||
}
|
||||
|
||||
# The Mutation type represents write entry points into the API.
|
||||
@@ -137,13 +133,6 @@ type Mutation {
|
||||
|
||||
# Remove a chapter
|
||||
removeChapter(id: String!): Chapter!
|
||||
|
||||
|
||||
# Log in
|
||||
login(username: String!, password: String!): Session!
|
||||
|
||||
# Log out
|
||||
logout(): Session!
|
||||
}
|
||||
|
||||
schema {
|
||||
|
||||
@@ -16,6 +16,18 @@ type Channel {
|
||||
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 {
|
||||
# The channel's name
|
||||
name: String!
|
||||
|
||||
@@ -22,6 +22,27 @@ type Character {
|
||||
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
|
||||
|
||||
# Filter by whether they've been part of a log.
|
||||
logged: Boolean
|
||||
}
|
||||
|
||||
# Input for adding characters
|
||||
input CharacterAddInput {
|
||||
# The primary IRC nick name to recognize this character by
|
||||
|
||||
@@ -29,6 +29,15 @@ type File {
|
||||
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 EditFileInput {
|
||||
# The file's unique ID
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user