package main import ( "time" "github.com/dgraph-io/badger/v4" lm "github.com/hrfee/jfa-go/logmessages" "github.com/hrfee/mediabrowser" "github.com/timshannon/badgerhold/v4" ) // clearEmails removes stored emails for users which no longer exist. // meant to be called with other such housekeeping functions, so assumes // the user cache is fresh. func (app *appContext) clearEmails() { app.debug.Println(lm.HousekeepingEmail) emails := app.storage.GetEmails() for _, email := range emails { _, err := app.jf.UserByID(email.JellyfinID, false) // Make sure the user doesn't exist, and no other error has occured switch err.(type) { case mediabrowser.ErrUserNotFound: app.storage.DeleteEmailsKey(email.JellyfinID) default: continue } } } // clearDiscord does the same as clearEmails, but for Discord Users. func (app *appContext) clearDiscord() { app.debug.Println(lm.HousekeepingDiscord) discordUsers := app.storage.GetDiscord() for _, discordUser := range discordUsers { user, err := app.jf.UserByID(discordUser.JellyfinID, false) // Make sure the user doesn't exist, and no other error has occured switch err.(type) { case mediabrowser.ErrUserNotFound: // Remove role in case their account was deleted oustide of jfa-go app.discord.RemoveRole(discordUser.MethodID().(string)) app.storage.DeleteDiscordKey(discordUser.JellyfinID) default: if user.Policy.IsDisabled { app.discord.RemoveRole(discordUser.MethodID().(string)) } continue } } } // clearMatrix does the same as clearEmails, but for Matrix Users. func (app *appContext) clearMatrix() { app.debug.Println(lm.HousekeepingMatrix) matrixUsers := app.storage.GetMatrix() for _, matrixUser := range matrixUsers { _, err := app.jf.UserByID(matrixUser.JellyfinID, false) // Make sure the user doesn't exist, and no other error has occured switch err.(type) { case mediabrowser.ErrUserNotFound: app.storage.DeleteMatrixKey(matrixUser.JellyfinID) default: continue } } } // clearTelegram does the same as clearEmails, but for Telegram Users. func (app *appContext) clearTelegram() { app.debug.Println(lm.HousekeepingTelegram) telegramUsers := app.storage.GetTelegram() for _, telegramUser := range telegramUsers { _, err := app.jf.UserByID(telegramUser.JellyfinID, false) // Make sure the user doesn't exist, and no other error has occured switch err.(type) { case mediabrowser.ErrUserNotFound: app.storage.DeleteTelegramKey(telegramUser.JellyfinID) default: continue } } } func (app *appContext) clearPWRCaptchas() { app.debug.Println(lm.HousekeepingCaptcha) captchas := map[string]Captcha{} for k, capt := range app.pwrCaptchas { if capt.Generated.Add(CAPTCHA_VALIDITY * time.Second).After(time.Now()) { captchas[k] = capt } } app.pwrCaptchas = captchas } func (app *appContext) clearActivities() { app.debug.Println(lm.HousekeepingActivity) keepCount := app.config.Section("activity_log").Key("keep_n_records").MustInt(1000) maxAgeDays := app.config.Section("activity_log").Key("delete_after_days").MustInt(90) minAge := time.Now().AddDate(0, 0, -maxAgeDays) err := error(nil) errorSource := 0 if maxAgeDays != 0 { err = app.storage.db.DeleteMatching(&Activity{}, badgerhold.Where("Time").Lt(minAge)) } if err == nil && keepCount != 0 { // app.debug.Printf("Keeping %d records", keepCount) err = app.storage.db.DeleteMatching(&Activity{}, (&badgerhold.Query{}).Reverse().SortBy("Time").Skip(keepCount)) if err != nil { errorSource = 1 } } if err == badger.ErrTxnTooBig { app.debug.Printf(lm.ActivityLogTxnTooBig) list := []Activity{} if errorSource == 0 { app.storage.db.Find(&list, badgerhold.Where("Time").Lt(minAge)) } else { app.storage.db.Find(&list, (&badgerhold.Query{}).Reverse().SortBy("Time").Skip(keepCount)) } for _, record := range list { app.storage.DeleteActivityKey(record.ID) } } } func newHousekeepingDaemon(interval time.Duration, app *appContext) *GenericDaemon { d := NewGenericDaemon(interval, app, func(app *appContext) { app.debug.Println(lm.HousekeepingInvites) app.checkInvites() }, func(app *appContext) { app.clearActivities() }, ) d.Name("Housekeeping") clearEmail := app.config.Section("email").Key("require_unique").MustBool(false) clearDiscord := discordEnabled && (app.config.Section("discord").Key("require_unique").MustBool(false) || app.config.Section("discord").Key("disable_enable_role").MustBool(false)) clearTelegram := telegramEnabled && (app.config.Section("telegram").Key("require_unique").MustBool(false)) clearMatrix := matrixEnabled && (app.config.Section("matrix").Key("require_unique").MustBool(false)) clearPWR := app.config.Section("captcha").Key("enabled").MustBool(false) && !app.config.Section("captcha").Key("recaptcha").MustBool(false) if clearEmail || clearDiscord || clearTelegram || clearMatrix { d.appendJobs(func(app *appContext) { app.jf.CacheExpiry = time.Now() }) } if clearEmail { d.appendJobs(func(app *appContext) { app.clearEmails() }) } if clearDiscord { d.appendJobs(func(app *appContext) { app.clearDiscord() }) } if clearTelegram { d.appendJobs(func(app *appContext) { app.clearTelegram() }) } if clearMatrix { d.appendJobs(func(app *appContext) { app.clearMatrix() }) } if clearPWR { d.appendJobs(func(app *appContext) { app.clearPWRCaptchas() }) } return d }