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-06-09 04:15:06 +00:00
"html/template"
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"
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.
2018-10-19 18:20:40 +00:00
var teaMatcher = regexp . MustCompile ( "(?i)^([^.]+)\\. [^.]*\\. ([^.]*\\.?)+$" )
2013-01-23 21:25:04 +00:00
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
}
2016-03-19 18:27:02 +00:00
// GetItem returns a specific counter for a subject
2016-03-19 18:02:46 +00:00
func GetItem ( 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
}
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 )
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
}
2019-02-05 19:41:38 +00:00
b . Register ( cp , bot . Message , cp . message )
b . Register ( cp , bot . Help , cp . help )
2019-05-27 18:27:34 +00:00
cp . registerWeb ( )
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 ) ) )
}
2013-01-23 21:25:04 +00:00
// Message responds to the bot hook on recieving messages.
2013-05-07 23:30:37 +00:00
// 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
2013-01-24 15:20:15 +00:00
// execution of other plugins.
2019-05-27 23:21:53 +00:00
func ( p * CounterPlugin ) message ( c bot . Connector , kind bot . Kind , message msg . Message , args ... interface { } ) bool {
2013-01-23 21:25:04 +00:00
// This bot does not reply to anything
nick := message . User . Name
channel := message . Channel
2016-05-11 16:10:15 +00:00
parts := strings . Fields ( message . Body )
2013-01-23 21:25:04 +00:00
if len ( parts ) == 0 {
return false
}
2018-01-04 17:23:59 +00:00
if len ( parts ) == 3 && strings . ToLower ( parts [ 0 ] ) == "mkalias" {
if _ , err := MkAlias ( p . DB , parts [ 1 ] , parts [ 2 ] ) ; err != nil {
2020-04-20 10:20:21 +00:00
log . Error ( ) . Err ( err ) . Msg ( "Could not mkalias" )
p . Bot . Send ( c , bot . Message , channel , "We're gonna need too much DB space to make an alias for your mom." )
return true
2018-01-04 17:23:59 +00:00
}
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , fmt . Sprintf ( "Created alias %s -> %s" ,
2018-01-04 17:23:59 +00:00
parts [ 1 ] , parts [ 2 ] ) )
return true
2020-04-20 10:20:21 +00:00
} else if len ( parts ) == 2 && strings . ToLower ( parts [ 0 ] ) == "rmalias" {
if err := RmAlias ( p . DB , parts [ 1 ] ) ; err != nil {
log . Error ( ) . Err ( err ) . Msg ( "could not RmAlias" )
p . Bot . Send ( c , bot . Message , channel , "`sudo rm your mom` => Nope, she's staying with me." )
return true
}
p . Bot . Send ( c , bot . Message , channel , "`sudo rm your mom`" )
return true
2018-01-04 17:23:59 +00:00
} else if strings . ToLower ( parts [ 0 ] ) == "leaderboard" {
2018-01-04 12:39:24 +00:00
var cmd func ( ) ( [ ] Item , error )
itNameTxt := ""
if len ( parts ) == 1 {
cmd = func ( ) ( [ ] Item , error ) { return LeaderAll ( p . DB ) }
} else {
itNameTxt = fmt . Sprintf ( " for %s" , parts [ 1 ] )
cmd = func ( ) ( [ ] Item , error ) { return Leader ( p . DB , parts [ 1 ] ) }
}
its , err := cmd ( )
if err != nil {
2020-01-24 21:32:24 +00:00
log . Error ( ) . Err ( err ) . Msg ( "Error with leaderboard" )
2018-01-04 12:39:24 +00:00
return false
} else if len ( its ) == 0 {
return false
}
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 ,
)
}
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , out )
2018-01-04 12:39:24 +00:00
return true
2018-10-19 18:20:40 +00:00
} else if match := teaMatcher . MatchString ( message . Body ) ; match {
// check for tea match TTT
2019-05-27 23:21:53 +00:00
return p . checkMatch ( c , message )
2017-01-31 20:35:05 +00:00
} else if message . Command && message . Body == "reset me" {
2017-01-24 02:13:21 +00:00
items , err := GetItems ( p . DB , strings . ToLower ( nick ) )
if err != nil {
2019-03-07 16:35:42 +00:00
log . Error ( ) .
Err ( err ) .
Str ( "nick" , nick ) .
Msg ( "Error getting items to reset" )
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , "Something is technically wrong with your counters." )
2017-01-24 02:13:21 +00:00
return true
}
2019-03-07 16:35:42 +00:00
log . Debug ( ) . Msgf ( "Items: %+v" , items )
2017-01-24 02:13:21 +00:00
for _ , item := range items {
item . Delete ( )
}
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , fmt . Sprintf ( "%s, you are as new, my son." , nick ) )
2017-01-24 02:13:21 +00:00
return true
} else if message . Command && parts [ 0 ] == "inspect" && len ( parts ) == 2 {
2013-01-23 21:40:51 +00:00
var subject string
if parts [ 1 ] == "me" {
subject = strings . ToLower ( nick )
} else {
2016-03-19 18:02:46 +00:00
subject = strings . ToLower ( parts [ 1 ] )
2013-01-23 21:40:51 +00:00
}
2019-03-07 16:35:42 +00:00
log . Debug ( ) .
Str ( "subject" , subject ) .
Msg ( "Getting counter" )
2013-01-23 21:40:51 +00:00
// pull all of the items associated with "subject"
2016-03-19 18:02:46 +00:00
items , err := GetItems ( p . DB , subject )
2016-01-15 06:12:26 +00:00
if err != nil {
2019-03-07 16:35:42 +00:00
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Msg ( "Error retrieving items" )
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , "Something went wrong finding that counter;" )
2016-03-19 18:02:46 +00:00
return true
2013-01-23 21:45:37 +00:00
}
2013-01-23 21:40:51 +00:00
resp := fmt . Sprintf ( "%s has the following counters:" , subject )
2016-01-15 06:12:26 +00:00
count := 0
2016-03-19 18:02:46 +00:00
for _ , it := range items {
2016-01-15 06:12:26 +00:00
count += 1
if count > 1 {
2016-03-30 14:00:20 +00:00
resp += ","
2013-01-23 21:40:51 +00:00
}
2016-03-19 18:02:46 +00:00
resp += fmt . Sprintf ( " %s: %d" , it . Item , it . Count )
2016-01-15 06:12:26 +00:00
if count > 20 {
2016-03-19 18:02:46 +00:00
resp += ", and a few others"
2013-01-23 21:40:51 +00:00
break
}
}
2016-03-19 18:02:46 +00:00
resp += "."
2013-01-23 21:40:51 +00:00
2016-01-15 06:12:26 +00:00
if count == 0 {
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , fmt . Sprintf ( "%s has no counters." , subject ) )
2016-01-15 06:12:26 +00:00
return true
}
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , resp )
2013-01-23 21:40:51 +00:00
return true
} else if message . Command && len ( parts ) == 2 && parts [ 0 ] == "clear" {
subject := strings . ToLower ( nick )
itemName := strings . ToLower ( parts [ 1 ] )
2016-03-19 18:02:46 +00:00
it , err := GetItem ( p . DB , subject , itemName )
if err != nil {
2019-03-07 16:35:42 +00:00
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error getting item to remove" )
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , "Something went wrong removing that counter;" )
2016-03-19 18:02:46 +00:00
return true
}
err = it . Delete ( )
if err != nil {
2019-03-07 16:35:42 +00:00
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error removing item" )
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , "Something went wrong removing that counter;" )
2016-01-15 06:12:26 +00:00
return true
}
2013-01-23 21:40:51 +00:00
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Action , channel , fmt . Sprintf ( "chops a few %s out of his brain" ,
2013-01-24 15:20:15 +00:00
itemName ) )
2013-01-23 21:40:51 +00:00
return true
} else if message . Command && parts [ 0 ] == "count" {
2013-01-23 21:25:04 +00:00
var subject string
var itemName string
if len ( parts ) == 3 {
// report count for parts[1]
subject = strings . ToLower ( parts [ 1 ] )
itemName = strings . ToLower ( parts [ 2 ] )
} else if len ( parts ) == 2 {
subject = strings . ToLower ( nick )
itemName = strings . ToLower ( parts [ 1 ] )
} else {
return false
}
var item Item
2016-03-19 18:02:46 +00:00
item , err := GetItem ( p . DB , subject , itemName )
2016-01-15 06:12:26 +00:00
switch {
case err == sql . ErrNoRows :
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , fmt . Sprintf ( "I don't think %s has any %s." ,
2013-01-23 21:25:04 +00:00
subject , itemName ) )
return true
2016-01-15 06:12:26 +00:00
case err != nil :
2019-03-07 16:35:42 +00:00
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error retrieving item count" )
2016-01-15 06:12:26 +00:00
return true
2013-01-23 21:25:04 +00:00
}
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , fmt . Sprintf ( "%s has %d %s." , subject , item . Count ,
2013-01-24 15:20:15 +00:00
itemName ) )
2013-01-23 21:25:04 +00:00
return true
2018-09-28 02:47:24 +00:00
} else if len ( parts ) <= 2 {
if ( len ( parts ) == 2 ) && ( parts [ 1 ] == "++" || parts [ 1 ] == "--" ) {
parts = [ ] string { parts [ 0 ] + parts [ 1 ] }
}
2016-03-19 18:02:46 +00:00
// Need to have at least 3 characters to ++ or --
2013-01-29 21:27:38 +00:00
if len ( parts [ 0 ] ) < 3 {
return false
}
2013-01-23 21:25:04 +00:00
subject := strings . ToLower ( nick )
itemName := strings . ToLower ( parts [ 0 ] ) [ : len ( parts [ 0 ] ) - 2 ]
2013-01-24 15:35:39 +00:00
if nameParts := strings . SplitN ( itemName , "." , 2 ) ; len ( nameParts ) == 2 {
subject = nameParts [ 0 ]
itemName = nameParts [ 1 ]
}
2013-01-23 21:25:04 +00:00
if strings . HasSuffix ( parts [ 0 ] , "++" ) {
// ++ those fuckers
2016-03-19 18:02:46 +00:00
item , err := GetItem ( p . DB , subject , itemName )
if err != nil {
2019-03-07 16:35:42 +00:00
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "error finding item" )
2016-03-19 18:02:46 +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 )
2016-03-19 18:27:02 +00:00
item . UpdateDelta ( 1 )
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , fmt . Sprintf ( "%s has %d %s." , subject ,
2013-01-24 15:35:39 +00:00
item . Count , item . Item ) )
2013-01-23 21:25:04 +00:00
return true
} else if strings . HasSuffix ( parts [ 0 ] , "--" ) {
// -- those fuckers
2016-03-19 18:02:46 +00:00
item , err := GetItem ( p . DB , subject , itemName )
if err != nil {
2019-03-07 16:35:42 +00:00
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error finding item" )
2016-03-19 18:02:46 +00:00
// Item ain't there, I guess
return false
}
2016-03-19 18:27:02 +00:00
item . UpdateDelta ( - 1 )
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , fmt . Sprintf ( "%s has %d %s." , subject ,
2013-01-24 15:35:39 +00:00
item . Count , item . Item ) )
2013-01-23 21:25:04 +00:00
return true
}
2017-01-17 22:57:39 +00:00
} else if len ( parts ) == 3 {
// Need to have at least 3 characters to ++ or --
if len ( parts [ 0 ] ) < 3 {
return false
}
subject := strings . ToLower ( nick )
2017-01-23 15:10:54 +00:00
itemName := strings . ToLower ( parts [ 0 ] )
2017-01-17 22:57:39 +00:00
if nameParts := strings . SplitN ( itemName , "." , 2 ) ; len ( nameParts ) == 2 {
subject = nameParts [ 0 ]
itemName = nameParts [ 1 ]
}
if parts [ 1 ] == "+=" {
// += those fuckers
item , err := GetItem ( p . DB , subject , itemName )
if err != nil {
2019-03-07 16:35:42 +00:00
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error finding item" )
2017-01-17 22:57:39 +00:00
// Item ain't there, I guess
return false
}
2017-01-23 15:10:54 +00:00
n , _ := strconv . Atoi ( parts [ 2 ] )
2019-03-07 16:35:42 +00:00
log . Debug ( ) . Msgf ( "About to update item by %d: %#v" , n , item )
2017-01-17 22:57:39 +00:00
item . UpdateDelta ( n )
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , fmt . Sprintf ( "%s has %d %s." , subject ,
2017-01-17 22:57:39 +00:00
item . Count , item . Item ) )
return true
} else if parts [ 1 ] == "-=" {
// -= those fuckers
item , err := GetItem ( p . DB , subject , itemName )
if err != nil {
2019-03-07 16:35:42 +00:00
log . Error ( ) .
Err ( err ) .
Str ( "subject" , subject ) .
Str ( "itemName" , itemName ) .
Msg ( "Error finding item" )
2017-01-17 22:57:39 +00:00
// Item ain't there, I guess
return false
}
2017-01-23 15:10:54 +00:00
n , _ := strconv . Atoi ( parts [ 2 ] )
2019-03-07 16:35:42 +00:00
log . Debug ( ) . Msgf ( "About to update item by -%d: %#v" , n , item )
2017-01-17 22:57:39 +00:00
item . UpdateDelta ( - n )
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , bot . Message , channel , fmt . Sprintf ( "%s has %d %s." , subject ,
2017-01-17 22:57:39 +00:00
item . Count , item . Item ) )
return true
}
2013-01-23 21:25:04 +00:00
}
return false
}
// 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
2019-05-27 23:21:53 +00:00
func ( p * CounterPlugin ) checkMatch ( c bot . Connector , message msg . Message ) bool {
2018-10-19 18:20:40 +00:00
nick := message . User . Name
channel := message . Channel
submatches := teaMatcher . FindStringSubmatch ( message . Body )
if len ( submatches ) <= 1 {
return false
}
itemName := strings . ToLower ( submatches [ 1 ] )
// We will specifically allow :tea: to keep compatability
item , err := GetItem ( p . DB , nick , itemName )
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 )
2019-05-27 23:21:53 +00:00
p . Bot . Send ( c , 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" )
}
2019-06-09 04:15:06 +00:00
var tpl = template . Must ( template . New ( "factoidIndex" ) . Parse ( html ) )
2019-05-27 18:27:34 +00:00
func ( p * CounterPlugin ) handleCounter ( w http . ResponseWriter , r * http . Request ) {
2019-06-09 04:15:06 +00:00
tpl . Execute ( w , struct { Nav [ ] bot . EndPoint } { p . Bot . GetWebNavigation ( ) } )
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
}
2019-05-27 18:27:34 +00:00
item , err := GetItem ( p . DB , info . User , info . Thing )
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 ) )
}