Add horoscope, !time @user, profile achievements; fix mention detection and multiple bugs

- Add !horoscope command and daily horoscope digest using Free Horoscope API
- Enhance !time to support @user timezone lookups
- Add profile completeness achievements (birthday, timezone, both set)
- Fix Matrix mention detection in reputation and LLM passive plugins
- Fix !whois reputation query (reason string mismatch and calculation)
- Fix !time IANA case-sensitivity and username/city collision
- Fix timezone default to empty string for achievement detection
- Scope all leaderboards to room members (XP, rep, potty, insult, first, rankings, emoji)
- Fix XP rank calculation to handle tied scores correctly
- Replace skull emoji with bomb for bot insult reactions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-03-09 23:55:02 -07:00
parent 2c191ec464
commit 03def6463f
24 changed files with 5057 additions and 116 deletions

View File

@@ -9,7 +9,6 @@ import (
"gogobee/internal/db"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/id"
)
// PresencePlugin handles away status and user profile lookups.
@@ -128,10 +127,13 @@ func (p *PresencePlugin) autoClearAway(ctx MessageContext) error {
func (p *PresencePlugin) handleWhois(ctx MessageContext) error {
args := strings.TrimSpace(p.GetArgs(ctx.Body, "whois"))
if args == "" {
return p.SendMessage(ctx.RoomID, "Usage: !whois @user:server")
return p.SendMessage(ctx.RoomID, "Usage: !whois <user>")
}
targetUser := id.UserID(args)
targetUser, ok := p.ResolveUser(args)
if !ok {
return p.SendMessage(ctx.RoomID, "Could not find a user matching that name.")
}
// Gather profile data
var displayName string
@@ -183,12 +185,13 @@ func (p *PresencePlugin) handleWhois(ctx MessageContext) error {
}
}
// Get reputation (from XP log with reason = 'rep')
var repCount int
// Get reputation (from XP log with reason = 'reputation')
var repXP int
_ = db.Get().QueryRow(
`SELECT COUNT(*) FROM xp_log WHERE user_id = ? AND reason = 'rep'`,
`SELECT COALESCE(SUM(amount), 0) FROM xp_log WHERE user_id = ? AND reason = 'reputation'`,
string(targetUser),
).Scan(&repCount)
).Scan(&repXP)
repCount := repXP / 5
// Get presence status
var status, statusMsg string