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