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-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-ensurechannels ./cmd/rpdata-ensurechannels
|
||||
|
||||
install:
|
||||
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"
|
||||
|
||||
"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/counter"
|
||||
|
||||
@@ -39,17 +40,22 @@ type Log struct {
|
||||
}
|
||||
|
||||
// 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")
|
||||
if err != nil {
|
||||
return Log{}, err
|
||||
}
|
||||
|
||||
_, err = channel.Ensure(channelName, open)
|
||||
if err != nil {
|
||||
return Log{}, err
|
||||
}
|
||||
|
||||
log := Log{
|
||||
ID: MakeLogID(date, channel),
|
||||
ID: MakeLogID(date, channelName),
|
||||
ShortID: "L" + strconv.Itoa(nextID),
|
||||
Date: date,
|
||||
Channel: channel,
|
||||
Channel: channelName,
|
||||
Title: title,
|
||||
Event: event,
|
||||
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
|
||||
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
|
||||
log(id: String): Log
|
||||
|
||||
@@ -51,6 +58,16 @@ type Mutation {
|
||||
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
|
||||
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