Gisle Aune
7 years ago
7 changed files with 407 additions and 3 deletions
-
42cmd/rpdata-ensurechannels/main.go
-
1makefile
-
133model/channel/channel.go
-
12model/log/log.go
-
154resolver/channel.go
-
17schema/root.graphql
-
51schema/types/channel.graphql
@ -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") |
||||
|
} |
||||
|
} |
@ -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") |
||||
|
}) |
||||
|
} |
@ -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 |
||||
|
} |
@ -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 |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue