Gisle Aune
6 years ago
16 changed files with 482 additions and 14 deletions
-
6.gitignore
-
90Gopkg.lock
-
4Gopkg.toml
-
46cmd/rpdata-server/main.go
-
4graph2/combine.sh
-
19graph2/gqlgen.yml
-
21graph2/graph.go
-
22graph2/queries/character.go
-
6graph2/queries/resolver.go
-
11graph2/queries/tags.go
-
16graph2/schema/root.gql
-
87graph2/schema/types/Character.gql
-
37graph2/schema/types/Tag.gql
-
63model/character/character.go
-
58model/story/tag-kind.go
-
6model/story/tag.go
@ -0,0 +1,46 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"fmt" |
||||
|
"log" |
||||
|
"net/http" |
||||
|
"runtime/debug" |
||||
|
|
||||
|
"git.aiterp.net/rpdata/api/graph2" |
||||
|
"git.aiterp.net/rpdata/api/internal/store" |
||||
|
logModel "git.aiterp.net/rpdata/api/model/log" |
||||
|
"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", "/query")) |
||||
|
http.Handle("/query", 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") |
||||
|
}), |
||||
|
)) |
||||
|
|
||||
|
go updateCharacters() |
||||
|
|
||||
|
log.Fatal(http.ListenAndServe(":8081", nil)) |
||||
|
} |
||||
|
|
||||
|
func updateCharacters() { |
||||
|
n, err := logModel.UpdateAllCharacters() |
||||
|
if err != nil { |
||||
|
log.Println("Charcter updated stopped:", err) |
||||
|
} |
||||
|
|
||||
|
log.Println("Updated characters on", n, "logs") |
||||
|
} |
@ -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,19 @@ |
|||||
|
schema: generated.gql |
||||
|
|
||||
|
exec: |
||||
|
filename: generated.go |
||||
|
package: graph2 |
||||
|
|
||||
|
model: |
||||
|
filename: input/generated.go |
||||
|
package: input |
||||
|
|
||||
|
models: |
||||
|
Tag: |
||||
|
model: git.aiterp.net/rpdata/api/model/story.Tag |
||||
|
TagKind: |
||||
|
model: git.aiterp.net/rpdata/api/model/story.TagKind |
||||
|
Character: |
||||
|
model: git.aiterp.net/rpdata/api/model/character.Character |
||||
|
CharactersFilter: |
||||
|
model: git.aiterp.net/rpdata/api/model/character.Filter |
@ -0,0 +1,21 @@ |
|||||
|
package graph2 |
||||
|
|
||||
|
import ( |
||||
|
"git.aiterp.net/rpdata/api/graph2/queries" |
||||
|
graphql "github.com/99designs/gqlgen/graphql" |
||||
|
) |
||||
|
|
||||
|
//go:generate ./combine.sh
|
||||
|
//go:generate gorunpkg github.com/99designs/gqlgen -v
|
||||
|
|
||||
|
func New() graphql.ExecutableSchema { |
||||
|
return NewExecutableSchema(Config{ |
||||
|
Resolvers: &rootResolver{}, |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
type rootResolver struct{} |
||||
|
|
||||
|
func (r *rootResolver) Query() QueryResolver { |
||||
|
return &queries.Resolver |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
package queries |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
"errors" |
||||
|
|
||||
|
"git.aiterp.net/rpdata/api/model/character" |
||||
|
) |
||||
|
|
||||
|
func (r *resolver) Character(ctx context.Context, id *string, nick *string) (character.Character, error) { |
||||
|
if id != nil { |
||||
|
return character.FindID(*id) |
||||
|
} else if nick != nil { |
||||
|
return character.FindNick(*nick) |
||||
|
} else { |
||||
|
return character.Character{}, errors.New("You must specify either an ID or a nick") |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (r *resolver) Characters(ctx context.Context, filter *character.Filter) ([]character.Character, error) { |
||||
|
return character.List(filter) |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
package queries |
||||
|
|
||||
|
type resolver struct{} |
||||
|
|
||||
|
// Resolver has all the queries
|
||||
|
var Resolver resolver |
@ -0,0 +1,11 @@ |
|||||
|
package queries |
||||
|
|
||||
|
import ( |
||||
|
"context" |
||||
|
|
||||
|
"git.aiterp.net/rpdata/api/model/story" |
||||
|
) |
||||
|
|
||||
|
func (r *resolver) Tags(ctx context.Context) ([]story.Tag, error) { |
||||
|
return story.ListTags() |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
schema { |
||||
|
query: Query |
||||
|
} |
||||
|
|
||||
|
type Query { |
||||
|
# Find character by either an ID or a nick. |
||||
|
character(id: String, nick: String): Character! |
||||
|
|
||||
|
# Find characters |
||||
|
characters(filter: CharactersFilter): [Character!]! |
||||
|
|
||||
|
|
||||
|
# Find all distinct tags used in stories |
||||
|
tags: [Tag!]! |
||||
|
} |
||||
|
|
@ -0,0 +1,87 @@ |
|||||
|
# 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 |
||||
|
|
||||
|
# 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 |
||||
|
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! |
||||
|
} |
||||
|
|
||||
|
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 |
||||
|
} |
||||
|
|
@ -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,58 @@ |
|||||
|
package story |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
"io" |
||||
|
) |
||||
|
|
||||
|
// TagKind represents the kind of tags.
|
||||
|
type TagKind string |
||||
|
|
||||
|
const ( |
||||
|
// TagKindOrganization is a tag kind, see GraphQL documentation.
|
||||
|
TagKindOrganization TagKind = "Organization" |
||||
|
|
||||
|
// TagKindCharacter is a tag kind, see GraphQL documentation.
|
||||
|
TagKindCharacter TagKind = "Character" |
||||
|
|
||||
|
// TagKindLocation is a tag kind, see GraphQL documentation.
|
||||
|
TagKindLocation TagKind = "Location" |
||||
|
|
||||
|
// TagKindEvent is a tag kind, see GraphQL documentation.
|
||||
|
TagKindEvent TagKind = "Event" |
||||
|
|
||||
|
// TagKindSeries is a tag kind, see GraphQL documentation.
|
||||
|
TagKindSeries TagKind = "Series" |
||||
|
) |
||||
|
|
||||
|
// IsValid returns true if the TagKind is one of the constants
|
||||
|
func (e TagKind) IsValid() bool { |
||||
|
switch e { |
||||
|
case TagKindOrganization, TagKindCharacter, TagKindLocation, TagKindEvent, TagKindSeries: |
||||
|
return true |
||||
|
} |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
func (e TagKind) String() string { |
||||
|
return string(e) |
||||
|
} |
||||
|
|
||||
|
// UnmarshalGQL unmarshals
|
||||
|
func (e *TagKind) UnmarshalGQL(v interface{}) error { |
||||
|
str, ok := v.(string) |
||||
|
if !ok { |
||||
|
return fmt.Errorf("enums must be strings") |
||||
|
} |
||||
|
|
||||
|
*e = TagKind(str) |
||||
|
if !e.IsValid() { |
||||
|
return fmt.Errorf("%s is not a valid TagKind", str) |
||||
|
} |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
// MarshalGQL turns it into a JSON string
|
||||
|
func (e TagKind) MarshalGQL(w io.Writer) { |
||||
|
fmt.Fprint(w, "\""+e.String(), "\"") |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue