mirror of https://github.com/velour/catbase.git
bot: add ability to disable plugins per channel
admin: use 'enable/disable plugin <name>'
This commit is contained in:
parent
c68ca70964
commit
12ca34006f
67
bot/bot.go
67
bot/bot.go
|
@ -26,6 +26,9 @@ type bot struct {
|
||||||
plugins map[string]Plugin
|
plugins map[string]Plugin
|
||||||
pluginOrdering []string
|
pluginOrdering []string
|
||||||
|
|
||||||
|
// channel -> plugin
|
||||||
|
pluginBlacklist map[string]bool
|
||||||
|
|
||||||
// Users holds information about all of our friends
|
// Users holds information about all of our friends
|
||||||
users []user.User
|
users []user.User
|
||||||
// Represents the bot
|
// Represents the bot
|
||||||
|
@ -77,21 +80,24 @@ func New(config *config.Config, connector Connector) Bot {
|
||||||
}
|
}
|
||||||
|
|
||||||
bot := &bot{
|
bot := &bot{
|
||||||
config: config,
|
config: config,
|
||||||
plugins: make(map[string]Plugin),
|
plugins: make(map[string]Plugin),
|
||||||
pluginOrdering: make([]string, 0),
|
pluginOrdering: make([]string, 0),
|
||||||
conn: connector,
|
pluginBlacklist: make(map[string]bool),
|
||||||
users: users,
|
conn: connector,
|
||||||
me: users[0],
|
users: users,
|
||||||
logIn: logIn,
|
me: users[0],
|
||||||
logOut: logOut,
|
logIn: logIn,
|
||||||
httpEndPoints: make([]EndPoint, 0),
|
logOut: logOut,
|
||||||
filters: make(map[string]func(string) string),
|
httpEndPoints: make([]EndPoint, 0),
|
||||||
callbacks: make(CallbackMap),
|
filters: make(map[string]func(string) string),
|
||||||
|
callbacks: make(CallbackMap),
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.migrateDB()
|
bot.migrateDB()
|
||||||
|
|
||||||
|
bot.RefreshPluginBlacklist()
|
||||||
|
|
||||||
http.HandleFunc("/", bot.serveRoot)
|
http.HandleFunc("/", bot.serveRoot)
|
||||||
|
|
||||||
connector.RegisterEvent(bot.Receive)
|
connector.RegisterEvent(bot.Receive)
|
||||||
|
@ -127,6 +133,13 @@ func (b *bot) migrateDB() {
|
||||||
);`); err != nil {
|
);`); err != nil {
|
||||||
log.Fatal().Err(err).Msgf("Initial DB migration create variables table")
|
log.Fatal().Err(err).Msgf("Initial DB migration create variables table")
|
||||||
}
|
}
|
||||||
|
if _, err := b.DB().Exec(`create table if not exists pluginBlacklist (
|
||||||
|
channel string,
|
||||||
|
name string,
|
||||||
|
primary key (channel, name)
|
||||||
|
);`); err != nil {
|
||||||
|
log.Fatal().Err(err).Msgf("Initial DB migration create variables table")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a constructed handler to the bots handlers list
|
// Adds a constructed handler to the bots handlers list
|
||||||
|
@ -265,3 +278,35 @@ func (b *bot) GetPassword() string {
|
||||||
func (b *bot) SetQuiet(status bool) {
|
func (b *bot) SetQuiet(status bool) {
|
||||||
b.quiet = status
|
b.quiet = status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *bot) RefreshPluginBlacklist() error {
|
||||||
|
blacklistItems := []struct {
|
||||||
|
Channel string
|
||||||
|
Name string
|
||||||
|
}{}
|
||||||
|
if err := b.DB().Select(&blacklistItems, `select channel, name from pluginBlacklist`); err != nil {
|
||||||
|
return fmt.Errorf("%w", err)
|
||||||
|
}
|
||||||
|
b.pluginBlacklist = make(map[string]bool)
|
||||||
|
for _, i := range blacklistItems {
|
||||||
|
b.pluginBlacklist[i.Channel+i.Name] = true
|
||||||
|
}
|
||||||
|
log.Debug().Interface("blacklist", b.pluginBlacklist).Msgf("Refreshed plugin blacklist")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bot) GetPluginNames() []string {
|
||||||
|
names := []string{}
|
||||||
|
for _, name := range b.pluginOrdering {
|
||||||
|
names = append(names, pluginNameStem(name))
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bot) onBlacklist(channel, plugin string) bool {
|
||||||
|
return b.pluginBlacklist[channel+plugin]
|
||||||
|
}
|
||||||
|
|
||||||
|
func pluginNameStem(name string) string {
|
||||||
|
return strings.Split(strings.TrimPrefix(name, "*"), ".")[0]
|
||||||
|
}
|
||||||
|
|
|
@ -31,7 +31,11 @@ func (b *bot) Receive(conn Connector, kind Kind, msg msg.Message, args ...interf
|
||||||
goto RET
|
goto RET
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debug().Msgf("checking blacklist %v", b.pluginBlacklist)
|
||||||
for _, name := range b.pluginOrdering {
|
for _, name := range b.pluginOrdering {
|
||||||
|
if b.onBlacklist(msg.Channel, pluginNameStem(name)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if b.runCallback(conn, b.plugins[name], kind, msg, args...) {
|
if b.runCallback(conn, b.plugins[name], kind, msg, args...) {
|
||||||
goto RET
|
goto RET
|
||||||
}
|
}
|
||||||
|
@ -70,7 +74,7 @@ func (b *bot) checkHelp(conn Connector, channel string, parts []string) {
|
||||||
// just print out a list of help topics
|
// just print out a list of help topics
|
||||||
topics := "Help topics: about variables"
|
topics := "Help topics: about variables"
|
||||||
for name := range b.plugins {
|
for name := range b.plugins {
|
||||||
name = strings.Split(strings.TrimPrefix(name, "*"), ".")[0]
|
name = pluginNameStem(name)
|
||||||
topics = fmt.Sprintf("%s, %s", topics, name)
|
topics = fmt.Sprintf("%s, %s", topics, name)
|
||||||
}
|
}
|
||||||
b.Send(conn, Message, channel, topics)
|
b.Send(conn, Message, channel, topics)
|
||||||
|
|
|
@ -4,6 +4,7 @@ package bot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
|
|
||||||
"github.com/velour/catbase/bot/msg"
|
"github.com/velour/catbase/bot/msg"
|
||||||
"github.com/velour/catbase/bot/user"
|
"github.com/velour/catbase/bot/user"
|
||||||
"github.com/velour/catbase/config"
|
"github.com/velour/catbase/config"
|
||||||
|
@ -69,6 +70,8 @@ type Bot interface {
|
||||||
GetWebNavigation() []EndPoint
|
GetWebNavigation() []EndPoint
|
||||||
GetPassword() string
|
GetPassword() string
|
||||||
SetQuiet(bool)
|
SetQuiet(bool)
|
||||||
|
GetPluginNames() []string
|
||||||
|
RefreshPluginBlacklist() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connector represents a server connection to a chat service
|
// Connector represents a server connection to a chat service
|
||||||
|
|
|
@ -112,3 +112,6 @@ func NewMockBot() *MockBot {
|
||||||
http.DefaultServeMux = new(http.ServeMux)
|
http.DefaultServeMux = new(http.ServeMux)
|
||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mb *MockBot) GetPluginNames() []string { return nil }
|
||||||
|
func (mb *MockBot) RefreshPluginBlacklist() error { return nil }
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -51,6 +52,9 @@ var forbiddenKeys = map[string]bool{
|
||||||
"meme.memes": true,
|
"meme.memes": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var addBlacklist = regexp.MustCompile(`(?i)disable plugin (.*)`)
|
||||||
|
var rmBlacklist = regexp.MustCompile(`(?i)enable plugin (.*)`)
|
||||||
|
|
||||||
// Message responds to the bot hook on recieving messages.
|
// Message responds to the bot hook on recieving messages.
|
||||||
// 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.
|
||||||
|
@ -103,6 +107,30 @@ func (p *AdminPlugin) message(conn bot.Connector, k bot.Kind, message msg.Messag
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if addBlacklist.MatchString(body) {
|
||||||
|
submatches := addBlacklist.FindStringSubmatch(message.Body)
|
||||||
|
plugin := submatches[1]
|
||||||
|
if err := p.addBlacklist(message.Channel, plugin); err != nil {
|
||||||
|
p.bot.Send(conn, bot.Message, message.Channel, fmt.Sprintf("I couldn't add that item: %s", err))
|
||||||
|
log.Error().Err(err).Msgf("error adding blacklist item")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
p.bot.Send(conn, bot.Message, message.Channel, fmt.Sprintf("%s disabled. Use `!enable plugin %s` to re-enable it.", plugin, plugin))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if rmBlacklist.MatchString(body) {
|
||||||
|
submatches := rmBlacklist.FindStringSubmatch(message.Body)
|
||||||
|
plugin := submatches[1]
|
||||||
|
if err := p.rmBlacklist(message.Channel, plugin); err != nil {
|
||||||
|
p.bot.Send(conn, bot.Message, message.Channel, fmt.Sprintf("I couldn't remove that item: %s", err))
|
||||||
|
log.Error().Err(err).Msgf("error removing blacklist item")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
p.bot.Send(conn, bot.Message, message.Channel, fmt.Sprintf("%s enabled. Use `!disable plugin %s` to disable it.", plugin, plugin))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
if strings.ToLower(body) == "password" {
|
if strings.ToLower(body) == "password" {
|
||||||
p.bot.Send(conn, bot.Message, message.Channel, p.bot.GetPassword())
|
p.bot.Send(conn, bot.Message, message.Channel, p.bot.GetPassword())
|
||||||
return true
|
return true
|
||||||
|
@ -254,3 +282,32 @@ func (p *AdminPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) {
|
||||||
j, _ := json.Marshal(configEntries)
|
j, _ := json.Marshal(configEntries)
|
||||||
fmt.Fprintf(w, "%s", j)
|
fmt.Fprintf(w, "%s", j)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *AdminPlugin) addBlacklist(channel, plugin string) error {
|
||||||
|
if plugin == "admin" {
|
||||||
|
return fmt.Errorf("you cannot disable the admin plugin")
|
||||||
|
}
|
||||||
|
return p.modBlacklist(`insert or replace into pluginBlacklist values (?, ?)`, channel, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AdminPlugin) rmBlacklist(channel, plugin string) error {
|
||||||
|
return p.modBlacklist(`delete from pluginBlacklist where channel=? and name=?`, channel, plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AdminPlugin) modBlacklist(query, channel, plugin string) error {
|
||||||
|
plugins := p.bot.GetPluginNames()
|
||||||
|
for _, pp := range plugins {
|
||||||
|
if pp == plugin {
|
||||||
|
if _, err := p.db.Exec(query, channel, plugin); err != nil {
|
||||||
|
return fmt.Errorf("%w", err)
|
||||||
|
}
|
||||||
|
err := p.bot.RefreshPluginBlacklist()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := fmt.Errorf("unknown plugin named '%s'", plugin)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue