This commit is contained in:
@@ -8,6 +8,8 @@ import (
|
|||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/graph2"
|
"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"
|
"git.aiterp.net/rpdata/api/internal/store"
|
||||||
logModel "git.aiterp.net/rpdata/api/model/log"
|
logModel "git.aiterp.net/rpdata/api/model/log"
|
||||||
"github.com/99designs/gqlgen/handler"
|
"github.com/99designs/gqlgen/handler"
|
||||||
@@ -20,7 +22,15 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
http.Handle("/", handler.Playground("RPData API", "/query"))
|
http.Handle("/", handler.Playground("RPData API", "/query"))
|
||||||
http.Handle("/query", handler.GraphQL(
|
http.Handle("/query", queryHandler())
|
||||||
|
|
||||||
|
go updateCharacters()
|
||||||
|
|
||||||
|
log.Fatal(http.ListenAndServe(":8081", nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func queryHandler() http.HandlerFunc {
|
||||||
|
handler := handler.GraphQL(
|
||||||
graph2.New(),
|
graph2.New(),
|
||||||
handler.RecoverFunc(func(ctx context.Context, err interface{}) error {
|
handler.RecoverFunc(func(ctx context.Context, err interface{}) error {
|
||||||
// send this panic somewhere
|
// send this panic somewhere
|
||||||
@@ -29,11 +39,16 @@ func main() {
|
|||||||
|
|
||||||
return fmt.Errorf("shit")
|
return fmt.Errorf("shit")
|
||||||
}),
|
}),
|
||||||
))
|
)
|
||||||
|
|
||||||
go updateCharacters()
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
l := loader.New()
|
||||||
|
r = r.WithContext(l.ToContext(r.Context()))
|
||||||
|
|
||||||
log.Fatal(http.ListenAndServe(":8081", nil))
|
r = auth.RequestWithToken(r)
|
||||||
|
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateCharacters() {
|
func updateCharacters() {
|
||||||
|
|||||||
@@ -23,5 +23,9 @@ models:
|
|||||||
model: git.aiterp.net/rpdata/api/model/channel.Filter
|
model: git.aiterp.net/rpdata/api/model/channel.Filter
|
||||||
Post:
|
Post:
|
||||||
model: git.aiterp.net/rpdata/api/model/log.Post
|
model: git.aiterp.net/rpdata/api/model/log.Post
|
||||||
|
Log:
|
||||||
|
model: git.aiterp.net/rpdata/api/model/log.Log
|
||||||
|
LogsFilter:
|
||||||
|
model: git.aiterp.net/rpdata/api/model/log.Filter
|
||||||
Date:
|
Date:
|
||||||
model: git.aiterp.net/rpdata/api/model/scalars.Date
|
model: git.aiterp.net/rpdata/api/model/scalars.Date
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package queries
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/internal/loader"
|
||||||
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *resolver) Log(ctx context.Context, id string) (log.Log, error) {
|
||||||
|
return log.FindID(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *resolver) Logs(ctx context.Context, filter *log.Filter) ([]log.Log, error) {
|
||||||
|
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.ChannelName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logs, nil
|
||||||
|
}
|
||||||
@@ -25,9 +25,17 @@ type Query {
|
|||||||
posts(ids: [String!]!): [Post!]!
|
posts(ids: [String!]!): [Post!]!
|
||||||
|
|
||||||
|
|
||||||
|
# Find log by ID
|
||||||
|
log(id: String!): Log!
|
||||||
|
|
||||||
|
# Find logs
|
||||||
|
logs(filter: LogsFilter): [Log!]!
|
||||||
|
|
||||||
|
|
||||||
# Find all distinct tags used in stories
|
# Find all distinct tags used in stories
|
||||||
tags: [Tag!]!
|
tags: [Tag!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# A Date represents a RFC3339 encoded date with up to millisecond precision.
|
||||||
scalar Date
|
scalar Date
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# 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.
|
||||||
|
event: 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
|
||||||
|
}
|
||||||
+1
-22
@@ -7,26 +7,5 @@ type Filter struct {
|
|||||||
Channels *[]string
|
Channels *[]string
|
||||||
Events *[]string
|
Events *[]string
|
||||||
Open *bool
|
Open *bool
|
||||||
Limit *int32
|
Limit int
|
||||||
}
|
|
||||||
|
|
||||||
// NewFilter makes a new filter
|
|
||||||
func NewFilter() *Filter {
|
|
||||||
return &Filter{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLimit adds a max amount of results to be returned.
|
|
||||||
func (filter *Filter) WithLimit(limit int) *Filter {
|
|
||||||
limitPtr := int32(limit)
|
|
||||||
filter.Limit = &limitPtr
|
|
||||||
|
|
||||||
return filter
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithOpen filters on whether a log is open.
|
|
||||||
func (filter *Filter) WithOpen(limit int) *Filter {
|
|
||||||
limitPtr := int32(limit)
|
|
||||||
filter.Limit = &limitPtr
|
|
||||||
|
|
||||||
return filter
|
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-40
@@ -31,7 +31,7 @@ type Log struct {
|
|||||||
ID string `bson:"_id"`
|
ID string `bson:"_id"`
|
||||||
ShortID string `bson:"shortId"`
|
ShortID string `bson:"shortId"`
|
||||||
Date time.Time `bson:"date"`
|
Date time.Time `bson:"date"`
|
||||||
Channel string `bson:"channel"`
|
ChannelName string `bson:"channel"`
|
||||||
Title string `bson:"title,omitempty"`
|
Title string `bson:"title,omitempty"`
|
||||||
Event string `bson:"event,omitempty"`
|
Event string `bson:"event,omitempty"`
|
||||||
Description string `bson:"description,omitempty"`
|
Description string `bson:"description,omitempty"`
|
||||||
@@ -55,7 +55,7 @@ func New(date time.Time, channelName, title, event, description string, open boo
|
|||||||
ID: MakeLogID(date, channelName),
|
ID: MakeLogID(date, channelName),
|
||||||
ShortID: "L" + strconv.Itoa(nextID),
|
ShortID: "L" + strconv.Itoa(nextID),
|
||||||
Date: date,
|
Date: date,
|
||||||
Channel: channelName,
|
ChannelName: channelName,
|
||||||
Title: title,
|
Title: title,
|
||||||
Event: event,
|
Event: event,
|
||||||
Description: description,
|
Description: description,
|
||||||
@@ -84,43 +84,44 @@ func FindID(id string) (Log, error) {
|
|||||||
// List lists all logs
|
// List lists all logs
|
||||||
func List(filter *Filter) ([]Log, error) {
|
func List(filter *Filter) ([]Log, error) {
|
||||||
query := bson.M{}
|
query := bson.M{}
|
||||||
|
|
||||||
// Run a text search
|
|
||||||
if filter.Search != nil {
|
|
||||||
searchResults := make([]string, 0, 32)
|
|
||||||
|
|
||||||
postMutex.RLock()
|
|
||||||
err := postCollection.Find(bson.M{"$text": bson.M{"$search": *filter.Search}}).Distinct("logId", &searchResults)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
postMutex.RUnlock()
|
|
||||||
|
|
||||||
// Posts always use shortId to refer to the log
|
|
||||||
query["shortId"] = bson.M{"$in": searchResults}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find logs including any of the specified events and channels
|
|
||||||
if filter.Channels != nil {
|
|
||||||
query["channel"] = bson.M{"$in": *filter.Channels}
|
|
||||||
}
|
|
||||||
if filter.Events != nil {
|
|
||||||
query["event"] = bson.M{"$in": *filter.Events}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find logs including all of the specified character IDs.
|
|
||||||
if filter.Characters != nil {
|
|
||||||
query["characterIds"] = bson.M{"$all": *filter.Characters}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limit to only open logs
|
|
||||||
if filter.Open != nil {
|
|
||||||
query["open"] = *filter.Open
|
|
||||||
}
|
|
||||||
|
|
||||||
limit := 0
|
limit := 0
|
||||||
if filter.Limit != nil {
|
|
||||||
limit = int(*filter.Limit)
|
if filter != nil {
|
||||||
|
// Run a text search
|
||||||
|
if filter.Search != nil {
|
||||||
|
searchResults := make([]string, 0, 32)
|
||||||
|
|
||||||
|
postMutex.RLock()
|
||||||
|
err := postCollection.Find(bson.M{"$text": bson.M{"$search": *filter.Search}}).Distinct("logId", &searchResults)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
postMutex.RUnlock()
|
||||||
|
|
||||||
|
// Posts always use shortId to refer to the log
|
||||||
|
query["shortId"] = bson.M{"$in": searchResults}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find logs including any of the specified events and channels
|
||||||
|
if filter.Channels != nil {
|
||||||
|
query["channel"] = bson.M{"$in": *filter.Channels}
|
||||||
|
}
|
||||||
|
if filter.Events != nil {
|
||||||
|
query["event"] = bson.M{"$in": *filter.Events}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find logs including all of the specified character IDs.
|
||||||
|
if filter.Characters != nil {
|
||||||
|
query["characterIds"] = bson.M{"$all": *filter.Characters}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit to only open logs
|
||||||
|
if filter.Open != nil {
|
||||||
|
query["open"] = *filter.Open
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the limit from the filter
|
||||||
|
limit = filter.Limit
|
||||||
}
|
}
|
||||||
|
|
||||||
return listLog(query, limit)
|
return listLog(query, limit)
|
||||||
@@ -168,9 +169,20 @@ func (log *Log) Edit(title *string, event *string, description *string, open *bo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Characters get all the characters for the character IDs stored in the
|
||||||
|
// log file.
|
||||||
|
func (log *Log) Characters() ([]character.Character, error) {
|
||||||
|
return character.ListIDs(log.CharacterIDs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channel gets the channel.
|
||||||
|
func (log *Log) Channel() (channel.Channel, error) {
|
||||||
|
return channel.FindName(log.ChannelName)
|
||||||
|
}
|
||||||
|
|
||||||
// Posts gets all the posts under the log. If no kinds are specified, it
|
// Posts gets all the posts under the log. If no kinds are specified, it
|
||||||
// will get all posts
|
// will get all posts
|
||||||
func (log *Log) Posts(kinds ...string) ([]Post, error) {
|
func (log *Log) Posts(kinds []string) ([]Post, error) {
|
||||||
postMutex.RLock()
|
postMutex.RLock()
|
||||||
defer postMutex.RUnlock()
|
defer postMutex.RUnlock()
|
||||||
|
|
||||||
@@ -238,7 +250,7 @@ func (log *Log) UpdateCharacters() error {
|
|||||||
characterUpdateMutex.Lock()
|
characterUpdateMutex.Lock()
|
||||||
defer characterUpdateMutex.Unlock()
|
defer characterUpdateMutex.Unlock()
|
||||||
|
|
||||||
posts, err := log.Posts()
|
posts, err := log.Posts([]string{"action", "text", "chars"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user