Added Channel model and API for it
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/model/channel"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/internal/store"
|
||||||
|
"git.aiterp.net/rpdata/api/model/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := store.Init()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logs, err := log.List(32768)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
added := make(map[string]bool, 1024)
|
||||||
|
for _, log := range logs {
|
||||||
|
if added[log.Channel] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := channel.Ensure(log.Channel, false)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, log.ID, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
added[log.Channel] = true
|
||||||
|
|
||||||
|
fmt.Println(log.Channel, "ensured")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ build:
|
|||||||
go build -ldflags="-s -w" -o $(INSTALL_PATH)/usr/bin/rpdata-lb2charimport ./cmd/rpdata-lb2charimport
|
go build -ldflags="-s -w" -o $(INSTALL_PATH)/usr/bin/rpdata-lb2charimport ./cmd/rpdata-lb2charimport
|
||||||
go build -ldflags="-s -w" -o $(INSTALL_PATH)/usr/bin/rpdata-lb2logimport ./cmd/rpdata-lb2logimport
|
go build -ldflags="-s -w" -o $(INSTALL_PATH)/usr/bin/rpdata-lb2logimport ./cmd/rpdata-lb2logimport
|
||||||
go build -ldflags="-s -w" -o $(INSTALL_PATH)/usr/bin/rpdata-wikifileimport ./cmd/rpdata-wikifileimport
|
go build -ldflags="-s -w" -o $(INSTALL_PATH)/usr/bin/rpdata-wikifileimport ./cmd/rpdata-wikifileimport
|
||||||
|
go build -ldflags="-s -w" -o $(INSTALL_PATH)/usr/bin/rpdata-ensurechannels ./cmd/rpdata-ensurechannels
|
||||||
|
|
||||||
install:
|
install:
|
||||||
cp $(INSTALL_PATH)/usr/bin/* /usr/local/bin/
|
cp $(INSTALL_PATH)/usr/bin/* /usr/local/bin/
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package channel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/internal/store"
|
||||||
|
"github.com/globalsign/mgo"
|
||||||
|
"github.com/globalsign/mgo/bson"
|
||||||
|
)
|
||||||
|
|
||||||
|
var collection *mgo.Collection
|
||||||
|
|
||||||
|
// ErrInvalidName is an error for an invalid channel name
|
||||||
|
var ErrInvalidName = errors.New("Invalid channel name")
|
||||||
|
|
||||||
|
// A Channel represents information abount an IRC RP channel, and whether it should be logged
|
||||||
|
type Channel struct {
|
||||||
|
Name string `bson:"_id"`
|
||||||
|
Logged bool `bson:"logged"`
|
||||||
|
Hub bool `bson:"hub"`
|
||||||
|
Event string `bson:"event,omitempty"`
|
||||||
|
Location string `bson:"location,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit edits the channel
|
||||||
|
func (channel *Channel) Edit(logged, hub *bool, event, location *string) error {
|
||||||
|
changes := bson.M{}
|
||||||
|
changed := *channel
|
||||||
|
|
||||||
|
if logged != nil && channel.Logged != *logged {
|
||||||
|
changes["logged"] = *logged
|
||||||
|
changed.Logged = *logged
|
||||||
|
}
|
||||||
|
if hub != nil && channel.Hub != *hub {
|
||||||
|
changes["hub"] = *hub
|
||||||
|
changed.Hub = *hub
|
||||||
|
}
|
||||||
|
if event != nil && channel.Event != *event {
|
||||||
|
changes["event"] = *event
|
||||||
|
changed.Event = *event
|
||||||
|
}
|
||||||
|
if location != nil && channel.Event != *location {
|
||||||
|
changes["location"] = *location
|
||||||
|
changed.Location = *location
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(changes) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := collection.UpdateId(channel.Name, bson.M{"$set": changes})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*channel = changed
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes the channel information from the database.
|
||||||
|
func (channel *Channel) Remove() error {
|
||||||
|
return collection.RemoveId(channel.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure ensures a channel's existence. It does not change `logged` if there is
|
||||||
|
// an existing channel.
|
||||||
|
func Ensure(name string, logged bool) (Channel, error) {
|
||||||
|
channel, err := FindName(name)
|
||||||
|
if err == mgo.ErrNotFound {
|
||||||
|
return New(name, logged, false, "", "")
|
||||||
|
} else if err != nil {
|
||||||
|
return Channel{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new channel
|
||||||
|
func New(name string, logged, hub bool, event, location string) (Channel, error) {
|
||||||
|
if len(name) < 3 && !strings.HasPrefix(name, "#") {
|
||||||
|
return Channel{}, ErrInvalidName
|
||||||
|
}
|
||||||
|
|
||||||
|
channel := Channel{
|
||||||
|
Name: name,
|
||||||
|
Logged: logged,
|
||||||
|
Hub: hub,
|
||||||
|
Event: event,
|
||||||
|
Location: location,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := collection.Insert(channel)
|
||||||
|
if err != nil {
|
||||||
|
return Channel{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindName finds a channel by its id (its name).
|
||||||
|
func FindName(name string) (Channel, error) {
|
||||||
|
channel := Channel{}
|
||||||
|
err := collection.FindId(name).One(&channel)
|
||||||
|
|
||||||
|
return channel, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// List finds channels, if logged is true it will be limited to logged
|
||||||
|
// channels
|
||||||
|
func List(logged bool) ([]Channel, error) {
|
||||||
|
query := bson.M{}
|
||||||
|
if logged {
|
||||||
|
query["logged"] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
channels := make([]Channel, 0, 32)
|
||||||
|
err := collection.Find(query).All(&channels)
|
||||||
|
|
||||||
|
return channels, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
store.HandleInit(func(db *mgo.Database) {
|
||||||
|
collection = db.C("common.channels")
|
||||||
|
|
||||||
|
collection.EnsureIndexKey("logged")
|
||||||
|
collection.EnsureIndexKey("hub")
|
||||||
|
collection.EnsureIndexKey("event")
|
||||||
|
collection.EnsureIndexKey("location")
|
||||||
|
})
|
||||||
|
}
|
||||||
+9
-3
@@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.aiterp.net/rpdata/api/internal/store"
|
"git.aiterp.net/rpdata/api/internal/store"
|
||||||
|
"git.aiterp.net/rpdata/api/model/channel"
|
||||||
"git.aiterp.net/rpdata/api/model/character"
|
"git.aiterp.net/rpdata/api/model/character"
|
||||||
"git.aiterp.net/rpdata/api/model/counter"
|
"git.aiterp.net/rpdata/api/model/counter"
|
||||||
|
|
||||||
@@ -39,17 +40,22 @@ type Log struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Log
|
// New creates a new Log
|
||||||
func New(date time.Time, channel, title, event, description string, open bool) (Log, error) {
|
func New(date time.Time, channelName, title, event, description string, open bool) (Log, error) {
|
||||||
nextID, err := counter.Next("auto_increment", "Log")
|
nextID, err := counter.Next("auto_increment", "Log")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Log{}, err
|
return Log{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = channel.Ensure(channelName, open)
|
||||||
|
if err != nil {
|
||||||
|
return Log{}, err
|
||||||
|
}
|
||||||
|
|
||||||
log := Log{
|
log := Log{
|
||||||
ID: MakeLogID(date, channel),
|
ID: MakeLogID(date, channelName),
|
||||||
ShortID: "L" + strconv.Itoa(nextID),
|
ShortID: "L" + strconv.Itoa(nextID),
|
||||||
Date: date,
|
Date: date,
|
||||||
Channel: channel,
|
Channel: channelName,
|
||||||
Title: title,
|
Title: title,
|
||||||
Event: event,
|
Event: event,
|
||||||
Description: description,
|
Description: description,
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
package resolver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.aiterp.net/rpdata/api/internal/session"
|
||||||
|
"git.aiterp.net/rpdata/api/model/channel"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChannelResolver for the Channel graphql type
|
||||||
|
type ChannelResolver struct{ C channel.Channel }
|
||||||
|
|
||||||
|
// ChannelArgs is args for channel query
|
||||||
|
type ChannelArgs struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channel implements the channel query
|
||||||
|
func (r *QueryResolver) Channel(ctx context.Context, args *ChannelArgs) (*ChannelResolver, error) {
|
||||||
|
channel, err := channel.FindName(args.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ChannelResolver{C: channel}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChannelsArgs is args for channel query
|
||||||
|
type ChannelsArgs struct {
|
||||||
|
Logged *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channels implements the channels query
|
||||||
|
func (r *QueryResolver) Channels(ctx context.Context, args *ChannelsArgs) ([]*ChannelResolver, error) {
|
||||||
|
channels, err := channel.List(args.Logged != nil && *args.Logged)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvers := make([]*ChannelResolver, len(channels))
|
||||||
|
for i := range channels {
|
||||||
|
resolvers[i] = &ChannelResolver{C: channels[i]}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChannelAddEditInput is input for the addChannel mutation
|
||||||
|
type ChannelAddEditInput struct {
|
||||||
|
Name string
|
||||||
|
Logged *bool
|
||||||
|
Hub *bool
|
||||||
|
EventName *string
|
||||||
|
LocationName *string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddChannel resolves the addChannel mutation
|
||||||
|
func (r *MutationResolver) AddChannel(ctx context.Context, args struct{ Input *ChannelAddEditInput }) (*ChannelResolver, error) {
|
||||||
|
user := session.FromContext(ctx).User()
|
||||||
|
if user == nil || !user.Permitted("channel.add") {
|
||||||
|
return nil, ErrUnauthorized
|
||||||
|
}
|
||||||
|
|
||||||
|
logged := args.Input.Logged != nil && *args.Input.Logged
|
||||||
|
hub := args.Input.Hub != nil && *args.Input.Hub
|
||||||
|
eventName := ""
|
||||||
|
if args.Input.EventName != nil {
|
||||||
|
eventName = *args.Input.EventName
|
||||||
|
}
|
||||||
|
locationName := ""
|
||||||
|
if args.Input.LocationName != nil {
|
||||||
|
locationName = *args.Input.LocationName
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := channel.New(args.Input.Name, logged, hub, eventName, locationName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ChannelResolver{C: channel}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditChannel resolves the editChannel mutation
|
||||||
|
func (r *MutationResolver) EditChannel(ctx context.Context, args struct{ Input *ChannelAddEditInput }) (*ChannelResolver, error) {
|
||||||
|
user := session.FromContext(ctx).User()
|
||||||
|
if user == nil || !user.Permitted("channel.edit") {
|
||||||
|
return nil, ErrUnauthorized
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := channel.FindName(args.Input.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = channel.Edit(args.Input.Logged, args.Input.Hub, args.Input.EventName, args.Input.LocationName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ChannelResolver{C: channel}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveChannel resolves the editChannel mutation
|
||||||
|
func (r *MutationResolver) RemoveChannel(ctx context.Context, args ChannelArgs) (*ChannelResolver, error) {
|
||||||
|
user := session.FromContext(ctx).User()
|
||||||
|
if user == nil || !user.Permitted("channel.remove") {
|
||||||
|
return nil, ErrUnauthorized
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := channel.FindName(args.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = channel.Remove()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ChannelResolver{C: channel}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name resolves channel.name
|
||||||
|
func (r *ChannelResolver) Name() string {
|
||||||
|
return r.C.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logged resolves channel.logged
|
||||||
|
func (r *ChannelResolver) Logged() bool {
|
||||||
|
return r.C.Logged
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hub resolves channel.hub
|
||||||
|
func (r *ChannelResolver) Hub() bool {
|
||||||
|
return r.C.Hub
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventName resolves channel.eventName
|
||||||
|
func (r *ChannelResolver) EventName() *string {
|
||||||
|
if r.C.Event == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r.C.Event
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocationName resolves channel.locationName
|
||||||
|
func (r *ChannelResolver) LocationName() *string {
|
||||||
|
if r.C.Location == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &r.C.Location
|
||||||
|
}
|
||||||
@@ -6,7 +6,14 @@ type Query {
|
|||||||
# Find characters by either a list of ids, nicks or an author. Only one parameter at a time
|
# 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!]!
|
characters(ids: [String!], nicks: [String!], author: String): [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 log by ID
|
# Find log by ID
|
||||||
log(id: String): Log
|
log(id: String): Log
|
||||||
|
|
||||||
@@ -51,6 +58,16 @@ type Mutation {
|
|||||||
removeCharacter(id: String!): Character!
|
removeCharacter(id: String!): Character!
|
||||||
|
|
||||||
|
|
||||||
|
# Add a channel
|
||||||
|
addChannel(input: ChannelAddInput!): Channel!
|
||||||
|
|
||||||
|
# Edit a channel
|
||||||
|
editChannel(input: ChannelEditInput!): Channel!
|
||||||
|
|
||||||
|
# Remove a channel
|
||||||
|
removeChannel(name: String!): Channel!
|
||||||
|
|
||||||
|
|
||||||
# Add a new log
|
# Add a new log
|
||||||
addLog(input: LogAddInput!): Log!
|
addLog(input: LogAddInput!): Log!
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user