boddle/boddle.go
2021-12-02 18:59:46 +00:00

345 lines
8.4 KiB
Go

package main
import "strings"
import "fmt"
import "regexp"
import "database/sql"
import _ "github.com/mattn/go-sqlite3"
type irc_msg struct {
channel string
msg string
author string
}
type cmd struct {
valid bool
add bool
cmd string
groups []string
suffix string
error string
}
var begin_char = []byte{'-', '<'}
var db *sql.DB
var err error
func checkErr(err error) {
if err != nil {
fmt.Printf("::::ERROR:::: %s\n", err)
panic(err)
}
}
func in (a byte, arr []byte) bool {
for _, x := range arr {
if x == a {
return true
}
}
return false
}
func unique_str(stringSlice []string) []string {
keys := make(map[string]bool)
list := []string{}
for _, entry := range stringSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}
func unique_int(intSlice []int) []int {
keys := make(map[int]bool)
list := []int{}
for _, entry := range intSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}
/*
func unique[T any](tSlice []T) []T {
keys := make(map[T]bool)
list := []T{}
for _, entry := range tSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}
*/
// function to split advise message correctly
func filter(msg string, foo bot) cmd {
var c cmd
if len(msg) <= 0 {
c.error = "Message is too short."
c.valid = false
return c
}
c.cmd = ""
c.valid = false
if strings.HasPrefix(msg, "add ") {
c.add = true
msg = msg[4:]
} else {
c.add = false
}
if (strings.Contains(msg, "[") && strings.Contains(msg, "]")) {
re, _ := regexp.Compile(`\s*(\w*)\s*\[(.+)\]\s*(.*)\s*`)
res := re.FindStringSubmatch(msg)
if len(res) < 4 {
c.error = "You entered weird stuff, please try again."
return c
}
c.cmd = res[1]
if c.cmd == "" {
LOG_WARN.Printf("empty cmd\n")
c.error = "The command was empty. A non-empty command is needed."
return c
}
// substitute group names with ids
groups := strings.Fields(res[2])
stmt, err := db.Prepare("select id from groups where name = ?")
checkErr(err)
for _, group := range groups {
rows, err := stmt.Query(group)
if err != nil {
LOG_WARN.Printf("invalid query.")
return c
}
group_id := 0
if rows.Next() {
rows.Scan(&group_id)
c.groups = append(c.groups, fmt.Sprintf("%d", group_id))
rows.Close()
} else {
c.valid = false
c.error = "Group name " + group + " is invalid."
rows.Close()
return c
}
}
c.suffix = res[3]
c.valid = true
} else {
c.groups = nil
re, _ := regexp.Compile(`\s*(\w*)\s*(.*)\s*`)
res := re.FindStringSubmatch(msg)
if len(res) < 3 {
c.error = "You entered weird stuff, please try again."
return c
}
c.cmd = res[1]
if c.cmd == "" {
c.error = "The command was empty. A non-empty command is needed."
return c
}
c.suffix = res[2]
c.valid = true
}
c.cmd = strings.TrimSpace(c.cmd)
c.suffix = strings.TrimSpace(c.suffix)
return c
}
func getRandomEntry(c cmd) string {
// TODO: increment counter
// if database entry exists: set tag / group and run query
task := "select distinct l.content from line l, brain b, tag t"
task += " where l.id = b.line_id and t.id = b.tag_id and t.id = " + c.cmd
if len(c.groups) > 0 {
task += " and l.id in (select line_id from brain where group_id = " + strings.Join(c.groups," intersect select line_id from brain where group_id = ") + ")"
}
task += " ORDER BY RANDOM() LIMIT 1"
return task
}
// line:
// >befehl <[groups]> <name>
// befehl ist genau ein wort
func parsemsg(msg irc_msg, foo bot) bool {
if len(msg.msg) <= 0 {
return false
}
if !in(msg.msg[0], begin_char) {
return false
}
msg.msg = msg.msg[1:]
c := filter(msg.msg, foo)
if !c.valid {
LOG_WARN.Printf("non valid input found.\n")
if c.error != "" {
sendmsg(foo.conn, msg.channel, "Falscher input du SP-Ersti... " + c.error)
}
return false
}
LOG_WARN.Printf("line was parsed, continue with evaluation.\n")
if c.cmd == "" {
LOG_WARN.Printf("no command provided.\n")
return false
}
if c.cmd == "help" {
return false
}
// hard code 'groups' to add new groups to the groups-table
if c.add && (c.cmd == "groups" || c.cmd == "group") {
if (c.groups != nil) {
sendmsg(foo.conn, msg.channel, "Ignoring groups for the groups-adding. Well, what were you expecting...?")
}
new_groups := strings.Fields(c.suffix)
stat_sel, err := db.Prepare("select id from groups where name = ?")
checkErr(err)
stat_ins, err := db.Prepare("insert into groups(name) values (?)")
checkErr(err)
var groups_added []string
for _, group := range new_groups {
fmt.Println(group)
ret, err := stat_sel.Query(group)
if ret.Next() {
ret.Close()
continue
}
_, err = stat_ins.Exec(group)
checkErr(err)
groups_added = append(groups_added, group)
}
if len(groups_added) > 0 {
sendmsg(foo.conn, msg.channel, "Added " + strings.Join(groups_added, ", ") + " to groups-table!")
} else {
sendmsg(foo.conn, msg.channel, "Added nothing to groups-table! :(")
}
return false
}
sorter_row, err := db.Query(fmt.Sprintf("select id, tag_id, groups_allow, name_allow, has_groups from sorter where name = '%s'", c.cmd))
checkErr(err)
if sorter_row.Next() {
var sorter_id string
var tag_id string
var groups_allow int
var name_allow int
var has_groups int
sorter_row.Scan(&sorter_id, &tag_id, &groups_allow, &name_allow, &has_groups)
sorter_row.Close()
if groups_allow != 0 {
sendmsg(foo.conn, msg.channel, "This command does not allow groups. :(")
return false
}
if name_allow != 0 && !c.add {
// warning: not allowed
c.suffix = ""
}
c.cmd = tag_id
if has_groups == 0 {
sorter_groups_row, err := db.Query(fmt.Sprintf("select group_id from sorter_groups where sorter_id = '%s'", sorter_id))
checkErr(err)
if sorter_groups_row.Next() {
var group_id int
sorter_groups_row.Scan(&group_id)
c.groups = append(c.groups, fmt.Sprintf("%d", group_id))
}
sorter_groups_row.Close()
if c.add {
var tag_name string
tag_name_row, err := db.Query(fmt.Sprintf("select name from tag where id = %d", tag_id))
checkErr(err)
if tag_name_row.Next() {
tag_name_row.Scan(&tag_name)
}
tag_name_row.Close()
LOG_WARN.Printf("Alias used. Tell the user about that.\n")
sendmsg(foo.conn, msg.channel, "You're using an alias. Please try again with 'add " + tag_name + " [" + strings.Join(c.groups, " ") + "]. Thanks!")
return false
}
}
} else {
LOG_WARN.Printf("no sorter entry, no translation possible\n")
sendmsg(foo.conn, msg.channel, "No entry found, sorry...")
return false
}
if c.add {
// if there is nothing to add, just return. :-)
if (len(c.suffix) <= 0) {
return false;
}
c.suffix = strings.Replace(c.suffix,"\"","'", -1)
LOG_WARN.Printf("adding new stuff: %s from %s.\n", c.suffix, msg.author)
res, err := db.Exec("insert into line (content, author) values (?,?)", c.suffix, msg.author)
checkErr(err)
LOG_WARN.Printf("added line to table.\n")
// get ID of content...
line_id, err := res.LastInsertId();
checkErr(err)
LOG_WARN.Printf("line_id: %d, tag_id: %d, groups: %s\n", line_id, c.cmd, strings.Join(c.groups, "-"))
// for tag and all groups
if len(c.groups) == 0 {
stat, err := db.Prepare("insert into brain(line_id, tag_id) values (?,?)")
checkErr(err)
_, err = stat.Exec(line_id, c.cmd)
checkErr(err)
LOG_INFO.Printf("inserted foo! \n")
defer stat.Close()
} else {
stat, err := db.Prepare("insert into brain(line_id, tag_id, group_id) values (?,?,?)")
checkErr(err)
for _, group := range c.groups {
_, err = stat.Exec(line_id, c.cmd, group)
checkErr(err)
}
LOG_INFO.Printf("inserted foo! \n")
defer stat.Close()
}
sendmsg(foo.conn, msg.channel, fmt.Sprintf("success adding new super funny enjoyable line with ID %d!", line_id))
sendmsg(foo.conn, "horscchtey", fmt.Sprintf("new line: > %s < (ID %d), into groups %s", c.suffix, line_id, strings.Join(c.groups,",")))
return true
}
task := getRandomEntry(c)
LOG_INFO.Printf(task)
row, err := db.Query(task)
checkErr(err)
res := ""
if row.Next() {
row.Scan(&res)
}
row.Close()
if len(res) <= 0 {
LOG_WARN.Printf("no entry found\n")
res = "No matching entry found :("
} else if len(c.suffix) > 0 {
res = fmt.Sprintf("%s... %s", c.suffix, res)
}
sendmsg(foo.conn, msg.channel, res)
return true
}