2016-03-19 15:44:27 +00:00
package counter
2013-01-23 21:25:04 +00:00
import (
2016-01-15 06:12:26 +00:00
"database/sql"
2019-05-27 18:27:34 +00:00
"encoding/json"
2013-01-23 21:25:04 +00:00
"fmt"
2019-02-12 16:03:24 +00:00
"math/rand"
2019-05-27 18:27:34 +00:00
"net/http"
2017-02-15 04:56:29 +00:00
"regexp"
2017-01-23 15:10:54 +00:00
"strconv"
2013-01-23 21:25:04 +00:00
"strings"
2016-01-15 06:12:26 +00:00
2019-03-07 16:35:42 +00:00
"github.com/rs/zerolog/log"
2016-03-19 18:02:46 +00:00
"github.com/jmoiron/sqlx"
2020-05-25 18:05:21 +00:00
2016-01-17 18:00:44 +00:00
"github.com/velour/catbase/bot"
2016-04-01 14:20:03 +00:00
"github.com/velour/catbase/bot/msg"
2013-01-23 21:25:04 +00:00
)
// This is a counter plugin to count arbitrary things.
type CounterPlugin struct {
2016-03-30 14:00:20 +00:00
Bot bot . Bot
2016-03-19 18:02:46 +00:00
DB * sqlx . DB
2013-01-23 21:25:04 +00:00
}
type Item struct {
2016-03-19 18:02:46 +00:00
* sqlx . DB
2016-01-15 06:12:26 +00:00
ID int64
2013-01-23 21:25:04 +00:00
Nick string
Item string
Count int
}
2018-01-04 17:23:59 +00:00
type alias struct {
* sqlx . DB
ID int64
Item string
PointsTo string ` db:"points_to" `
}
2019-05-27 18:27:34 +00:00
// GetItems returns all counters
func GetAllItems ( db * sqlx . DB ) ( [ ] Item , error ) {
var items [ ] Item
err := db . Select ( & items , ` select * from counter ` )
if err != nil {
return nil , err
}
// Don't forget to embed the DB into all of that shiz
for i := range items {
items [ i ] . DB = db
}
return items , nil
}
2016-03-19 18:27:02 +00:00
// GetItems returns all counters for a subject
2016-03-19 18:02:46 +00:00
func GetItems ( db * sqlx . DB , nick string ) ( [ ] Item , error ) {
var items [ ] Item
err := db . Select ( & items , ` select * from counter where nick = ? ` , nick )
if err != nil {
return nil , err
}
// Don't forget to embed the DB into all of that shiz
2017-01-24 02:13:21 +00:00
for i := range items {
items [ i ] . DB = db
2016-03-19 18:02:46 +00:00
}
return items , nil
}
2018-01-04 12:39:24 +00:00
func LeaderAll ( db * sqlx . DB ) ( [ ] Item , error ) {
2020-01-24 21:32:24 +00:00
s := ` select id,item,nick,count from (select id,item,nick,count,max(abs(count)) from counter group by item having count(nick) > 1 and max(abs(count)) > 1) order by count desc `
2018-01-04 12:39:24 +00:00
var items [ ] Item
err := db . Select ( & items , s )
if err != nil {
2020-03-26 18:00:08 +00:00
log . Error ( ) . Msgf ( "Error querying leaderboard: %s" , err )
2018-01-04 12:39:24 +00:00
return nil , err
}
for i := range items {
items [ i ] . DB = db
}
return items , nil
}
func Leader ( db * sqlx . DB , itemName string ) ( [ ] Item , error ) {
2018-01-04 17:23:59 +00:00
itemName = strings . ToLower ( itemName )
2018-01-04 12:39:24 +00:00
s := ` select * from counter where item=? order by count desc `
var items [ ] Item
err := db . Select ( & items , s , itemName )
if err != nil {
return nil , err
}
for i := range items {
items [ i ] . DB = db
}
return items , nil
}
2020-04-20 10:20:21 +00:00
func RmAlias ( db * sqlx . DB , aliasName string ) error {
q := ` delete from counter_alias where item = ? `
tx , err := db . Beginx ( )
if err != nil {
return err
}
_ , err = tx . Exec ( q , aliasName )
if err != nil {
if err := tx . Rollback ( ) ; err != nil {
return err
}
return err
}
err = tx . Commit ( )
return err
}
func MkAlias ( db * sqlx . DB , aliasName , pointsTo string ) ( * alias , error ) {
aliasName = strings . ToLower ( aliasName )
2018-01-04 17:23:59 +00:00
pointsTo = strings . ToLower ( pointsTo )
res , err := db . Exec ( ` insert into counter_alias (item, points_to) values (?, ?) ` ,
2020-04-20 10:20:21 +00:00
aliasName , pointsTo )
2018-01-04 17:23:59 +00:00
if err != nil {
2020-04-20 10:20:21 +00:00
_ , err := db . Exec ( ` update counter_alias set points_to=? where item=? ` , pointsTo , aliasName )
2018-01-04 17:23:59 +00:00
if err != nil {
return nil , err
}
var a alias
2020-04-20 10:20:21 +00:00
if err := db . Get ( & a , ` select * from counter_alias where item=? ` , aliasName ) ; err != nil {
2018-01-04 17:23:59 +00:00
return nil , err
}
return & a , nil
}
id , _ := res . LastInsertId ( )
2020-04-20 10:20:21 +00:00
return & alias { db , id , aliasName , pointsTo } , nil
2018-01-04 17:23:59 +00:00
}
2020-05-26 15:38:55 +00:00
// GetUserItem returns a specific counter for all subjects
func GetItem ( db * sqlx . DB , itemName string ) ( [ ] Item , error ) {
itemName = trimUnicode ( itemName )
var items [ ] Item
var a alias
if err := db . Get ( & a , ` select * from counter_alias where item=? ` , itemName ) ; err == nil {
itemName = a . PointsTo
} else {
log . Error ( ) . Err ( err ) . Interface ( "alias" , a )
}
err := db . Select ( & items , ` select * from counter where item= ? ` , itemName )
if err != nil {
return nil , err
}
log . Debug ( ) .
Str ( "itemName" , itemName ) .
Interface ( "items" , items ) .
Msg ( "got item" )
for _ , i := range items {
i . DB = db
}
return items , nil
}
// GetUserItem returns a specific counter for a subject
func GetUserItem ( db * sqlx . DB , nick , itemName string ) ( Item , error ) {
2019-11-25 19:26:26 +00:00
itemName = trimUnicode ( itemName )
2016-03-19 18:02:46 +00:00
var item Item
item . DB = db
2018-01-04 17:23:59 +00:00
var a alias
if err := db . Get ( & a , ` select * from counter_alias where item=? ` , itemName ) ; err == nil {
itemName = a . PointsTo
} else {
2019-03-07 16:35:42 +00:00
log . Error ( ) . Err ( err ) . Interface ( "alias" , a )
2018-01-04 17:23:59 +00:00
}
2016-03-19 18:02:46 +00:00
err := db . Get ( & item , ` select * from counter where nick = ? and item= ? ` ,
nick , itemName )
switch err {
case sql . ErrNoRows :
item . ID = - 1
item . Nick = nick
item . Item = itemName
case nil :
default :
return Item { } , err
}
2019-03-07 16:35:42 +00:00
log . Debug ( ) .
Str ( "nick" , nick ) .
Str ( "itemName" , itemName ) .
Interface ( "item" , item ) .
Msg ( "got item" )
2016-03-19 18:02:46 +00:00
return item , nil
}
2020-05-26 15:38:55 +00:00
// GetUserItem returns a specific counter for a subject
2016-03-19 18:27:02 +00:00
// Create saves a counter
2016-03-19 18:02:46 +00:00
func ( i * Item ) Create ( ) error {
res , err := i . Exec ( ` insert into counter (nick, item, count) values (?, ?, ?); ` ,
i . Nick , i . Item , i . Count )
2019-01-20 20:21:26 +00:00
if err != nil {
return err
}
2016-03-19 18:02:46 +00:00
id , _ := res . LastInsertId ( )
// hackhackhack?
i . ID = id
return err
}
2016-03-19 18:27:02 +00:00
// UpdateDelta sets a value
// This will create or delete the item if necessary
func ( i * Item ) Update ( value int ) error {
i . Count = value
2016-03-19 18:02:46 +00:00
if i . Count == 0 && i . ID != - 1 {
return i . Delete ( )
}
if i . ID == - 1 {
i . Create ( )
}
2019-03-07 16:35:42 +00:00
log . Debug ( ) .
Interface ( "i" , i ) .
Int ( "value" , value ) .
Msg ( "Updating item" )
2016-03-19 18:02:46 +00:00
_ , err := i . Exec ( ` update counter set count = ? where id = ? ` , i . Count , i . ID )
2020-05-25 18:05:21 +00:00
if err == nil {
sendUpdate ( i . Nick , i . Item , i . Count )
}
2016-03-19 18:02:46 +00:00
return err
}
2016-03-19 18:27:02 +00:00
// UpdateDelta changes a value according to some delta
// This will create or delete the item if necessary
func ( i * Item ) UpdateDelta ( delta int ) error {
i . Count += delta
return i . Update ( i . Count )
}
// Delete removes a counter from the database
2016-03-19 18:02:46 +00:00
func ( i * Item ) Delete ( ) error {
_ , err := i . Exec ( ` delete from counter where id = ? ` , i . ID )
i . ID = - 1
return err
}
2013-01-23 21:25:04 +00:00
// NewCounterPlugin creates a new CounterPlugin with the Plugin interface
2019-02-05 19:41:38 +00:00
func New ( b bot . Bot ) * CounterPlugin {
tx := b . DB ( ) . MustBegin ( )
b . DB ( ) . MustExec ( ` create table if not exists counter (
2016-01-15 06:12:26 +00:00
id integer primary key ,
nick string ,
item string ,
count integer
2019-01-21 17:36:02 +00:00
) ; ` )
2019-02-05 19:41:38 +00:00
b . DB ( ) . MustExec ( ` create table if not exists counter_alias (
2018-01-04 17:23:59 +00:00
id integer PRIMARY KEY AUTOINCREMENT ,
item string NOT NULL UNIQUE ,
points_to string NOT NULL
2019-01-21 17:36:02 +00:00
) ; ` )
tx . Commit ( )
2019-02-05 19:41:38 +00:00
cp := & CounterPlugin {
Bot : b ,
DB : b . DB ( ) ,
2013-01-23 21:25:04 +00:00
}
2021-02-01 02:21:19 +00:00
b . RegisterRegexCmd ( cp , bot . Message , mkAliasRegex , cp . mkAliasCmd )
b . RegisterRegexCmd ( cp , bot . Message , rmAliasRegex , cp . rmAliasCmd )
b . RegisterRegexCmd ( cp , bot . Message , leaderboardRegex , cp . leaderboardCmd )
b . RegisterRegex ( cp , bot . Message , teaRegex , cp . teaMatchCmd )
b . RegisterRegexCmd ( cp , bot . Message , resetRegex , cp . resetCmd )
b . RegisterRegexCmd ( cp , bot . Message , inspectRegex , cp . inspectCmd )
b . RegisterRegexCmd ( cp , bot . Message , clearRegex , cp . clearCmd )
b . RegisterRegexCmd ( cp , bot . Message , countRegex , cp . countCmd )
b . RegisterRegex ( cp , bot . Message , incrementRegex , cp . incrementCmd )
b . RegisterRegex ( cp , bot . Message , decrementRegex , cp . decrementCmd )
b . RegisterRegex ( cp , bot . Message , addToRegex , cp . addToCmd )
b . RegisterRegex ( cp , bot . Message , removeFromRegex , cp . removeFromCmd )
2019-02-05 19:41:38 +00:00
b . Register ( cp , bot . Help , cp . help )
2019-05-27 18:27:34 +00:00
cp . registerWeb ( )
2020-05-25 18:05:21 +00:00
2019-02-05 19:41:38 +00:00
return cp
2013-01-23 21:25:04 +00:00
}
2019-11-25 19:26:26 +00:00
func trimUnicode ( s string ) string {
return strings . Trim ( s , string ( rune ( 0xFE0F ) ) )
}
2021-02-01 02:21:19 +00:00
var mkAliasRegex = regexp . MustCompile ( ` (?i)^mkalias (?P<what>\S+) (?P<to>\S+)$ ` )
var rmAliasRegex = regexp . MustCompile ( ` (?i)^rmalias (?P<what>\S+)$ ` )
var leaderboardRegex = regexp . MustCompile ( ` (?i)^leaderboard\s?(?P<what>\S+)?$ ` )
var teaRegex = regexp . MustCompile ( "(?i)^([^.]+)\\. [^.]*\\. ([^.]*\\.?)+$" )
var resetRegex = regexp . MustCompile ( ` (?i)^reset me$ ` )
var inspectRegex = regexp . MustCompile ( ` (?i)^inspect (?P<who>\S+)$ ` )
var clearRegex = regexp . MustCompile ( ` (?i)^clear (?P<what>\S+)$ ` )
var countRegex = regexp . MustCompile ( ` (?i)^count (?P<who>\S+)\s?(?P<what>\S+)?$ ` )
2021-02-01 02:51:28 +00:00
var incrementRegex = regexp . MustCompile ( ` (?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\s?\+\+$ ` )
var decrementRegex = regexp . MustCompile ( ` (?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\s?--$ ` )
2021-02-01 02:21:19 +00:00
var addToRegex = regexp . MustCompile ( ` (?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\s+\+=\s+(?P<amount>\d+)$ ` )
var removeFromRegex = regexp . MustCompile ( ` (?i)^(?P<who>[^.\t\n\f\r ]+\s?\.)?(?P<thing>\S+)\s+-=\s+(?P<amount>\d+)$ ` )
func ( p * CounterPlugin ) mkAliasCmd ( r bot . Request ) bool {
what := r . Values [ "what" ]
to := r . Values [ "to" ]
if what == "" || to == "" {
p . Bot . Send ( r . Conn , bot . Message , fmt . Sprintf ( "You must provide all fields for an alias: %s" , mkAliasRegex ) )
return true
2013-01-23 21:25:04 +00:00
}
2021-02-01 02:21:19 +00:00
if _ , err := MkAlias ( p . DB , what , to ) ; err != nil {
log . Error ( ) . Err ( err ) . Msg ( "Could not mkalias" )
p . Bot . Send ( r . Conn , bot . Message , r . Msg . Channel , "We're gonna need too much DB space to make an alias for your mom." )
return true
}
p . Bot . Send ( r . Conn , bot . Message , r . Msg . Channel , fmt . Sprintf ( "Created alias %s -> %s" ,
what , to ) )
return true
}
2013-01-23 21:25:04 +00:00
2021-02-01 02:21:19 +00:00
func ( p * CounterPlugin ) rmAliasCmd ( r bot . Request ) bool {
what := r . Values [ "what" ]
if what == "" {
p . Bot . Send ( r . Conn , bot . Message , r . Msg . Channel , "You must specify an alias to remove." )
2018-01-04 17:23:59 +00:00
return true
2021-02-01 02:21:19 +00:00
}
if err := RmAlias ( p . DB , what ) ; err != nil {
log . Error ( ) . Err ( err ) . Msg ( "could not RmAlias" )
p . Bot . Send ( r . Conn , bot . Message , r . Msg . Channel , "`sudo rm your mom` => Nope, she's staying with me." )
2020-04-20 10:20:21 +00:00
return true
2021-02-01 02:21:19 +00:00
}
p . Bot . Send ( r . Conn , bot . Message , r . Msg . Channel , "`sudo rm your mom`" )
return true
}
2018-01-04 12:39:24 +00:00
2021-02-01 02:21:19 +00:00
func ( p * CounterPlugin ) leaderboardCmd ( r bot . Request ) bool {
var cmd func ( ) ( [ ] Item , error )
itNameTxt := ""
what := r . Values [ "what" ]
2018-01-04 12:39:24 +00:00
2021-02-01 02:21:19 +00:00
if what == "" {
cmd = func ( ) ( [ ] Item , error ) { return LeaderAll ( p . DB ) }
} else {
itNameTxt = fmt . Sprintf ( " for %s" , what )
cmd = func ( ) ( [ ] Item , error ) { return Leader ( p . DB , what ) }
}
its , err := cmd ( )
if err != nil {
log . Error ( ) . Err ( err ) . Msg ( "Error with leaderboard" )
return false
} else if len ( its ) == 0 {
p . Bot . Send ( r . Conn , bot . Message , r . Msg . Channel , "There are not enough entries for a leaderboard." )
2018-01-04 12:39:24 +00:00
return true
2021-02-01 02:21:19 +00:00
}
out := fmt . Sprintf ( "Leaderboard%s:\n" , itNameTxt )
for _ , it := range its {
out += fmt . Sprintf ( "%s with %d %s\n" ,
it . Nick ,
it . Count ,
it . Item ,
)
}
p . Bot . Send ( r . Conn , bot . Message , r . Msg . Channel , out )
return true
}
func ( p * CounterPlugin ) resetCmd ( r bot . Request ) bool {
nick := r . Msg . User . Name
channel := r . Msg . Channel
items , err := GetItems ( p . DB , strings . ToLower ( nick ) )
if err != nil {
log . Error ( ) .
Err ( err ) .
Str ( "nick" , nick ) .
Msg ( "Error getting items to reset" )
p . Bot . Send ( r . Conn , bot . Message , channel , "Something is technically wrong with your counters." )
2017-01-24 02:13:21 +00:00
return true
2021-02-01 02:21:19 +00:00
}
log . Debug ( ) . Msgf ( "Items: %+v" , items )
for _ , item := range items {
item . Delete ( )
}
p . Bot . Send ( r . Conn , bot . Message , channel , fmt . Sprintf ( "%s, you are as new, my son." , nick ) )
return true
}
2013-01-23 21:40:51 +00:00
2021-02-01 02:21:19 +00:00
func ( p * CounterPlugin ) inspectCmd ( r bot . Request ) bool {
var subject string
subject = r . Values [ "who" ]
channel := r . Msg . Channel
c := r . Conn
2013-01-23 21:40:51 +00:00
2021-02-01 02:21:19 +00:00
if subject == "me" {
subject = strings . ToLower ( r . Msg . User . Name )
} else {
subject = strings . ToLower ( subject )
}
log . Debug ( ) .
Str ( "subject" , subject ) .
Msg ( "Getting counter" )
// pull all of the items associated with "subject"
items , err := GetItems ( p . DB , subject )
if err != nil {
log . Error ( ) .
Err ( err ) .
2019-03-07 16:35:42 +00:00
Str ( "subject" , subject ) .
2021-02-01 02:21:19 +00:00
Msg ( "Error retrieving items" )
p . Bot . Send ( c , bot . Message , channel , "Something went wrong finding that counter;" )
return true
}
2013-01-23 21:45:37 +00:00
2021-02-01 02:21:19 +00:00
resp := fmt . Sprintf ( "%s has the following counters:" , subject )
count := 0
for _ , it := range items {
count += 1
if count > 1 {
resp += ","
2013-01-23 21:40:51 +00:00
}
2021-02-01 02:21:19 +00:00
resp += fmt . Sprintf ( " %s: %d" , it . Item , it . Count )
if count > 20 {
resp += ", and a few others"
break
2016-01-15 06:12:26 +00:00
}
2021-02-01 02:21:19 +00:00
}
resp += "."
2016-01-15 06:12:26 +00:00
2021-02-01 02:21:19 +00:00
if count == 0 {
p . Bot . Send ( c , bot . Message , channel , fmt . Sprintf ( "%s has no counters." , subject ) )
2013-01-23 21:40:51 +00:00
return true
2021-02-01 02:21:19 +00:00
}
2013-01-23 21:40:51 +00:00
2021-02-01 02:21:19 +00:00
p . Bot . Send ( c , bot . Message , channel , resp )
return true
}
2013-01-23 21:40:51 +00:00
2021-02-01 02:21:19 +00:00
func ( p * CounterPlugin ) clearCmd ( r bot . Request ) bool {
subject := strings . ToLower ( r . Msg . User . Name )
itemName := strings . ToLower ( r . Values [ "what" ] )
channel := r . Msg . Channel
c := r . Conn
it , err := GetUserItem ( p . DB , subject , itemName )
if err != nil {
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error getting item to remove" )
p . Bot . Send ( c , bot . Message , channel , "Something went wrong removing that counter;" )
return true
}
err = it . Delete ( )
if err != nil {
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error removing item" )
p . Bot . Send ( c , bot . Message , channel , "Something went wrong removing that counter;" )
2013-01-23 21:40:51 +00:00
return true
2021-02-01 02:21:19 +00:00
}
2013-01-23 21:40:51 +00:00
2021-02-01 02:21:19 +00:00
p . Bot . Send ( c , bot . Action , channel , fmt . Sprintf ( "chops a few %s out of his brain" ,
itemName ) )
return true
}
2013-01-23 21:25:04 +00:00
2021-02-01 02:21:19 +00:00
func ( p * CounterPlugin ) countCmd ( r bot . Request ) bool {
var subject string
var itemName string
2013-01-23 21:25:04 +00:00
2021-02-01 02:21:19 +00:00
if r . Values [ "what" ] == "" && r . Values [ "who" ] == "" {
return false
} else if r . Values [ "what" ] != "" {
subject = strings . ToLower ( r . Values [ "who" ] )
itemName = strings . ToLower ( r . Values [ "what" ] )
} else {
subject = strings . ToLower ( r . Msg . User . Name )
itemName = strings . ToLower ( r . Values [ "who" ] )
}
2013-01-23 21:25:04 +00:00
2021-02-01 02:21:19 +00:00
var item Item
item , err := GetUserItem ( p . DB , subject , itemName )
switch {
case err == sql . ErrNoRows :
p . Bot . Send ( r . Conn , bot . Message , r . Msg . Channel , fmt . Sprintf ( "I don't think %s has any %s." ,
subject , itemName ) )
2013-01-23 21:25:04 +00:00
return true
2021-02-01 02:21:19 +00:00
case err != nil :
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error retrieving item count" )
return true
}
2013-01-23 21:25:04 +00:00
2021-02-01 02:21:19 +00:00
p . Bot . Send ( r . Conn , bot . Message , r . Msg . Channel , fmt . Sprintf ( "%s has %d %s." , subject , item . Count ,
itemName ) )
2013-01-24 15:35:39 +00:00
2021-02-01 02:21:19 +00:00
return true
}
2017-01-17 22:57:39 +00:00
2021-02-01 02:21:19 +00:00
func ( p * CounterPlugin ) incrementCmd ( r bot . Request ) bool {
subject := r . Msg . User . Name
if r . Values [ "who" ] != "" {
subject = strings . TrimSuffix ( r . Values [ "who" ] , "." )
}
itemName := r . Values [ "thing" ]
channel := r . Msg . Channel
// ++ those fuckers
item , err := GetUserItem ( p . DB , subject , itemName )
if err != nil {
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "error finding item" )
// Item ain't there, I guess
return false
}
log . Debug ( ) . Msgf ( "About to update item: %#v" , item )
item . UpdateDelta ( 1 )
p . Bot . Send ( r . Conn , bot . Message , channel , fmt . Sprintf ( "%s has %d %s." , subject ,
item . Count , item . Item ) )
return true
}
2017-01-17 22:57:39 +00:00
2021-02-01 02:21:19 +00:00
func ( p * CounterPlugin ) decrementCmd ( r bot . Request ) bool {
subject := r . Msg . User . Name
if r . Values [ "who" ] != "" {
subject = strings . TrimSuffix ( r . Values [ "who" ] , "." )
}
itemName := r . Values [ "thing" ]
channel := r . Msg . Channel
// -- those fuckers
item , err := GetUserItem ( p . DB , subject , itemName )
if err != nil {
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error finding item" )
// Item ain't there, I guess
return false
}
item . UpdateDelta ( - 1 )
p . Bot . Send ( r . Conn , bot . Message , channel , fmt . Sprintf ( "%s has %d %s." , subject ,
item . Count , item . Item ) )
return true
}
2017-01-17 22:57:39 +00:00
2021-02-01 02:21:19 +00:00
func ( p * CounterPlugin ) addToCmd ( r bot . Request ) bool {
subject := r . Msg . User . Name
if r . Values [ "who" ] != "" {
subject = strings . TrimSuffix ( r . Values [ "who" ] , "." )
}
itemName := r . Values [ "thing" ]
channel := r . Msg . Channel
// += those fuckers
item , err := GetUserItem ( p . DB , subject , itemName )
if err != nil {
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error finding item" )
// Item ain't there, I guess
return false
2013-01-23 21:25:04 +00:00
}
2021-02-01 02:21:19 +00:00
n , _ := strconv . Atoi ( r . Values [ "amount" ] )
log . Debug ( ) . Msgf ( "About to update item by %d: %#v" , n , item )
item . UpdateDelta ( n )
p . Bot . Send ( r . Conn , bot . Message , channel , fmt . Sprintf ( "%s has %d %s." , subject ,
item . Count , item . Item ) )
return true
}
2013-01-23 21:25:04 +00:00
2021-02-01 02:21:19 +00:00
func ( p * CounterPlugin ) removeFromCmd ( r bot . Request ) bool {
subject := r . Msg . User . Name
if r . Values [ "who" ] != "" {
subject = strings . TrimSuffix ( r . Values [ "who" ] , "." )
}
itemName := r . Values [ "thing" ]
channel := r . Msg . Channel
// -= those fuckers
item , err := GetUserItem ( p . DB , subject , itemName )
if err != nil {
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error finding item" )
// Item ain't there, I guess
return false
}
n , _ := strconv . Atoi ( r . Values [ "amount" ] )
log . Debug ( ) . Msgf ( "About to update item by -%d: %#v" , n , item )
item . UpdateDelta ( - n )
p . Bot . Send ( r . Conn , bot . Message , channel , fmt . Sprintf ( "%s has %d %s." , subject ,
item . Count , item . Item ) )
return true
2013-01-23 21:25:04 +00:00
}
// Help responds to help requests. Every plugin must implement a help function.
2019-05-27 23:21:53 +00:00
func ( p * CounterPlugin ) help ( c bot . Connector , kind bot . Kind , message msg . Message , args ... interface { } ) bool {
p . Bot . Send ( c , bot . Message , message . Channel , "You can set counters incrementally by using " +
2020-04-20 10:20:21 +00:00
"`<noun>++` and `<noun>--`. You can see all of your counters using " +
"`inspect`, erase them with `clear`, and view single counters with " +
"`count`." )
p . Bot . Send ( c , bot . Message , message . Channel , "You can create aliases with `!mkalias <alias> <original>`" )
p . Bot . Send ( c , bot . Message , message . Channel , "You can remove aliases with `!rmalias <alias>`" )
2019-02-05 19:41:38 +00:00
return true
2013-05-08 00:08:18 +00:00
}
2013-06-01 17:10:15 +00:00
2021-02-01 02:21:19 +00:00
func ( p * CounterPlugin ) teaMatchCmd ( r bot . Request ) bool {
nick := r . Msg . User . Name
channel := r . Msg . Channel
2018-10-19 18:20:40 +00:00
2021-02-01 02:21:19 +00:00
submatches := teaRegex . FindStringSubmatch ( r . Msg . Body )
2018-10-19 18:20:40 +00:00
if len ( submatches ) <= 1 {
return false
}
itemName := strings . ToLower ( submatches [ 1 ] )
// We will specifically allow :tea: to keep compatability
2020-05-26 15:38:55 +00:00
item , err := GetUserItem ( p . DB , nick , itemName )
2018-10-19 18:20:40 +00:00
if err != nil || ( item . Count == 0 && item . Item != ":tea:" ) {
2019-03-07 16:35:42 +00:00
log . Error ( ) .
Err ( err ) .
Str ( "itemName" , itemName ) .
Msg ( "Error finding item" )
2018-10-19 18:20:40 +00:00
// Item ain't there, I guess
return false
}
2019-03-07 16:35:42 +00:00
log . Debug ( ) . Msgf ( "About to update item: %#v" , item )
2020-01-21 21:26:06 +00:00
delta := 1
if item . Count < 0 {
delta = - 1
}
item . UpdateDelta ( delta )
2021-02-01 02:21:19 +00:00
p . Bot . Send ( r . Conn , bot . Message , channel , fmt . Sprintf ( "%s... %s has %d %s" ,
2019-02-12 16:03:24 +00:00
strings . Join ( everyDayImShuffling ( [ ] string { "bleep" , "bloop" , "blop" } ) , "-" ) , nick , item . Count , itemName ) )
2018-10-19 18:20:40 +00:00
return true
}
2019-02-12 16:03:24 +00:00
func everyDayImShuffling ( vals [ ] string ) [ ] string {
ret := make ( [ ] string , len ( vals ) )
perm := rand . Perm ( len ( vals ) )
for i , randIndex := range perm {
ret [ i ] = vals [ randIndex ]
}
return ret
}
2019-05-27 18:27:34 +00:00
func ( p * CounterPlugin ) registerWeb ( ) {
http . HandleFunc ( "/counter/api" , p . handleCounterAPI )
http . HandleFunc ( "/counter" , p . handleCounter )
p . Bot . RegisterWeb ( "/counter" , "Counter" )
}
func ( p * CounterPlugin ) handleCounter ( w http . ResponseWriter , r * http . Request ) {
2021-01-09 18:46:28 +00:00
fmt . Fprint ( w , html )
2019-05-27 18:27:34 +00:00
}
func ( p * CounterPlugin ) handleCounterAPI ( w http . ResponseWriter , r * http . Request ) {
if r . Method == http . MethodPost {
info := struct {
2019-06-13 14:04:06 +00:00
User string
Thing string
Action string
Password string
2019-05-27 18:27:34 +00:00
} { }
decoder := json . NewDecoder ( r . Body )
err := decoder . Decode ( & info )
if err != nil {
w . WriteHeader ( 500 )
fmt . Fprint ( w , err )
return
}
log . Debug ( ) .
Interface ( "postbody" , info ) .
Msg ( "Got a POST" )
2019-06-13 14:04:06 +00:00
if info . Password != p . Bot . GetPassword ( ) {
w . WriteHeader ( http . StatusForbidden )
j , _ := json . Marshal ( struct { Err string } { Err : "Invalid Password" } )
w . Write ( j )
return
}
2020-05-26 15:38:55 +00:00
item , err := GetUserItem ( p . DB , info . User , info . Thing )
2019-05-27 18:27:34 +00:00
if err != nil {
log . Error ( ) .
Err ( err ) .
Str ( "subject" , info . User ) .
Str ( "itemName" , info . Thing ) .
Msg ( "error finding item" )
w . WriteHeader ( 404 )
fmt . Fprint ( w , err )
return
}
if info . Action == "++" {
item . UpdateDelta ( 1 )
} else if info . Action == "--" {
item . UpdateDelta ( - 1 )
} else {
w . WriteHeader ( 400 )
fmt . Fprint ( w , "Invalid increment" )
return
}
}
all , err := GetAllItems ( p . DB )
if err != nil {
w . WriteHeader ( 500 )
fmt . Fprint ( w , err )
return
}
data , err := json . Marshal ( all )
if err != nil {
w . WriteHeader ( 500 )
fmt . Fprint ( w , err )
return
}
fmt . Fprint ( w , string ( data ) )
}
2020-05-25 18:05:21 +00:00
type Update struct {
Who string
What string
Amount int
}
type updateFunc func ( Update )
var updateFuncs = [ ] updateFunc { }
func RegisterUpdate ( f updateFunc ) {
log . Debug ( ) . Msgf ( "registering update func" )
updateFuncs = append ( updateFuncs , f )
}
func sendUpdate ( who , what string , amount int ) {
log . Debug ( ) . Msgf ( "sending updates to %d places" , len ( updateFuncs ) )
for _ , f := range updateFuncs {
f ( Update { who , what , amount } )
}
}