diff --git a/.gitignore b/.gitignore index 785c0bc..03f52e7 100644 --- a/.gitignore +++ b/.gitignore @@ -74,3 +74,7 @@ gus.sh rathaus.sh run.sh impact.ttf +.env +*.store +rathaus_discord.sh +util/migrate/migrate diff --git a/bot/handlers.go b/bot/handlers.go index 4797862..c152384 100644 --- a/bot/handlers.go +++ b/bot/handlers.go @@ -67,7 +67,9 @@ func ParseValues(r *regexp.Regexp, body string) RegexValues { func (b *bot) runCallback(conn Connector, plugin Plugin, evt Kind, message msg.Message, args ...interface{}) bool { t := reflect.TypeOf(plugin).String() for _, spec := range b.callbacks[t][evt] { + log.Debug().Msgf("Trying callback %v with regex %v for msg %v", t, spec.Regex.String(), message.Body) if spec.Regex.MatchString(message.Body) { + log.Debug().Msgf("Running callback") req := Request{ Conn: conn, Kind: evt, diff --git a/plugins/achievements/achievements.go b/plugins/achievements/achievements.go index 2bd1da2..2e9db69 100644 --- a/plugins/achievements/achievements.go +++ b/plugins/achievements/achievements.go @@ -1,6 +1,7 @@ package achievements import ( + "database/sql" "fmt" bh "github.com/timshannon/bolthold" "regexp" @@ -179,7 +180,7 @@ func (p *AchievementsPlugin) Grant(nick, emojy string) (Award, error) { Holder: nick, Emojy: emojy, Description: trophy.Description, - Granted: time.Now(), + Granted: sql.NullTime{Time: time.Now()}, } if err = p.store.Insert(bh.NextSequence(), &award); err != nil { return Award{}, err @@ -205,17 +206,18 @@ func (p *AchievementsPlugin) Create(emojy, description, creator string) (Trophy, } type Trophy struct { - Emojy string + Emojy string `boltholderKey:"Emojy"` Description string Creator string } type Award struct { - ID int64 `boltholderid:"ID"` - Holder string + ID uint64 `boltholderKey:"ID"` Emojy string Description string - Granted time.Time + Holder string + Amount int64 + Granted sql.NullTime } func (p *AchievementsPlugin) AllTrophies() ([]Trophy, error) { diff --git a/plugins/fact/factoid.go b/plugins/fact/factoid.go index ace51b5..ca40953 100644 --- a/plugins/fact/factoid.go +++ b/plugins/fact/factoid.go @@ -4,18 +4,14 @@ package fact import ( "embed" - "encoding/json" "fmt" bh "github.com/timshannon/bolthold" - "html/template" "math/rand" - "net/http" "net/url" "regexp" "strings" "time" - "github.com/go-chi/chi/v5" "github.com/rs/zerolog/log" "github.com/velour/catbase/bot" @@ -40,16 +36,20 @@ type Factoid struct { Count int } -type alias struct { +type Alias struct { Fact string Next string } -func (a *alias) resolve(store *bh.Store) (*Factoid, error) { +func (a Alias) Key() string { + return a.Fact + a.Next +} + +func (a *Alias) resolve(store *bh.Store) (*Factoid, error) { // perform db query to fill the To field // todo: remove this query //q := `select fact, next from factoid_alias where fact=?` - var next alias + var next Alias err := store.FindOne(&next, bh.Where("Fact").Eq(a.Next)) if err != nil { // we hit the end of the chain, get a factoid named Next @@ -66,7 +66,7 @@ func (a *alias) resolve(store *bh.Store) (*Factoid, error) { func findAlias(store *bh.Store, fact string) (bool, *Factoid) { // todo: remove this query //q := `select * from factoid_alias where fact=?` - var a alias + var a Alias err := store.FindOne(&a, bh.Where("Fact").Eq(fact)) if err != nil { return false, nil @@ -75,9 +75,9 @@ func findAlias(store *bh.Store, fact string) (bool, *Factoid) { return err == nil, f } -func (a *alias) save(store *bh.Store) error { +func (a *Alias) save(store *bh.Store) error { //q := `select * from factoid_alias where fact=?` - var offender alias + var offender Alias err := store.FindOne(&offender, bh.Where("Fact").Eq(a.Next)) if err == nil { return fmt.Errorf("DANGER: an opposite alias already exists") @@ -95,8 +95,8 @@ func (a *alias) save(store *bh.Store) error { return nil } -func aliasFromStrings(from, to string) *alias { - return &alias{from, to} +func aliasFromStrings(from, to string) *Alias { + return &Alias{from, to} } func (f *Factoid) Save(store *bh.Store) error { @@ -123,7 +123,7 @@ func (f *Factoid) delete(store *bh.Store) error { func getFacts(store *bh.Store, fact string, tidbit string) ([]*Factoid, error) { var fs []*Factoid - err := store.Find(&fs, bh.Where("Fact").Contains(fact).And("Tidbit").Contains(tidbit)) + err := store.Find(&fs, bh.Where("Fact").RegExp(regexp.MustCompile(`.*`+fact+`.*`)).And("Tidbit").RegExp(regexp.MustCompile(`.*`+tidbit+`.*`))) if err != nil { log.Error().Err(err).Msg("Error regexping for facts") return nil, err @@ -669,58 +669,3 @@ func (p *FactoidPlugin) factTimer(c bot.Connector, channel string) { } } } - -// Register any web URLs desired -func (p *FactoidPlugin) registerWeb() { - r := chi.NewRouter() - r.HandleFunc("/api", p.serveAPI) - r.HandleFunc("/req", p.serveQuery) - r.HandleFunc("/", p.serveQuery) - p.Bot.RegisterWebName(r, "/factoid", "Factoid") -} - -func linkify(text string) template.HTML { - parts := strings.Fields(text) - for i, word := range parts { - if strings.HasPrefix(word, "http") { - parts[i] = fmt.Sprintf("%s", word, word) - } - } - return template.HTML(strings.Join(parts, " ")) -} -func (p *FactoidPlugin) serveAPI(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - fmt.Fprintf(w, "Incorrect HTTP method") - return - } - info := struct { - Query string `json:"query"` - }{} - decoder := json.NewDecoder(r.Body) - err := decoder.Decode(&info) - if err != nil { - w.WriteHeader(500) - fmt.Fprint(w, err) - return - } - - entries, err := getFacts(p.store, info.Query, "") - if err != nil { - w.WriteHeader(500) - fmt.Fprint(w, err) - return - } - - data, err := json.Marshal(entries) - if err != nil { - w.WriteHeader(500) - fmt.Fprint(w, err) - return - } - w.Write(data) -} - -func (p *FactoidPlugin) serveQuery(w http.ResponseWriter, r *http.Request) { - index, _ := embeddedFS.ReadFile("index.html") - w.Write(index) -} diff --git a/plugins/fact/web.go b/plugins/fact/web.go new file mode 100644 index 0000000..c9c06aa --- /dev/null +++ b/plugins/fact/web.go @@ -0,0 +1,68 @@ +package fact + +import ( + "encoding/json" + "fmt" + "github.com/go-chi/chi/v5" + "github.com/rs/zerolog/log" + "html/template" + "net/http" + "strings" +) + +// Register any web URLs desired +func (p *FactoidPlugin) registerWeb() { + r := chi.NewRouter() + r.HandleFunc("/api", p.serveAPI) + r.HandleFunc("/req", p.serveQuery) + r.HandleFunc("/", p.serveQuery) + p.Bot.RegisterWebName(r, "/factoid", "Factoid") +} + +func linkify(text string) template.HTML { + parts := strings.Fields(text) + for i, word := range parts { + if strings.HasPrefix(word, "http") { + parts[i] = fmt.Sprintf("%s", word, word) + } + } + return template.HTML(strings.Join(parts, " ")) +} +func (p *FactoidPlugin) serveAPI(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + fmt.Fprintf(w, "Incorrect HTTP method") + return + } + info := struct { + Query string `json:"query"` + }{} + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&info) + if err != nil { + w.WriteHeader(500) + fmt.Fprint(w, err) + return + } + + entries, err := getFacts(p.store, info.Query, "") + if err != nil { + w.WriteHeader(500) + fmt.Fprint(w, err) + return + } + + log.Debug().Msgf("api request got %d entries", len(entries)) + + data, err := json.Marshal(entries) + if err != nil { + w.WriteHeader(500) + fmt.Fprint(w, err) + return + } + w.Write(data) +} + +func (p *FactoidPlugin) serveQuery(w http.ResponseWriter, r *http.Request) { + index, _ := embeddedFS.ReadFile("index.html") + w.Write(index) +} diff --git a/plugins/reminder/reminder.go b/plugins/reminder/reminder.go index 542ec8f..1708f23 100644 --- a/plugins/reminder/reminder.go +++ b/plugins/reminder/reminder.go @@ -264,11 +264,11 @@ func (p *ReminderPlugin) getRemindersFormatted(filter, who string) (string, erro if filter == "" || who == "" { total, _ = p.store.Count(Reminder{}, &bh.Query{}) - err = p.store.Find(&reminders, (&bh.Query{}).SortBy("ID").Limit(max)) + err = p.store.Find(&reminders, (&bh.Query{}).SortBy("When").Limit(max)) } else { log.Debug().Msgf("Looking for reminders where %s eq %s", filter, who) total, _ = p.store.Count(Reminder{}, bh.Where(filter).Eq(who)) - err = p.store.Find(&reminders, bh.Where(filter).Eq(who).SortBy("ID").Limit(max)) + err = p.store.Find(&reminders, bh.Where(filter).Eq(who).SortBy("When").Limit(max)) } if err != nil { log.Error().Err(err).Msgf("error finding reminders") @@ -281,7 +281,7 @@ func (p *ReminderPlugin) getRemindersFormatted(filter, who string) (string, erro txt := "" for counter, reminder := range reminders { - txt += fmt.Sprintf("%d) %s -> %s :: %s @ %s (%d)\n", reminder.ID, reminder.From, reminder.Who, reminder.What, reminder.When, reminder.ID) + txt += fmt.Sprintf("%d) %s -> %s :: %s @ %s\n", reminder.ID, reminder.From, reminder.Who, reminder.What, reminder.When.Format(time.RFC3339)) counter++ } diff --git a/plugins/rest/rest.go b/plugins/rest/rest.go index 9f373c0..bebf71c 100644 --- a/plugins/rest/rest.go +++ b/plugins/rest/rest.go @@ -146,7 +146,7 @@ type Wire struct { // ID ID int64 `boltholdIndex:"ID"` // The URL to make a request to - URL ScanableURL + URL string // The regex which will trigger this REST action ParseRegex string `db:"parse_regex"` regex *regexp.Regexp @@ -230,10 +230,11 @@ func (p *RestPlugin) mkWire(r bot.Request) (Wire, error) { return w, err } - w.URL.URL, err = url.Parse(r.Values["url"]) + _, err = url.Parse(r.Values["url"]) if err != nil { return w, err } + w.URL = r.Values["url"] w.ReturnField = r.Values["returnField"] @@ -287,7 +288,7 @@ func (p *RestPlugin) mkHandler(w Wire) bot.ResponseHandler { values[k] = url.QueryEscape(r.Values[k]) } log.Debug().Interface("values", values).Msgf("r.Values") - urlStr := w.URL.String() + urlStr := w.URL parse, err := template.New(urlStr).Parse(urlStr) if p.handleErr(err, r) { return true diff --git a/util/migrate/apppass.go b/util/migrate/apppass.go index 419b7da..31077d8 100644 --- a/util/migrate/apppass.go +++ b/util/migrate/apppass.go @@ -23,7 +23,7 @@ func migrateApppass(db *sqlx.DB, store *bh.Store) error { return err } for _, i := range all { - if err := store.Insert(i.ID, i); err != nil { + if err := store.Insert(bh.NextSequence(), i); err != nil { return err } } diff --git a/util/migrate/awards.go b/util/migrate/awards.go index 5fdeaf2..a4de5d4 100644 --- a/util/migrate/awards.go +++ b/util/migrate/awards.go @@ -1,44 +1,29 @@ package main import ( - "database/sql" "github.com/jmoiron/sqlx" "github.com/rs/zerolog/log" bh "github.com/timshannon/bolthold" + "github.com/velour/catbase/plugins/achievements" goals2 "github.com/velour/catbase/plugins/goals" ) -type Trophy struct { - Emojy string - Description string - Creator string -} - -type Award struct { - ID int64 `boltholderid:"ID"` - Holder string - Emojy string - Description string - Granted sql.NullTime - Amount int64 -} - func migrateAwards(db *sqlx.DB, store *bh.Store) error { - awards := []Award{} + awards := []achievements.Award{} log.Printf("Migrating %T", awards) err := db.Select(&awards, `select * from awards`) if err != nil { return err } for _, a := range awards { - err := store.Insert(a.ID, a) + err := store.Insert(bh.NextSequence(), &a) if err != nil { return err } } log.Printf("Migrated %d awards", len(awards)) - trophies := []Trophy{} + trophies := []achievements.Trophy{} err = db.Select(&trophies, `select * from trophies`) for _, t := range trophies { err := store.Insert(t.Emojy, t) @@ -54,7 +39,7 @@ func migrateAwards(db *sqlx.DB, store *bh.Store) error { return err } for _, i := range goals { - if err := store.Insert(i.ID, i); err != nil { + if err := store.Insert(bh.NextSequence(), &i); err != nil { return err } } diff --git a/util/migrate/counter.go b/util/migrate/counter.go index dcc6ea2..4967378 100644 --- a/util/migrate/counter.go +++ b/util/migrate/counter.go @@ -25,7 +25,7 @@ func migrateCounter(db *sqlx.DB, store *bh.Store) error { if i.UserID.Valid { it.UserID = i.UserID.String } - if err := store.Insert(i.ID, it); err != nil { + if err := store.Insert(bh.NextSequence(), &it); err != nil { return err } } @@ -36,7 +36,7 @@ func migrateCounter(db *sqlx.DB, store *bh.Store) error { return err } for _, i := range all { - if err := store.Insert(i.ID, i); err != nil { + if err := store.Insert(bh.NextSequence(), &i); err != nil { return err } } diff --git a/util/migrate/fact.go b/util/migrate/fact.go index 1b8ac44..6285fb9 100644 --- a/util/migrate/fact.go +++ b/util/migrate/fact.go @@ -3,6 +3,7 @@ package main import ( "github.com/rs/zerolog/log" bh "github.com/timshannon/bolthold" + fact2 "github.com/velour/catbase/plugins/fact" _ "modernc.org/sqlite" "time" @@ -10,28 +11,12 @@ import ( ) type SQLFactoid struct { - Factoid + fact2.Factoid Created int64 Accessed int64 } -type Factoid struct { - ID uint64 `boltholdKey:"ID"` - Fact string - Tidbit string - Verb string - Owner string - Created time.Time - Accessed time.Time - Count int -} - -type Alias struct { - Fact string - Next string -} - func migrateFacts(db *sqlx.DB, store *bh.Store) error { q := `select * from factoid` allFacts := []SQLFactoid{} @@ -43,7 +28,7 @@ func migrateFacts(db *sqlx.DB, store *bh.Store) error { f := sqlf.Factoid f.Accessed = time.Unix(sqlf.Accessed, 0) f.Created = time.Unix(sqlf.Created, 0) - if err := store.Insert(f.ID, f); err != nil { + if err := store.Insert(bh.NextSequence(), &f); err != nil { return err } } @@ -51,14 +36,14 @@ func migrateFacts(db *sqlx.DB, store *bh.Store) error { log.Printf("Migrated %d facts", len(allFacts)) q = `select * from factoid_alias` - allAliases := []Alias{} + allAliases := []fact2.Alias{} if err := db.Select(&allAliases, q); err != nil { return err } for _, f := range allAliases { - if err := store.Insert(bh.NextSequence(), &f); err != nil { + if err := store.Insert(f.Key(), &f); err != nil { return err } } diff --git a/util/migrate/first.go b/util/migrate/first.go index b874fe7..884b28d 100644 --- a/util/migrate/first.go +++ b/util/migrate/first.go @@ -25,7 +25,7 @@ func migrateFirst(db *sqlx.DB, store *bh.Store) error { fe := i.FirstEntry fe.Day = time.Unix(i.Day, 0) fe.Time = time.Unix(i.Time, 0) - if err := store.Insert(i.ID, fe); err != nil { + if err := store.Insert(bh.NextSequence(), &fe); err != nil { return err } } diff --git a/util/migrate/reminders.go b/util/migrate/reminders.go index 51ae8c7..d4de47c 100644 --- a/util/migrate/reminders.go +++ b/util/migrate/reminders.go @@ -23,7 +23,7 @@ func migrateReminders(db *sqlx.DB, store *bh.Store) error { for _, r := range allReminders { rem := r.Reminder rem.When, _ = time.Parse("2006-01-02 15:04:05", r.When) - if err := store.Insert(r.ID, rem); err != nil { + if err := store.Insert(bh.NextSequence(), &rem); err != nil { return err } } diff --git a/util/migrate/tell.go b/util/migrate/tell.go index 43346d5..4076068 100644 --- a/util/migrate/tell.go +++ b/util/migrate/tell.go @@ -15,7 +15,7 @@ func migrateTell(db *sqlx.DB, store *bh.Store) error { } for _, t := range tells { - if err := store.Insert(t.ID, t); err != nil { + if err := store.Insert(bh.NextSequence(), &t); err != nil { return err } } diff --git a/util/migrate/webshit.go b/util/migrate/webshit.go index 3f51794..976287a 100644 --- a/util/migrate/webshit.go +++ b/util/migrate/webshit.go @@ -25,7 +25,7 @@ func migrateWebshit(db *sqlx.DB, store *bh.Store) error { } for _, b := range balances { - if err := store.Insert(b.User, b); err != nil { + if err := store.Insert(bh.NextSequence(), &b); err != nil { return err } } @@ -39,7 +39,7 @@ func migrateWebshit(db *sqlx.DB, store *bh.Store) error { bid := b.Bid bid.Placed = time.Unix(b.Placed, 0) bid.Processed = time.Unix(b.Processed, 0) - if err := store.Insert(b.ID, bid); err != nil { + if err := store.Insert(bh.NextSequence(), &bid); err != nil { return err } } diff --git a/util/migrate/wires.go b/util/migrate/wires.go index 1d308b8..e9a4897 100644 --- a/util/migrate/wires.go +++ b/util/migrate/wires.go @@ -5,27 +5,16 @@ import ( bh "github.com/timshannon/bolthold" "github.com/velour/catbase/plugins/rest" "log" - "net/url" ) -type WireSQL struct { - rest.Wire - - // The URL to make a request to - URL string -} - func migrateWires(db *sqlx.DB, store *bh.Store) error { - wires := []WireSQL{} + wires := []rest.Wire{} log.Printf("Migrating %T", wires) if err := db.Select(&wires, `select * from wires`); err != nil { return err } for _, w := range wires { - wire := w.Wire - u, _ := url.Parse(w.URL) - wire.URL = rest.ScanableURL{u} - if err := store.Insert(w.ID, wire); err != nil { + if err := store.Insert(bh.NextSequence(), &w); err != nil { return err } }