Browse Source

Added Channel model and API for it

1.0
Gisle Aune 7 years ago
parent
commit
fcce379dea
  1. 42
      cmd/rpdata-ensurechannels/main.go
  2. 1
      makefile
  3. 133
      model/channel/channel.go
  4. 12
      model/log/log.go
  5. 154
      resolver/channel.go
  6. 17
      schema/root.graphql
  7. 51
      schema/types/channel.graphql

42
cmd/rpdata-ensurechannels/main.go

@ -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")
}
}

1
makefile

@ -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/

133
model/channel/channel.go

@ -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")
})
}

12
model/log/log.go

@ -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,

154
resolver/channel.go

@ -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
}

17
schema/root.graphql

@ -7,6 +7,13 @@ type Query {
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!

51
schema/types/channel.graphql

@ -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
}
Loading…
Cancel
Save