Merge pull request #136 from velour/configdefault

Configdefault
This commit is contained in:
Chris Sexton 2019-01-22 08:56:40 -05:00 committed by GitHub
commit 0ee92123c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 113 additions and 173 deletions

View File

@ -56,7 +56,7 @@ func New(config *config.Config, connector Connector) Bot {
users := []user.User{ users := []user.User{
user.User{ user.User{
Name: config.Get("Nick"), Name: config.Get("Nick", "bot"),
}, },
} }
@ -76,11 +76,7 @@ func New(config *config.Config, connector Connector) Bot {
bot.migrateDB() bot.migrateDB()
http.HandleFunc("/", bot.serveRoot) http.HandleFunc("/", bot.serveRoot)
addr := config.Get("HttpAddr") addr := config.Get("HttpAddr", "127.0.0.1:1337")
if addr == "" {
addr = "127.0.0.1:1337"
config.Set("HttpAddr", addr)
}
go http.ListenAndServe(addr, nil) go http.ListenAndServe(addr, nil)
connector.RegisterMessageReceived(bot.MsgReceived) connector.RegisterMessageReceived(bot.MsgReceived)
@ -172,12 +168,8 @@ func (b *bot) serveRoot(w http.ResponseWriter, r *http.Request) {
// Checks if message is a command and returns its curtailed version // Checks if message is a command and returns its curtailed version
func IsCmd(c *config.Config, message string) (bool, string) { func IsCmd(c *config.Config, message string) (bool, string) {
cmdcs := c.GetArray("CommandChar") cmdcs := c.GetArray("CommandChar", []string{"!"})
if len(cmdcs) == 0 { botnick := strings.ToLower(c.Get("Nick", "bot"))
cmdcs = []string{"!"}
c.SetArray("CommandChar", cmdcs)
}
botnick := strings.ToLower(c.Get("Nick"))
if botnick == "" { if botnick == "" {
log.Fatalf(`You must run catbase -set nick -val <your bot nick>`) log.Fatalf(`You must run catbase -set nick -val <your bot nick>`)
} }
@ -212,7 +204,7 @@ func IsCmd(c *config.Config, message string) (bool, string) {
} }
func (b *bot) CheckAdmin(nick string) bool { func (b *bot) CheckAdmin(nick string) bool {
for _, u := range b.Config().GetArray("Admins") { for _, u := range b.Config().GetArray("Admins", []string{}) {
if nick == u { if nick == u {
return true return true
} }
@ -240,7 +232,7 @@ func (b *bot) NewUser(nick string) *user.User {
} }
func (b *bot) checkAdmin(nick string) bool { func (b *bot) checkAdmin(nick string) bool {
for _, u := range b.Config().GetArray("Admins") { for _, u := range b.Config().GetArray("Admins", []string{}) {
if nick == u { if nick == u {
return true return true
} }

View File

@ -28,8 +28,8 @@ type Config struct {
// It will check the DB for the key if an env DNE // It will check the DB for the key if an env DNE
// Finally, it will return a zero value if the key does not exist // Finally, it will return a zero value if the key does not exist
// It will attempt to convert the value to a float64 if it exists // It will attempt to convert the value to a float64 if it exists
func (c *Config) GetFloat64(key string) float64 { func (c *Config) GetFloat64(key string, fallback float64) float64 {
f, err := strconv.ParseFloat(c.GetString(key), 64) f, err := strconv.ParseFloat(c.GetString(key, fmt.Sprintf("%f", fallback)), 64)
if err != nil { if err != nil {
return 0.0 return 0.0
} }
@ -41,8 +41,8 @@ func (c *Config) GetFloat64(key string) float64 {
// It will check the DB for the key if an env DNE // It will check the DB for the key if an env DNE
// Finally, it will return a zero value if the key does not exist // Finally, it will return a zero value if the key does not exist
// It will attempt to convert the value to an int if it exists // It will attempt to convert the value to an int if it exists
func (c *Config) GetInt(key string) int { func (c *Config) GetInt(key string, fallback int) int {
i, err := strconv.Atoi(c.GetString(key)) i, err := strconv.Atoi(c.GetString(key, strconv.Itoa(fallback)))
if err != nil { if err != nil {
return 0 return 0
} }
@ -50,8 +50,8 @@ func (c *Config) GetInt(key string) int {
} }
// Get is a shortcut for GetString // Get is a shortcut for GetString
func (c *Config) Get(key string) string { func (c *Config) Get(key, fallback string) string {
return c.GetString(key) return c.GetString(key, fallback)
} }
func envkey(key string) string { func envkey(key string) string {
@ -65,7 +65,7 @@ func envkey(key string) string {
// It will check the DB for the key if an env DNE // It will check the DB for the key if an env DNE
// Finally, it will return a zero value if the key does not exist // Finally, it will return a zero value if the key does not exist
// It will convert the value to a string if it exists // It will convert the value to a string if it exists
func (c *Config) GetString(key string) string { func (c *Config) GetString(key, fallback string) string {
key = strings.ToLower(key) key = strings.ToLower(key)
if v, found := os.LookupEnv(envkey(key)); found { if v, found := os.LookupEnv(envkey(key)); found {
return v return v
@ -75,7 +75,7 @@ func (c *Config) GetString(key string) string {
err := c.DB.Get(&configValue, q, key) err := c.DB.Get(&configValue, q, key)
if err != nil { if err != nil {
log.Printf("WARN: Key %s is empty", key) log.Printf("WARN: Key %s is empty", key)
return "" return fallback
} }
return configValue return configValue
} }
@ -86,10 +86,10 @@ func (c *Config) GetString(key string) string {
// It will check the DB for the key if an env DNE // It will check the DB for the key if an env DNE
// Finally, it will return a zero value if the key does not exist // Finally, it will return a zero value if the key does not exist
// This will do no conversion. // This will do no conversion.
func (c *Config) GetArray(key string) []string { func (c *Config) GetArray(key string, fallback []string) []string {
val := c.GetString(key) val := c.GetString(key, "")
if val == "" { if val == "" {
return []string{} return fallback
} }
return strings.Split(val, ";;") return strings.Split(val, ";;")
} }

View File

@ -10,7 +10,7 @@ func TestSetGet(t *testing.T) {
cfg := ReadConfig(":memory:") cfg := ReadConfig(":memory:")
expected := "value" expected := "value"
cfg.Set("test", expected) cfg.Set("test", expected)
actual := cfg.Get("test") actual := cfg.Get("test", "NOPE")
assert.Equal(t, expected, actual, "Config did not store values") assert.Equal(t, expected, actual, "Config did not store values")
} }
@ -18,6 +18,6 @@ func TestSetGetArray(t *testing.T) {
cfg := ReadConfig(":memory:") cfg := ReadConfig(":memory:")
expected := []string{"a", "b", "c"} expected := []string{"a", "b", "c"}
cfg.SetArray("test", expected) cfg.SetArray("test", expected)
actual := cfg.GetArray("test") actual := cfg.GetArray("test", []string{"NOPE"})
assert.Equal(t, expected, actual, "Config did not store values") assert.Equal(t, expected, actual, "Config did not store values")
} }

View File

@ -2,36 +2,16 @@ package config
import ( import (
"bytes" "bytes"
"html/template"
"log" "log"
"strings" "strings"
"text/template"
) )
var q = ` var q = `
INSERT INTO config VALUES('type','slack');
INSERT INTO config VALUES('nick','{{.Nick}}'); INSERT INTO config VALUES('nick','{{.Nick}}');
INSERT INTO config VALUES('channels','{{.Channel}}'); INSERT INTO config VALUES('channels','{{.Channel}}');
INSERT INTO config VALUES('factoid.quotetime',30);
INSERT INTO config VALUES('reaction.negativereactions','bullshit;;fake;;tableflip;;vomit');
INSERT INTO config VALUES('reaction.positivereactions','+1;;authorized;;aw_yeah;;yeah_man;;joy');
INSERT INTO config VALUES('reaction.generalchance',0.01);
INSERT INTO config VALUES('reaction.harrasschance',0.05);
INSERT INTO config VALUES('commandchar','!;;¡');
INSERT INTO config VALUES('factoid.startupfact','speed test');
INSERT INTO config VALUES('factoid.quotechance',0.99);
INSERT INTO config VALUES('factoid.minlen',4);
INSERT INTO config VALUES('untappd.channels','{{.Channel}}'); INSERT INTO config VALUES('untappd.channels','{{.Channel}}');
INSERT INTO config VALUES('twitch.channels','{{.Channel}}'); INSERT INTO config VALUES('twitch.channels','{{.Channel}}');
INSERT INTO config VALUES('twitch.{{.ChannelKey}}.users','drseabass;;phlyingpenguin;;stack5;;geoffwithaj;;msherms;;eaburns;;sheltim;;rathaus;;rcuhljr');
INSERT INTO config VALUES('twitch.freq',60);
INSERT INTO config VALUES('leftpad.maxlen',50);
INSERT INTO config VALUES('untappd.freq',60);
INSERT INTO config VALUES('your.replacements.0.freq',1);
INSERT INTO config VALUES('your.replacements.0.this','fuck');
INSERT INTO config VALUES('your.replacements.0.that','duck');
INSERT INTO config VALUES('your.replacements','0;;1;;2');
INSERT INTO config VALUES('httpaddr','127.0.0.1:1337');
INSERT INTO config VALUES('your.maxlength',140);
INSERT INTO config VALUES('init',1); INSERT INTO config VALUES('init',1);
` `

View File

@ -87,7 +87,7 @@ func (i *Irc) SendMessage(channel, message string) string {
} }
if throttle == nil { if throttle == nil {
ratePerSec := i.config.GetInt("RatePerSec") ratePerSec := i.config.GetInt("RatePerSec", 5)
throttle = time.Tick(time.Second / time.Duration(ratePerSec)) throttle = time.Tick(time.Second / time.Duration(ratePerSec))
} }
@ -136,17 +136,17 @@ func (i *Irc) Serve() error {
var err error var err error
i.Client, err = irc.DialSSL( i.Client, err = irc.DialSSL(
i.config.Get("Irc.Server"), i.config.Get("Irc.Server", "localhost"),
i.config.Get("Nick"), i.config.Get("Nick", "bot"),
i.config.Get("FullName"), i.config.Get("FullName", "bot"),
i.config.Get("Irc.Pass"), i.config.Get("Irc.Pass", ""),
true, true,
) )
if err != nil { if err != nil {
return fmt.Errorf("%s", err) return fmt.Errorf("%s", err)
} }
for _, c := range i.config.GetArray("channels") { for _, c := range i.config.GetArray("channels", []string{}) {
i.JoinChannel(c) i.JoinChannel(c)
} }
@ -270,7 +270,7 @@ func (i *Irc) buildMessage(inMsg irc.Msg) msg.Message {
} }
channel := inMsg.Args[0] channel := inMsg.Args[0]
if channel == i.config.Get("Nick") { if channel == i.config.Get("Nick", "bot") {
channel = inMsg.Args[0] channel = inMsg.Args[0]
} }

11
main.go
View File

@ -58,7 +58,7 @@ func main() {
log.Printf("Set config %s: %s", *key, *val) log.Printf("Set config %s: %s", *key, *val)
return return
} }
if (*initDB && len(flag.Args()) != 2) || (!*initDB && c.GetInt("init") != 1) { if (*initDB && len(flag.Args()) != 2) || (!*initDB && c.GetInt("init", 0) != 1) {
log.Fatal(`You must run "catbase -init <channel> <nick>"`) log.Fatal(`You must run "catbase -init <channel> <nick>"`)
} else if *initDB { } else if *initDB {
c.SetDefaults(flag.Arg(0), flag.Arg(1)) c.SetDefaults(flag.Arg(0), flag.Arg(1))
@ -67,18 +67,13 @@ func main() {
var client bot.Connector var client bot.Connector
t := c.Get("type") switch c.Get("type", "slack") {
if t == "" {
c.Set("type", "slack")
t = "slack"
}
switch c.Get("type") {
case "irc": case "irc":
client = irc.New(c) client = irc.New(c)
case "slack": case "slack":
client = slack.New(c) client = slack.New(c)
default: default:
log.Fatalf("Unknown connection type: %s", c.Get("type")) log.Fatalf("Unknown connection type: %s", c.Get("type", "UNSET"))
} }
b := bot.New(c, client) b := bot.New(c, client)

View File

@ -65,7 +65,7 @@ func (p *AdminPlugin) Message(message msg.Message) bool {
p.Bot.SendMessage(message.Channel, "You cannot access that key") p.Bot.SendMessage(message.Channel, "You cannot access that key")
return true return true
} else if parts[0] == "get" && len(parts) == 2 { } else if parts[0] == "get" && len(parts) == 2 {
v := p.cfg.Get(parts[1]) v := p.cfg.Get(parts[1], "<unknown>")
p.Bot.SendMessage(message.Channel, fmt.Sprintf("%s: %s", parts[1], v)) p.Bot.SendMessage(message.Channel, fmt.Sprintf("%s: %s", parts[1], v))
return true return true
} }

View File

@ -39,7 +39,7 @@ func TestSet(t *testing.T) {
a, mb := setup(t) a, mb := setup(t)
expected := "test value" expected := "test value"
a.Message(makeMessage("!set test.key " + expected)) a.Message(makeMessage("!set test.key " + expected))
actual := mb.Config().Get("test.key") actual := mb.Config().Get("test.key", "ERR")
assert.Equal(t, expected, actual) assert.Equal(t, expected, actual)
} }
@ -54,7 +54,7 @@ func TestGetValue(t *testing.T) {
func TestGetEmpty(t *testing.T) { func TestGetEmpty(t *testing.T) {
a, mb := setup(t) a, mb := setup(t)
expected := "test.key: " expected := "test.key: <unknown>"
a.Message(makeMessage("!get test.key")) a.Message(makeMessage("!get test.key"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Equal(t, expected, mb.Messages[0]) assert.Equal(t, expected, mb.Messages[0])

View File

@ -52,7 +52,7 @@ func New(bot bot.Bot) *BeersPlugin {
Bot: bot, Bot: bot,
db: bot.DB(), db: bot.DB(),
} }
for _, channel := range bot.Config().GetArray("Untappd.Channels") { for _, channel := range bot.Config().GetArray("Untappd.Channels", []string{}) {
go p.untappdLoop(channel) go p.untappdLoop(channel)
} }
return &p return &p
@ -306,8 +306,8 @@ type Beers struct {
} }
func (p *BeersPlugin) pullUntappd() ([]checkin, error) { func (p *BeersPlugin) pullUntappd() ([]checkin, error) {
token := p.Bot.Config().Get("Untappd.Token") token := p.Bot.Config().Get("Untappd.Token", "NONE")
if token == "" { if token == "NONE" {
return []checkin{}, fmt.Errorf("No untappd token") return []checkin{}, fmt.Errorf("No untappd token")
} }
@ -341,8 +341,8 @@ func (p *BeersPlugin) pullUntappd() ([]checkin, error) {
} }
func (p *BeersPlugin) checkUntappd(channel string) { func (p *BeersPlugin) checkUntappd(channel string) {
token := p.Bot.Config().Get("Untappd.Token") token := p.Bot.Config().Get("Untappd.Token", "NONE")
if token == "" { if token == "NONE" {
log.Println(`Set config value "untappd.token" if you wish to enable untappd`) log.Println(`Set config value "untappd.token" if you wish to enable untappd`)
return return
} }
@ -426,7 +426,7 @@ func (p *BeersPlugin) checkUntappd(channel string) {
} }
func (p *BeersPlugin) untappdLoop(channel string) { func (p *BeersPlugin) untappdLoop(channel string) {
frequency := p.Bot.Config().GetInt("Untappd.Freq") frequency := p.Bot.Config().GetInt("Untappd.Freq", 120)
if frequency == 0 { if frequency == 0 {
return return
} }

View File

@ -159,7 +159,7 @@ func (p *DowntimePlugin) Message(message msg.Message) bool {
for _, e := range entries { for _, e := range entries {
// filter out ZNC entries and ourself // filter out ZNC entries and ourself
if strings.HasPrefix(e.nick, "*") || strings.ToLower(p.Bot.Config().Get("Nick")) == e.nick { if strings.HasPrefix(e.nick, "*") || strings.ToLower(p.Bot.Config().Get("Nick", "bot")) == e.nick {
p.remove(e.nick) p.remove(e.nick)
} else { } else {
tops = fmt.Sprintf("%s%s: %s ", tops, e.nick, time.Now().Sub(e.lastSeen)) tops = fmt.Sprintf("%s%s: %s ", tops, e.nick, time.Now().Sub(e.lastSeen))
@ -203,7 +203,7 @@ func (p *DowntimePlugin) Help(channel string, parts []string) {
// Empty event handler because this plugin does not do anything on event recv // Empty event handler because this plugin does not do anything on event recv
func (p *DowntimePlugin) Event(kind string, message msg.Message) bool { func (p *DowntimePlugin) Event(kind string, message msg.Message) bool {
log.Println(kind, "\t", message) log.Println(kind, "\t", message)
if kind != "PART" && message.User.Name != p.Bot.Config().Get("Nick") { if kind != "PART" && message.User.Name != p.Bot.Config().Get("Nick", "bot") {
// user joined, let's nail them for it // user joined, let's nail them for it
if kind == "NICK" { if kind == "NICK" {
p.record(strings.ToLower(message.Channel)) p.record(strings.ToLower(message.Channel))

View File

@ -64,7 +64,7 @@ func (p *EmojifyMePlugin) Message(message msg.Message) bool {
} }
} }
inertTokens := p.Bot.Config().GetArray("Emojify.Scoreless") inertTokens := p.Bot.Config().GetArray("Emojify.Scoreless", []string{})
emojied := 0.0 emojied := 0.0
emojys := []string{} emojys := []string{}
msg := strings.Replace(strings.ToLower(message.Body), "_", " ", -1) msg := strings.Replace(strings.ToLower(message.Body), "_", " ", -1)
@ -87,7 +87,7 @@ func (p *EmojifyMePlugin) Message(message msg.Message) bool {
} }
} }
if emojied > 0 && rand.Float64() <= p.Bot.Config().GetFloat64("Emojify.Chance")*emojied { if emojied > 0 && rand.Float64() <= p.Bot.Config().GetFloat64("Emojify.Chance", 0.02)*emojied {
for _, e := range emojys { for _, e := range emojys {
p.Bot.React(message.Channel, e, message) p.Bot.React(message.Channel, e, message)
} }

View File

@ -297,13 +297,13 @@ func New(botInst bot.Bot) *Factoid {
log.Fatal(err) log.Fatal(err)
} }
for _, channel := range botInst.Config().GetArray("channels") { for _, channel := range botInst.Config().GetArray("channels", []string{}) {
go p.factTimer(channel) go p.factTimer(channel)
go func(ch string) { go func(ch string) {
// Some random time to start up // Some random time to start up
time.Sleep(time.Duration(15) * time.Second) time.Sleep(time.Duration(15) * time.Second)
if ok, fact := p.findTrigger(p.Bot.Config().Get("Factoid.StartupFact")); ok { if ok, fact := p.findTrigger(p.Bot.Config().Get("Factoid.StartupFact", "speed test")); ok {
p.sayFact(msg.Message{ p.sayFact(msg.Message{
Channel: ch, Channel: ch,
Body: "speed test", // BUG: This is defined in the config too Body: "speed test", // BUG: This is defined in the config too
@ -430,7 +430,7 @@ func (p *Factoid) sayFact(message msg.Message, fact factoid) {
// trigger checks the message for its fitness to be a factoid and then hauls // trigger checks the message for its fitness to be a factoid and then hauls
// the message off to sayFact for processing if it is in fact a trigger // the message off to sayFact for processing if it is in fact a trigger
func (p *Factoid) trigger(message msg.Message) bool { func (p *Factoid) trigger(message msg.Message) bool {
minLen := p.Bot.Config().GetInt("Factoid.MinLen") minLen := p.Bot.Config().GetInt("Factoid.MinLen", 4)
if len(message.Body) > minLen || message.Command || message.Body == "..." { if len(message.Body) > minLen || message.Command || message.Body == "..." {
if ok, fact := p.findTrigger(message.Body); ok { if ok, fact := p.findTrigger(message.Body); ok {
p.sayFact(message, *fact) p.sayFact(message, *fact)
@ -691,7 +691,7 @@ func (p *Factoid) randomFact() *factoid {
// factTimer spits out a fact at a given interval and with given probability // factTimer spits out a fact at a given interval and with given probability
func (p *Factoid) factTimer(channel string) { func (p *Factoid) factTimer(channel string) {
quoteTime := p.Bot.Config().GetInt("Factoid.QuoteTime") quoteTime := p.Bot.Config().GetInt("Factoid.QuoteTime", 30)
if quoteTime == 0 { if quoteTime == 0 {
quoteTime = 30 quoteTime = 30
p.Bot.Config().Set("Factoid.QuoteTime", "30") p.Bot.Config().Set("Factoid.QuoteTime", "30")
@ -710,7 +710,7 @@ func (p *Factoid) factTimer(channel string) {
tdelta := time.Since(lastmsg.Time) tdelta := time.Since(lastmsg.Time)
earlier := time.Since(myLastMsg) > tdelta earlier := time.Since(myLastMsg) > tdelta
chance := rand.Float64() chance := rand.Float64()
quoteChance := p.Bot.Config().GetFloat64("Factoid.QuoteChance") quoteChance := p.Bot.Config().GetFloat64("Factoid.QuoteChance", 0.99)
if quoteChance == 0.0 { if quoteChance == 0.0 {
quoteChance = 0.99 quoteChance = 0.99
p.Bot.Config().Set("Factoid.QuoteChance", "0.99") p.Bot.Config().Set("Factoid.QuoteChance", "0.99")

View File

@ -150,7 +150,7 @@ func (p *FirstPlugin) Message(message msg.Message) bool {
} }
func (p *FirstPlugin) allowed(message msg.Message) bool { func (p *FirstPlugin) allowed(message msg.Message) bool {
for _, msg := range p.Bot.Config().GetArray("Bad.Msgs") { for _, msg := range p.Bot.Config().GetArray("Bad.Msgs", []string{}) {
match, err := regexp.MatchString(msg, strings.ToLower(message.Body)) match, err := regexp.MatchString(msg, strings.ToLower(message.Body))
if err != nil { if err != nil {
log.Println("Bad regexp: ", err) log.Println("Bad regexp: ", err)
@ -160,13 +160,13 @@ func (p *FirstPlugin) allowed(message msg.Message) bool {
return false return false
} }
} }
for _, host := range p.Bot.Config().GetArray("Bad.Hosts") { for _, host := range p.Bot.Config().GetArray("Bad.Hosts", []string{}) {
if host == message.Host { if host == message.Host {
log.Println("Disallowing first: ", message.User.Name, ":", message.Body) log.Println("Disallowing first: ", message.User.Name, ":", message.Body)
return false return false
} }
} }
for _, nick := range p.Bot.Config().GetArray("Bad.Nicks") { for _, nick := range p.Bot.Config().GetArray("Bad.Nicks", []string{}) {
if nick == message.User.Name { if nick == message.User.Name {
log.Println("Disallowing first: ", message.User.Name, ":", message.Body) log.Println("Disallowing first: ", message.User.Name, ":", message.Body)
return false return false

View File

@ -8,7 +8,6 @@ import (
"fmt" "fmt"
"log" "log"
"regexp" "regexp"
"strconv"
"strings" "strings"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
@ -27,7 +26,7 @@ type InventoryPlugin struct {
// New creates a new InventoryPlugin with the Plugin interface // New creates a new InventoryPlugin with the Plugin interface
func New(bot bot.Bot) *InventoryPlugin { func New(bot bot.Bot) *InventoryPlugin {
config := bot.Config() config := bot.Config()
nick := config.Get("nick") nick := config.Get("nick", "bot")
r1, err := regexp.Compile("take this (.+)") r1, err := regexp.Compile("take this (.+)")
checkerr(err) checkerr(err)
r2, err := regexp.Compile("have a (.+)") r2, err := regexp.Compile("have a (.+)")
@ -202,11 +201,7 @@ func (p *InventoryPlugin) addItem(m msg.Message, i string) bool {
return true return true
} }
var removed string var removed string
max := p.config.GetInt("inventory.max") max := p.config.GetInt("inventory.max", 10)
if max == 0 {
max = 10
p.config.Set("inventory.max", strconv.Itoa(max))
}
if p.count() > max { if p.count() > max {
removed = p.removeRandom() removed = p.removeRandom()
} }

View File

@ -45,13 +45,9 @@ func (p *LeftpadPlugin) Message(message msg.Message) bool {
p.bot.SendMessage(message.Channel, "Invalid padding number") p.bot.SendMessage(message.Channel, "Invalid padding number")
return true return true
} }
maxLen, who := p.config.GetInt("LeftPad.MaxLen"), p.config.Get("LeftPad.Who") maxLen, who := p.config.GetInt("LeftPad.MaxLen", 50), p.config.Get("LeftPad.Who", "Putin")
if who == "" {
who = "Putin"
p.config.Set("LeftPad.MaxLen", who)
}
if length > maxLen && maxLen > 0 { if length > maxLen && maxLen > 0 {
msg := fmt.Sprintf("%s would kill me if I did that.", p.config.Get("LeftPad.Who")) msg := fmt.Sprintf("%s would kill me if I did that.", who)
p.bot.SendMessage(message.Channel, msg) p.bot.SendMessage(message.Channel, msg)
return true return true
} }

View File

@ -66,7 +66,7 @@ func TestNoMaxLen(t *testing.T) {
func Test50Padding(t *testing.T) { func Test50Padding(t *testing.T) {
p, mb := makePlugin(t) p, mb := makePlugin(t)
p.config.Set("LeftPad.MaxLen", "50") p.config.Set("LeftPad.MaxLen", "50")
assert.Equal(t, 50, p.config.GetInt("LeftPad.MaxLen")) assert.Equal(t, 50, p.config.GetInt("LeftPad.MaxLen", 100))
p.Message(makeMessage("!leftpad dicks 100 dicks")) p.Message(makeMessage("!leftpad dicks 100 dicks"))
assert.Len(t, mb.Messages, 1) assert.Len(t, mb.Messages, 1)
assert.Contains(t, mb.Messages[0], "kill me") assert.Contains(t, mb.Messages[0], "kill me")

View File

@ -24,23 +24,23 @@ func New(bot bot.Bot) *ReactionPlugin {
func (p *ReactionPlugin) Message(message msg.Message) bool { func (p *ReactionPlugin) Message(message msg.Message) bool {
harrass := false harrass := false
for _, nick := range p.Config.GetArray("Reaction.HarrassList") { for _, nick := range p.Config.GetArray("Reaction.HarrassList", []string{}) {
if message.User.Name == nick { if message.User.Name == nick {
harrass = true harrass = true
break break
} }
} }
chance := p.Config.GetFloat64("Reaction.GeneralChance") chance := p.Config.GetFloat64("Reaction.GeneralChance", 0.01)
negativeWeight := 1 negativeWeight := 1
if harrass { if harrass {
chance = p.Config.GetFloat64("Reaction.HarrassChance") chance = p.Config.GetFloat64("Reaction.HarrassChance", 0.05)
negativeWeight = p.Config.GetInt("Reaction.NegativeHarrassmentMultiplier") negativeWeight = p.Config.GetInt("Reaction.NegativeHarrassmentMultiplier", 2)
} }
if rand.Float64() < chance { if rand.Float64() < chance {
numPositiveReactions := len(p.Config.GetArray("Reaction.PositiveReactions")) numPositiveReactions := len(p.Config.GetArray("Reaction.PositiveReactions", []string{}))
numNegativeReactions := len(p.Config.GetArray("Reaction.NegativeReactions")) numNegativeReactions := len(p.Config.GetArray("Reaction.NegativeReactions", []string{}))
maxIndex := numPositiveReactions + numNegativeReactions*negativeWeight maxIndex := numPositiveReactions + numNegativeReactions*negativeWeight
@ -49,11 +49,11 @@ func (p *ReactionPlugin) Message(message msg.Message) bool {
reaction := "" reaction := ""
if index < numPositiveReactions { if index < numPositiveReactions {
reaction = p.Config.GetArray("Reaction.PositiveReactions")[index] reaction = p.Config.GetArray("Reaction.PositiveReactions", []string{})[index]
} else { } else {
index -= numPositiveReactions index -= numPositiveReactions
index %= numNegativeReactions index %= numNegativeReactions
reaction = p.Config.GetArray("Reaction.NegativeReactions")[index] reaction = p.Config.GetArray("Reaction.NegativeReactions", []string{})[index]
} }
p.Bot.React(message.Channel, reaction, message) p.Bot.React(message.Channel, reaction, message)

View File

@ -122,11 +122,7 @@ func (p *ReminderPlugin) Message(message msg.Message) bool {
what := strings.Join(parts[6:], " ") what := strings.Join(parts[6:], " ")
for i := 0; when.Before(endTime); i++ { for i := 0; when.Before(endTime); i++ {
max := p.config.GetInt("Reminder.MaxBatchAdd") max := p.config.GetInt("Reminder.MaxBatchAdd", 10)
if max == 0 {
max = 10
p.config.Set("reminder.maxbatchadd", strconv.Itoa(max))
}
if i >= max { if i >= max {
p.Bot.SendMessage(channel, "Easy cowboy, that's a lot of reminders. I'll add some of them.") p.Bot.SendMessage(channel, "Easy cowboy, that's a lot of reminders. I'll add some of them.")
doConfirm = false doConfirm = false

View File

@ -136,7 +136,7 @@ func (p *RPGPlugin) RegisterWeb() *string {
} }
func (p *RPGPlugin) ReplyMessage(message msg.Message, identifier string) bool { func (p *RPGPlugin) ReplyMessage(message msg.Message, identifier string) bool {
if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Get("Nick")) { if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Get("Nick", "bot")) {
if b, ok := p.listenFor[identifier]; ok { if b, ok := p.listenFor[identifier]; ok {
var res int var res int

View File

@ -59,14 +59,8 @@ func (g *game) scheduleDecrement() {
if g.timers[0] != nil { if g.timers[0] != nil {
g.timers[0].Stop() g.timers[0].Stop()
} }
minDec := g.bot.Config().GetInt("Sisyphus.MinDecrement") minDec := g.bot.Config().GetInt("Sisyphus.MinDecrement", 10)
maxDec := g.bot.Config().GetInt("Sisyphus.MaxDecrement") maxDec := g.bot.Config().GetInt("Sisyphus.MaxDecrement", 30)
if maxDec == minDec && maxDec == 0 {
maxDec = 30
minDec = 10
g.bot.Config().Set("Sisyphus.MinDecrement", strconv.Itoa(minDec))
g.bot.Config().Set("Sisyphus.MaxDecrement", strconv.Itoa(maxDec))
}
g.nextDec = time.Now().Add(time.Duration((minDec + rand.Intn(maxDec))) * time.Minute) g.nextDec = time.Now().Add(time.Duration((minDec + rand.Intn(maxDec))) * time.Minute)
go func() { go func() {
t := time.NewTimer(g.nextDec.Sub(time.Now())) t := time.NewTimer(g.nextDec.Sub(time.Now()))
@ -82,14 +76,8 @@ func (g *game) schedulePush() {
if g.timers[1] != nil { if g.timers[1] != nil {
g.timers[1].Stop() g.timers[1].Stop()
} }
minPush := g.bot.Config().GetInt("Sisyphus.MinPush") minPush := g.bot.Config().GetInt("Sisyphus.MinPush", 1)
maxPush := g.bot.Config().GetInt("Sisyphus.MaxPush") maxPush := g.bot.Config().GetInt("Sisyphus.MaxPush", 10)
if minPush == maxPush && maxPush == 0 {
minPush = 1
maxPush = 10
g.bot.Config().Set("Sisyphus.MinPush", strconv.Itoa(minPush))
g.bot.Config().Set("Sisyphus.MaxPush", strconv.Itoa(maxPush))
}
g.nextPush = time.Now().Add(time.Duration(rand.Intn(maxPush)+minPush) * time.Minute) g.nextPush = time.Now().Add(time.Duration(rand.Intn(maxPush)+minPush) * time.Minute)
go func() { go func() {
t := time.NewTimer(g.nextPush.Sub(time.Now())) t := time.NewTimer(g.nextPush.Sub(time.Now()))
@ -207,7 +195,7 @@ func (p *SisyphusPlugin) RegisterWeb() *string {
} }
func (p *SisyphusPlugin) ReplyMessage(message msg.Message, identifier string) bool { func (p *SisyphusPlugin) ReplyMessage(message msg.Message, identifier string) bool {
if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Get("Nick")) { if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Get("Nick", "bot")) {
if g, ok := p.listenFor[identifier]; ok { if g, ok := p.listenFor[identifier]; ok {
log.Printf("got message on %s: %+v", identifier, message) log.Printf("got message on %s: %+v", identifier, message)

View File

@ -58,8 +58,8 @@ func New(bot bot.Bot) *TwitchPlugin {
twitchList: map[string]*Twitcher{}, twitchList: map[string]*Twitcher{},
} }
for _, ch := range p.config.GetArray("Twitch.Channels") { for _, ch := range p.config.GetArray("Twitch.Channels", []string{}) {
for _, twitcherName := range p.config.GetArray("Twitch." + ch + ".Users") { for _, twitcherName := range p.config.GetArray("Twitch."+ch+".Users", []string{}) {
if _, ok := p.twitchList[twitcherName]; !ok { if _, ok := p.twitchList[twitcherName]; !ok {
p.twitchList[twitcherName] = &Twitcher{ p.twitchList[twitcherName] = &Twitcher{
name: twitcherName, name: twitcherName,
@ -117,7 +117,7 @@ func (p *TwitchPlugin) serveStreaming(w http.ResponseWriter, r *http.Request) {
func (p *TwitchPlugin) Message(message msg.Message) bool { func (p *TwitchPlugin) Message(message msg.Message) bool {
if strings.ToLower(message.Body) == "twitch status" { if strings.ToLower(message.Body) == "twitch status" {
channel := message.Channel channel := message.Channel
if users := p.config.GetArray("Twitch." + channel + ".Users"); len(users) > 0 { if users := p.config.GetArray("Twitch."+channel+".Users", []string{}); len(users) > 0 {
for _, twitcherName := range users { for _, twitcherName := range users {
if _, ok := p.twitchList[twitcherName]; ok { if _, ok := p.twitchList[twitcherName]; ok {
p.checkTwitch(channel, p.twitchList[twitcherName], true) p.checkTwitch(channel, p.twitchList[twitcherName], true)
@ -144,14 +144,14 @@ func (p *TwitchPlugin) Help(channel string, parts []string) {
} }
func (p *TwitchPlugin) twitchLoop(channel string) { func (p *TwitchPlugin) twitchLoop(channel string) {
frequency := p.config.GetInt("Twitch.Freq") frequency := p.config.GetInt("Twitch.Freq", 60)
log.Println("Checking every ", frequency, " seconds") log.Println("Checking every ", frequency, " seconds")
for { for {
time.Sleep(time.Duration(frequency) * time.Second) time.Sleep(time.Duration(frequency) * time.Second)
for _, twitcherName := range p.config.GetArray("Twitch." + channel + ".Users") { for _, twitcherName := range p.config.GetArray("Twitch."+channel+".Users", []string{}) {
p.checkTwitch(channel, p.twitchList[twitcherName], false) p.checkTwitch(channel, p.twitchList[twitcherName], false)
} }
} }
@ -197,8 +197,12 @@ func (p *TwitchPlugin) checkTwitch(channel string, twitcher *Twitcher, alwaysPri
baseURL.RawQuery = query.Encode() baseURL.RawQuery = query.Encode()
cid := p.config.Get("Twitch.ClientID") cid := p.config.Get("Twitch.ClientID", "")
auth := p.config.Get("Twitch.Authorization") auth := p.config.Get("Twitch.Authorization", "")
if cid == auth && cid == "" {
log.Println("Twitch plugin not enabled.")
return
}
body, ok := getRequest(baseURL.String(), cid, auth) body, ok := getRequest(baseURL.String(), cid, auth)
if !ok { if !ok {

View File

@ -28,6 +28,8 @@ func makeMessage(payload string) msg.Message {
func makeTwitchPlugin(t *testing.T) (*TwitchPlugin, *bot.MockBot) { func makeTwitchPlugin(t *testing.T) (*TwitchPlugin, *bot.MockBot) {
mb := bot.NewMockBot() mb := bot.NewMockBot()
c := New(mb) c := New(mb)
mb.Config().Set("twitch.clientid", "fake")
mb.Config().Set("twitch.authorization", "fake")
c.config.SetArray("Twitch.Channels", []string{"test"}) c.config.SetArray("Twitch.Channels", []string{"test"})
c.config.SetArray("Twitch.test.Users", []string{"drseabass"}) c.config.SetArray("Twitch.test.Users", []string{"drseabass"})
assert.NotNil(t, c) assert.NotNil(t, c)

View File

@ -4,7 +4,6 @@ package your
import ( import (
"math/rand" "math/rand"
"strconv"
"strings" "strings"
"github.com/velour/catbase/bot" "github.com/velour/catbase/bot"
@ -29,19 +28,15 @@ func New(bot bot.Bot) *YourPlugin {
// This function returns true if the plugin responds in a meaningful way to the users message. // This function returns true if the plugin responds in a meaningful way to the users message.
// Otherwise, the function returns false and the bot continues execution of other plugins. // Otherwise, the function returns false and the bot continues execution of other plugins.
func (p *YourPlugin) Message(message msg.Message) bool { func (p *YourPlugin) Message(message msg.Message) bool {
maxLen := p.config.GetInt("your.maxlength") maxLen := p.config.GetInt("your.maxlength", 140)
if maxLen == 0 {
maxLen = 140
p.config.Set("your.maxlength", strconv.Itoa(maxLen))
}
if len(message.Body) > maxLen { if len(message.Body) > maxLen {
return false return false
} }
msg := message.Body msg := message.Body
for _, replacement := range p.config.GetArray("Your.Replacements") { for _, replacement := range p.config.GetArray("Your.Replacements", []string{}) {
freq := p.config.GetFloat64("your.replacements." + replacement + ".freq") freq := p.config.GetFloat64("your.replacements."+replacement+".freq", 0.0)
this := p.config.Get("your.replacements." + replacement + ".this") this := p.config.Get("your.replacements."+replacement+".this", "")
that := p.config.Get("your.replacements." + replacement + ".that") that := p.config.Get("your.replacements."+replacement+".that", "")
if rand.Float64() < freq { if rand.Float64() < freq {
r := strings.NewReplacer(this, that) r := strings.NewReplacer(this, that)
msg = r.Replace(msg) msg = r.Replace(msg)

View File

@ -31,9 +31,10 @@ import (
type Slack struct { type Slack struct {
config *config.Config config *config.Config
url string url string
id string id string
ws *websocket.Conn token string
ws *websocket.Conn
lastRecieved time.Time lastRecieved time.Time
@ -163,8 +164,13 @@ type rtmStart struct {
} }
func New(c *config.Config) *Slack { func New(c *config.Config) *Slack {
token := c.Get("slack.token", "NONE")
if token == "NONE" {
log.Fatalf("No slack token found. Set SLACKTOKEN env.")
}
return &Slack{ return &Slack{
config: c, config: c,
token: c.Get("slack.token", ""),
lastRecieved: time.Now(), lastRecieved: time.Now(),
users: make(map[string]string), users: make(map[string]string),
emoji: make(map[string]string), emoji: make(map[string]string),
@ -210,15 +216,11 @@ func (s *Slack) SendMessageType(channel, message string, meMessage bool) (string
postUrl = "https://slack.com/api/chat.meMessage" postUrl = "https://slack.com/api/chat.meMessage"
} }
nick := s.config.Get("Nick") nick := s.config.Get("Nick", "bot")
icon := s.config.Get("IconURL") icon := s.config.Get("IconURL", "https://placekitten.com/128/128")
if icon == "" {
icon = "https://placekitten.com/400/400"
log.Println("Set config item IconURL to customize appearance!")
}
resp, err := http.PostForm(postUrl, resp, err := http.PostForm(postUrl,
url.Values{"token": {s.config.Get("Slack.Token")}, url.Values{"token": {s.token},
"username": {nick}, "username": {nick},
"icon_url": {icon}, "icon_url": {icon},
"channel": {channel}, "channel": {channel},
@ -273,11 +275,11 @@ func (s *Slack) SendAction(channel, message string) string {
} }
func (s *Slack) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) { func (s *Slack) ReplyToMessageIdentifier(channel, message, identifier string) (string, bool) {
nick := s.config.Get("Nick") nick := s.config.Get("Nick", "bot")
icon := s.config.Get("IconURL") icon := s.config.Get("IconURL", "https://placekitten.com/128/128")
resp, err := http.PostForm("https://slack.com/api/chat.postMessage", resp, err := http.PostForm("https://slack.com/api/chat.postMessage",
url.Values{"token": {s.config.Get("Slack.Token")}, url.Values{"token": {s.token},
"username": {nick}, "username": {nick},
"icon_url": {icon}, "icon_url": {icon},
"channel": {channel}, "channel": {channel},
@ -325,7 +327,7 @@ func (s *Slack) ReplyToMessage(channel, message string, replyTo msg.Message) (st
func (s *Slack) React(channel, reaction string, message msg.Message) bool { func (s *Slack) React(channel, reaction string, message msg.Message) bool {
log.Printf("Reacting in %s: %s", channel, reaction) log.Printf("Reacting in %s: %s", channel, reaction)
resp, err := http.PostForm("https://slack.com/api/reactions.add", resp, err := http.PostForm("https://slack.com/api/reactions.add",
url.Values{"token": {s.config.Get("Slack.Token")}, url.Values{"token": {s.token},
"name": {reaction}, "name": {reaction},
"channel": {channel}, "channel": {channel},
"timestamp": {message.AdditionalData["RAW_SLACK_TIMESTAMP"]}}) "timestamp": {message.AdditionalData["RAW_SLACK_TIMESTAMP"]}})
@ -339,7 +341,7 @@ func (s *Slack) React(channel, reaction string, message msg.Message) bool {
func (s *Slack) Edit(channel, newMessage, identifier string) bool { func (s *Slack) Edit(channel, newMessage, identifier string) bool {
log.Printf("Editing in (%s) %s: %s", identifier, channel, newMessage) log.Printf("Editing in (%s) %s: %s", identifier, channel, newMessage)
resp, err := http.PostForm("https://slack.com/api/chat.update", resp, err := http.PostForm("https://slack.com/api/chat.update",
url.Values{"token": {s.config.Get("Slack.Token")}, url.Values{"token": {s.token},
"channel": {channel}, "channel": {channel},
"text": {newMessage}, "text": {newMessage},
"ts": {identifier}}) "ts": {identifier}})
@ -356,7 +358,7 @@ func (s *Slack) GetEmojiList() map[string]string {
func (s *Slack) populateEmojiList() { func (s *Slack) populateEmojiList() {
resp, err := http.PostForm("https://slack.com/api/emoji.list", resp, err := http.PostForm("https://slack.com/api/emoji.list",
url.Values{"token": {s.config.Get("Slack.Token")}}) url.Values{"token": {s.token}})
if err != nil { if err != nil {
log.Printf("Error retrieving emoji list from Slack: %s", err) log.Printf("Error retrieving emoji list from Slack: %s", err)
return return
@ -549,7 +551,7 @@ func (s *Slack) markAllChannelsRead() {
func (s *Slack) getAllChannels() []slackChannelListItem { func (s *Slack) getAllChannels() []slackChannelListItem {
u := s.url + "channels.list" u := s.url + "channels.list"
resp, err := http.PostForm(u, resp, err := http.PostForm(u,
url.Values{"token": {s.config.Get("Slack.Token")}}) url.Values{"token": {s.token}})
if err != nil { if err != nil {
log.Printf("Error posting user info request: %s", log.Printf("Error posting user info request: %s",
err) err)
@ -574,7 +576,7 @@ func (s *Slack) getAllChannels() []slackChannelListItem {
func (s *Slack) markChannelAsRead(slackChanId string) error { func (s *Slack) markChannelAsRead(slackChanId string) error {
u := s.url + "channels.info" u := s.url + "channels.info"
resp, err := http.PostForm(u, resp, err := http.PostForm(u,
url.Values{"token": {s.config.Get("Slack.Token")}, "channel": {slackChanId}}) url.Values{"token": {s.token}, "channel": {slackChanId}})
if err != nil { if err != nil {
log.Printf("Error posting user info request: %s", log.Printf("Error posting user info request: %s",
err) err)
@ -596,7 +598,7 @@ func (s *Slack) markChannelAsRead(slackChanId string) error {
u = s.url + "channels.mark" u = s.url + "channels.mark"
resp, err = http.PostForm(u, resp, err = http.PostForm(u,
url.Values{"token": {s.config.Get("Slack.Token")}, "channel": {slackChanId}, "ts": {chanInfo.Channel.Latest.Ts}}) url.Values{"token": {s.token}, "channel": {slackChanId}, "ts": {chanInfo.Channel.Latest.Ts}})
if err != nil { if err != nil {
log.Printf("Error posting user info request: %s", log.Printf("Error posting user info request: %s",
err) err)
@ -621,7 +623,7 @@ func (s *Slack) markChannelAsRead(slackChanId string) error {
} }
func (s *Slack) connect() { func (s *Slack) connect() {
token := s.config.Get("Slack.Token") token := s.token
u := fmt.Sprintf("https://slack.com/api/rtm.connect?token=%s", token) u := fmt.Sprintf("https://slack.com/api/rtm.connect?token=%s", token)
resp, err := http.Get(u) resp, err := http.Get(u)
if err != nil { if err != nil {
@ -667,7 +669,7 @@ func (s *Slack) getUser(id string) (string, bool) {
log.Printf("User %s not already found, requesting info", id) log.Printf("User %s not already found, requesting info", id)
u := s.url + "users.info" u := s.url + "users.info"
resp, err := http.PostForm(u, resp, err := http.PostForm(u,
url.Values{"token": {s.config.Get("Slack.Token")}, "user": {id}}) url.Values{"token": {s.token}, "user": {id}})
if err != nil || resp.StatusCode != 200 { if err != nil || resp.StatusCode != 200 {
log.Printf("Error posting user info request: %d %s", log.Printf("Error posting user info request: %d %s",
resp.StatusCode, err) resp.StatusCode, err)
@ -689,7 +691,7 @@ func (s *Slack) Who(id string) []string {
log.Println("Who is queried for ", id) log.Println("Who is queried for ", id)
u := s.url + "channels.info" u := s.url + "channels.info"
resp, err := http.PostForm(u, resp, err := http.PostForm(u,
url.Values{"token": {s.config.Get("Slack.Token")}, "channel": {id}}) url.Values{"token": {s.token}, "channel": {id}})
if err != nil { if err != nil {
log.Printf("Error posting user info request: %s", log.Printf("Error posting user info request: %s",
err) err)

View File

@ -1,5 +0,0 @@
// © 2013 the CatBase Authors under the WTFPL. See AUTHORS for the list of authors.
package main
const Version = "0.9"