Add version system, tax tracking, lottery winner DMs, fmtEuro, audit fixes

- Version system: per-plugin versions via Versioned interface, crash_log and
  version_history DB tables, !version command, crash stats in !botinfo
- Tax tracking: tax_ledger table, trackTaxPaid across all communityTax and
  communityPotAdd sites, tax paid display in !stats and !superstatsexplusalpha
- Lottery: DM winners with winning ticket details and matched numbers bolded
- fmtEuro: generic currency formatter with thousand separators across all
  economy display paths
- Audit fixes: streak_decayed column for Streak Survivor achievement,
  combat_narrative empty-phase guard, crafting success rate integer division,
  RecordCrash nil-DB guard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-04-18 01:07:25 -07:00
parent 42e6e23900
commit b15c13cde7
22 changed files with 600 additions and 75 deletions

View File

@@ -13,6 +13,7 @@ import (
"gogobee/internal/db"
"gogobee/internal/util"
"gogobee/internal/version"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/event"
@@ -57,6 +58,19 @@ type Plugin interface {
Init() error
}
// Versioned is an optional interface plugins can implement to declare their version.
type Versioned interface {
Version() string
}
// PluginVersion returns the version for a plugin, or "1.0.0" if it doesn't implement Versioned.
func PluginVersion(p Plugin) string {
if v, ok := p.(Versioned); ok {
return v.Version()
}
return "1.0.0"
}
// dmCache maps user IDs to their DM room IDs to avoid creating duplicate rooms.
var (
dmCache = make(map[id.UserID]id.RoomID)
@@ -764,6 +778,7 @@ func safeGo(label string, fn func()) {
defer func() {
if r := recover(); r != nil {
slog.Error("goroutine panic recovered", "label", label, "panic", r)
db.RecordCrash(version.Short(), label, fmt.Sprintf("%v", r))
}
}()
fn()