db: migrate invites, user expiry

some fixes to stuff in there too, probably
db
Harvey Tindall 10 months ago
parent a470d77938
commit 63948a6de0
No known key found for this signature in database
GPG Key ID: BBC65952848FB1A2

@ -15,16 +15,15 @@ import (
func (app *appContext) checkInvites() {
currentTime := time.Now()
app.storage.loadInvites()
changed := false
for code, data := range app.storage.GetInvites() {
for _, data := range app.storage.GetInvites() {
expiry := data.ValidTill
if !currentTime.After(expiry) {
continue
}
app.debug.Printf("Housekeeping: Deleting old invite %s", code)
app.debug.Printf("Housekeeping: Deleting old invite %s", data.Code)
notify := data.Notify
if emailEnabled && app.config.Section("notifications").Key("enabled").MustBool(false) && len(notify) != 0 {
app.debug.Printf("%s: Expiry notification", code)
app.debug.Printf("%s: Expiry notification", data.Code)
var wait sync.WaitGroup
for address, settings := range notify {
if !settings["notify-expiry"] {
@ -33,9 +32,9 @@ func (app *appContext) checkInvites() {
wait.Add(1)
go func(addr string) {
defer wait.Done()
msg, err := app.email.constructExpiry(code, data, app, false)
msg, err := app.email.constructExpiry(data.Code, data, app, false)
if err != nil {
app.err.Printf("%s: Failed to construct expiry notification: %v", code, err)
app.err.Printf("%s: Failed to construct expiry notification: %v", data.Code, err)
} else {
// Check whether notify "address" is an email address of Jellyfin ID
if strings.Contains(addr, "@") {
@ -44,7 +43,7 @@ func (app *appContext) checkInvites() {
err = app.sendByID(msg, addr)
}
if err != nil {
app.err.Printf("%s: Failed to send expiry notification: %v", code, err)
app.err.Printf("%s: Failed to send expiry notification: %v", data.Code, err)
} else {
app.info.Printf("Sent expiry notification to %s", addr)
}
@ -53,18 +52,13 @@ func (app *appContext) checkInvites() {
}
wait.Wait()
}
changed = true
app.storage.DeleteInvitesKey(code)
}
if changed {
app.storage.storeInvites()
app.storage.DeleteInvitesKey(data.Code)
}
}
func (app *appContext) checkInvite(code string, used bool, username string) bool {
currentTime := time.Now()
app.storage.loadInvites()
changed := false
inv, match := app.storage.GetInvitesKey(code)
if !match {
return false
@ -103,11 +97,9 @@ func (app *appContext) checkInvite(code string, used bool, username string) bool
}
wait.Wait()
}
changed = true
match = false
app.storage.DeleteInvitesKey(code)
} else if used {
changed = true
del := false
newInv := inv
if newInv.RemainingUses == 1 {
@ -122,9 +114,6 @@ func (app *appContext) checkInvite(code string, used bool, username string) bool
app.storage.SetInvitesKey(code, newInv)
}
}
if changed {
app.storage.storeInvites()
}
return match
}
@ -220,7 +209,6 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
}
}
app.storage.SetInvitesKey(inviteCode, invite)
app.storage.storeInvites()
respondBool(200, true, gc)
}
@ -236,10 +224,10 @@ func (app *appContext) GetInvites(gc *gin.Context) {
app.storage.loadInvites()
app.checkInvites()
var invites []inviteDTO
for code, inv := range app.storage.GetInvites() {
for _, inv := range app.storage.GetInvites() {
_, months, days, hours, minutes, _ := timeDiff(inv.ValidTill, currentTime)
invite := inviteDTO{
Code: code,
Code: inv.Code,
Months: months,
Days: days,
Hours: hours,
@ -277,21 +265,19 @@ func (app *appContext) GetInvites(gc *gin.Context) {
invite.SendTo = inv.SendTo
}
if len(inv.Notify) != 0 {
var address string
// app.err.Printf("%s has notify section: %+v, you are %s\n", inv.Code, inv.Notify, gc.GetString("jfId"))
var addressOrID string
if app.config.Section("ui").Key("jellyfin_login").MustBool(false) {
app.storage.loadEmails()
if addr, ok := app.storage.GetEmailsKey(gc.GetString("jfId")); ok && addr.Addr != "" {
address = addr.Addr
}
addressOrID = gc.GetString("jfId")
} else {
address = app.config.Section("ui").Key("email").String()
addressOrID = app.config.Section("ui").Key("email").String()
}
if _, ok := inv.Notify[address]; ok {
if _, ok = inv.Notify[address]["notify-expiry"]; ok {
invite.NotifyExpiry = inv.Notify[address]["notify-expiry"]
if _, ok := inv.Notify[addressOrID]; ok {
if _, ok = inv.Notify[addressOrID]["notify-expiry"]; ok {
invite.NotifyExpiry = inv.Notify[addressOrID]["notify-expiry"]
}
if _, ok = inv.Notify[address]["notify-creation"]; ok {
invite.NotifyCreation = inv.Notify[address]["notify-creation"]
if _, ok = inv.Notify[addressOrID]["notify-creation"]; ok {
invite.NotifyCreation = inv.Notify[addressOrID]["notify-creation"]
}
}
}
@ -338,7 +324,6 @@ func (app *appContext) SetProfile(gc *gin.Context) {
inv, _ := app.storage.GetInvitesKey(req.Invite)
inv.Profile = req.Profile
app.storage.SetInvitesKey(req.Invite, inv)
app.storage.storeInvites()
respondBool(200, true, gc)
}
@ -401,9 +386,6 @@ func (app *appContext) SetNotify(gc *gin.Context) {
app.storage.SetInvitesKey(code, invite)
}
}
if changed {
app.storage.storeInvites()
}
}
// @Summary Delete an invite.
@ -422,7 +404,6 @@ func (app *appContext) DeleteInvite(gc *gin.Context) {
_, ok = app.storage.GetInvitesKey(req.Code)
if ok {
app.storage.DeleteInvitesKey(req.Code)
app.storage.storeInvites()
app.info.Printf("%s: Invite deleted", req.Code)
respondBool(200, true, gc)
return

@ -387,11 +387,6 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
change := dcUser.Contact != req.Discord
dcUser.Contact = req.Discord
app.storage.SetDiscordKey(req.ID, dcUser)
if err := app.storage.storeDiscordUsers(); err != nil {
respondBool(500, false, gc)
app.err.Printf("Discord: Failed to store users: %v", err)
return
}
if change {
msg := ""
if !req.Discord {
@ -404,11 +399,6 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
change := mxUser.Contact != req.Matrix
mxUser.Contact = req.Matrix
app.storage.SetMatrixKey(req.ID, mxUser)
if err := app.storage.storeMatrixUsers(); err != nil {
respondBool(500, false, gc)
app.err.Printf("Matrix: Failed to store users: %v", err)
return
}
if change {
msg := ""
if !req.Matrix {
@ -421,11 +411,6 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
change := email.Contact != req.Email
email.Contact = req.Email
app.storage.SetEmailsKey(req.ID, email)
if err := app.storage.storeEmails(); err != nil {
respondBool(500, false, gc)
app.err.Printf("Failed to store emails: %v", err)
return
}
if change {
msg := ""
if !req.Email {
@ -646,7 +631,7 @@ func (app *appContext) MatrixConnect(gc *gin.Context) {
var req MatrixConnectUserDTO
gc.BindJSON(&req)
if app.storage.GetMatrix() == nil {
app.storage.matrix = matrixStore{}
app.storage.deprecatedMatrix = matrixStore{}
}
roomID, encrypted, err := app.matrix.CreateRoom(req.UserID)
if err != nil {
@ -662,11 +647,6 @@ func (app *appContext) MatrixConnect(gc *gin.Context) {
Encrypted: encrypted,
})
app.matrix.isEncrypted[roomID] = encrypted
if err := app.storage.storeMatrixUsers(); err != nil {
app.err.Printf("Failed to store Matrix users: %v", err)
respondBool(500, false, gc)
return
}
respondBool(200, true, gc)
}
@ -717,11 +697,6 @@ func (app *appContext) DiscordConnect(gc *gin.Context) {
return
}
app.storage.SetDiscordKey(req.JellyfinID, user)
if err := app.storage.storeDiscordUsers(); err != nil {
app.err.Printf("Failed to store Discord users: %v", err)
respondBool(500, false, gc)
return
}
linkExistingOmbiDiscordTelegram(app)
respondBool(200, true, gc)
}

@ -38,8 +38,8 @@ func (app *appContext) MyDetails(gc *gin.Context) {
}
resp.Disabled = user.Policy.IsDisabled
if exp, ok := app.storage.users[user.ID]; ok {
resp.Expiry = exp.Unix()
if exp, ok := app.storage.GetUserExpiryKey(user.ID); ok {
resp.Expiry = exp.Expiry.Unix()
}
app.storage.loadEmails()
@ -199,7 +199,6 @@ func (app *appContext) confirmMyAction(gc *gin.Context, key string) {
}
}
app.storage.storeEmails()
app.info.Println("Email list modified")
gc.Redirect(http.StatusSeeOther, "/my/account")
return

@ -62,7 +62,6 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
app.jf.CacheExpiry = time.Now()
if emailEnabled {
app.storage.SetEmailsKey(id, EmailAddress{Addr: req.Email, Contact: true})
app.storage.storeEmails()
}
if app.config.Section("ombi").Key("enabled").MustBool(false) {
app.storage.loadOmbiTemplate()
@ -327,29 +326,19 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
// if app.config.Section("password_resets").Key("enabled").MustBool(false) {
if req.Email != "" {
app.storage.SetEmailsKey(id, EmailAddress{Addr: req.Email, Contact: true})
app.storage.storeEmails()
}
expiry := time.Time{}
if invite.UserExpiry {
app.storage.usersLock.Lock()
defer app.storage.usersLock.Unlock()
expiry = time.Now().AddDate(0, invite.UserMonths, invite.UserDays).Add(time.Duration((60*invite.UserHours)+invite.UserMinutes) * time.Minute)
app.storage.users[id] = expiry
if err := app.storage.storeUsers(); err != nil {
app.err.Printf("Failed to store user duration: %v", err)
}
app.storage.SetUserExpiryKey(id, UserExpiry{Expiry: expiry})
}
if discordVerified {
discordUser.Contact = req.DiscordContact
if app.storage.discord == nil {
app.storage.discord = discordStore{}
if app.storage.deprecatedDiscord == nil {
app.storage.deprecatedDiscord = discordStore{}
}
app.storage.SetDiscordKey(user.ID, discordUser)
if err := app.storage.storeDiscordUsers(); err != nil {
app.err.Printf("Failed to store Discord users: %v", err)
} else {
delete(app.discord.verifiedTokens, req.DiscordPIN)
}
delete(app.discord.verifiedTokens, req.DiscordPIN)
}
if telegramVerified {
tgUser := TelegramUser{
@ -360,8 +349,8 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
if lang, ok := app.telegram.languages[tgToken.ChatID]; ok {
tgUser.Lang = lang
}
if app.storage.telegram == nil {
app.storage.telegram = telegramStore{}
if app.storage.deprecatedTelegram == nil {
app.storage.deprecatedTelegram = telegramStore{}
}
app.telegram.DeleteVerifiedToken(req.TelegramPIN)
app.storage.SetTelegramKey(user.ID, tgUser)
@ -404,13 +393,10 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
if matrixVerified {
matrixUser.Contact = req.MatrixContact
delete(app.matrix.tokens, req.MatrixPIN)
if app.storage.matrix == nil {
app.storage.matrix = matrixStore{}
if app.storage.deprecatedMatrix == nil {
app.storage.deprecatedMatrix = matrixStore{}
}
app.storage.SetMatrixKey(user.ID, matrixUser)
if err := app.storage.storeMatrixUsers(); err != nil {
app.err.Printf("Failed to store Matrix users: %v", err)
}
}
if (emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "") || telegramVerified || discordVerified || matrixVerified {
name := app.getAddressOrName(user.ID)
@ -629,21 +615,16 @@ func (app *appContext) ExtendExpiry(gc *gin.Context) {
respondBool(400, false, gc)
return
}
app.storage.usersLock.Lock()
defer app.storage.usersLock.Unlock()
for _, id := range req.Users {
if expiry, ok := app.storage.users[id]; ok {
app.storage.users[id] = expiry.AddDate(0, req.Months, req.Days).Add(time.Duration(((60 * req.Hours) + req.Minutes)) * time.Minute)
base := time.Now()
if expiry, ok := app.storage.GetUserExpiryKey(id); ok {
base = expiry.Expiry
app.debug.Printf("Expiry extended for \"%s\"", id)
} else {
app.storage.users[id] = time.Now().AddDate(0, req.Months, req.Days).Add(time.Duration(((60 * req.Hours) + req.Minutes)) * time.Minute)
app.debug.Printf("Created expiry for \"%s\"", id)
}
}
if err := app.storage.storeUsers(); err != nil {
app.err.Printf("Failed to store user duration: %v", err)
respondBool(500, false, gc)
return
expiry := UserExpiry{Expiry: base.AddDate(0, req.Months, req.Days).Add(time.Duration(((60 * req.Hours) + req.Minutes)) * time.Minute)}
app.storage.SetUserExpiryKey(id, expiry)
}
respondBool(204, true, gc)
}
@ -853,8 +834,6 @@ func (app *appContext) GetUsers(gc *gin.Context) {
adminOnly := app.config.Section("ui").Key("admin_only").MustBool(true)
allowAll := app.config.Section("ui").Key("allow_all").MustBool(false)
i := 0
app.storage.usersLock.Lock()
defer app.storage.usersLock.Unlock()
for _, jfUser := range users {
user := respUser{
ID: jfUser.ID,
@ -871,9 +850,9 @@ func (app *appContext) GetUsers(gc *gin.Context) {
user.Label = email.Label
user.AccountsAdmin = (app.jellyfinLogin) && (email.Admin || (adminOnly && jfUser.Policy.IsAdministrator) || allowAll)
}
expiry, ok := app.storage.users[jfUser.ID]
expiry, ok := app.storage.GetUserExpiryKey(jfUser.ID)
if ok {
user.Expiry = expiry.Unix()
user.Expiry = expiry.Expiry.Unix()
}
if tgUser, ok := app.storage.GetTelegramKey(jfUser.ID); ok {
user.Telegram = tgUser.Username
@ -924,10 +903,6 @@ func (app *appContext) SetAccountsAdmin(gc *gin.Context) {
app.storage.SetEmailsKey(id, emailStore)
}
}
if err := app.storage.storeEmails(); err != nil {
app.err.Printf("Failed to store email list: %v", err)
respondBool(500, false, gc)
}
app.info.Println("Email list modified")
respondBool(204, true, gc)
}
@ -961,10 +936,6 @@ func (app *appContext) ModifyLabels(gc *gin.Context) {
app.storage.SetEmailsKey(id, emailStore)
}
}
if err := app.storage.storeEmails(); err != nil {
app.err.Printf("Failed to store email list: %v", err)
respondBool(500, false, gc)
}
app.info.Println("Email list modified")
respondBool(204, true, gc)
}
@ -999,7 +970,6 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
// Auto enable contact by email for newly added addresses
if !ok || oldEmail.Addr == "" {
emailStore.Contact = true
app.storage.storeEmails()
}
emailStore.Addr = address
@ -1016,7 +986,6 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
}
}
}
app.storage.storeEmails()
app.info.Println("Email list modified")
respondBool(200, true, gc)
}

@ -362,7 +362,7 @@ func start(asDaemon, firstCall bool) {
app.err.Printf("Failed to load Displayprefs: %v", err)
}
app.storage.users_path = app.config.Section("files").Key("users").String()
if err := app.storage.loadUsers(); err != nil {
if err := app.storage.loadUserExpiries(); err != nil {
app.err.Printf("Failed to load Users: %v", err)
}
app.storage.telegram_path = app.config.Section("files").Key("telegram_users").String()
@ -400,11 +400,6 @@ func start(asDaemon, firstCall bool) {
app.storage.db_path = filepath.Join(app.dataPath, "db")
app.ConnectDB()
defer app.storage.db.Close()
if !app.config.Section("").Key("migrated_to_db").MustBool(false) {
// FIXME: Mark as done at some point
migrateToBadger(app)
}
// Read config-base for settings on web.
app.configBasePath = "config-base.json"
configBase, _ := fs.ReadFile(localFS, app.configBasePath)

@ -16,26 +16,28 @@ func runMigrations(app *appContext) {
migrateNotificationMethods(app)
linkExistingOmbiDiscordTelegram(app)
// migrateHyphens(app)
migrateToBadger(app)
}
// Migrate pre-0.2.0 user templates to profiles
func migrateProfiles(app *appContext) {
if !(app.storage.policy.BlockedTags == nil && app.storage.configuration.GroupedFolders == nil && len(app.storage.displayprefs) == 0) {
app.info.Println("Migrating user template files to new profile format")
app.storage.migrateToProfile()
for _, path := range [3]string{app.storage.policy_path, app.storage.configuration_path, app.storage.displayprefs_path} {
if _, err := os.Stat(path); !os.IsNotExist(err) {
dir, fname := filepath.Split(path)
newFname := strings.Replace(fname, ".json", ".old.json", 1)
err := os.Rename(path, filepath.Join(dir, newFname))
if err != nil {
app.err.Fatalf("Failed to rename %s: %s", fname, err)
}
if app.storage.policy.BlockedTags == nil && app.storage.configuration.GroupedFolders == nil && len(app.storage.displayprefs) == 0 {
return
}
app.info.Println("Migrating user template files to new profile format")
app.storage.migrateToProfile()
for _, path := range [3]string{app.storage.policy_path, app.storage.configuration_path, app.storage.displayprefs_path} {
if _, err := os.Stat(path); !os.IsNotExist(err) {
dir, fname := filepath.Split(path)
newFname := strings.Replace(fname, ".json", ".old.json", 1)
err := os.Rename(path, filepath.Join(dir, newFname))
if err != nil {
app.err.Fatalf("Failed to rename %s: %s", fname, err)
}
}
app.info.Println("In case of a problem, your original files have been renamed to <file>.old.json")
app.storage.storeProfiles()
}
app.info.Println("In case of a problem, your original files have been renamed to <file>.old.json")
app.storage.storeProfiles()
}
// Migrate pre-0.2.5 bootstrap theme choice to a17t version.
@ -131,7 +133,7 @@ func migrateNotificationMethods(app *appContext) error {
return nil
}
changes := false
for code, invite := range app.storage.invites {
for code, invite := range app.storage.deprecatedInvites {
if invite.Notify == nil {
continue
}
@ -149,7 +151,7 @@ func migrateNotificationMethods(app *appContext) error {
}
}
if changes {
app.storage.invites[code] = invite
app.storage.deprecatedInvites[code] = invite
}
}
if changes {
@ -195,31 +197,45 @@ func linkExistingOmbiDiscordTelegram(app *appContext) error {
}
func migrateToBadger(app *appContext) {
if app.config.Section("").Key("migrated_to_db").MustBool(false) {
return
// FIXME: Mark as done at some point
}
app.info.Println("Migrating to Badger(hold)")
app.storage.loadAnnouncements()
for k, v := range app.storage.announcements {
for k, v := range app.storage.deprecatedAnnouncements {
app.storage.SetAnnouncementsKey(k, v)
}
app.storage.loadDiscordUsers()
for jfID, v := range app.storage.discord {
for jfID, v := range app.storage.deprecatedDiscord {
app.storage.SetDiscordKey(jfID, v)
}
app.storage.loadTelegramUsers()
for jfID, v := range app.storage.telegram {
for jfID, v := range app.storage.deprecatedTelegram {
app.storage.SetTelegramKey(jfID, v)
}
app.storage.loadMatrixUsers()
for jfID, v := range app.storage.matrix {
for jfID, v := range app.storage.deprecatedMatrix {
app.storage.SetMatrixKey(jfID, v)
}
app.storage.loadEmails()
for jfID, v := range app.storage.emails {
for jfID, v := range app.storage.deprecatedEmails {
app.storage.SetEmailsKey(jfID, v)
}
app.storage.loadInvites()
for k, v := range app.storage.deprecatedInvites {
app.storage.SetInvitesKey(k, v)
}
app.storage.loadUserExpiries()
for k, v := range app.storage.deprecatedUserExpiries {
app.storage.SetUserExpiryKey(k, UserExpiry{Expiry: v})
}
}
// Migrate between hyphenated & non-hyphenated user IDs. Doesn't seem to happen anymore, so disabled.
@ -283,7 +299,7 @@ func migrateToBadger(app *appContext) {
// app.storage.emails = newEmails
// app.storage.users = newUsers
// err = app.storage.storeEmails()
// err2 = app.storage.storeUsers()
// err2 = app.storage.storeUserExpiries()
// if err != nil {
// app.err.Fatalf("couldn't store emails.json: %v", err)
// }

@ -8,7 +8,6 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"github.com/hrfee/mediabrowser"
@ -21,6 +20,11 @@ type telegramStore map[string]TelegramUser
type matrixStore map[string]MatrixUser
type emailStore map[string]EmailAddress
type UserExpiry struct {
JellyfinID string `badgerhold:"key"`
Expiry time.Time
}
type Storage struct {
timePattern string
@ -28,22 +32,21 @@ type Storage struct {
db *badgerhold.Store
invite_path, emails_path, policy_path, configuration_path, displayprefs_path, ombi_path, profiles_path, customEmails_path, users_path, telegram_path, discord_path, matrix_path, announcements_path, matrix_sql_path, userPage_path string
users map[string]time.Time // Map of Jellyfin User IDs to their expiry times.
invites Invites
deprecatedUserExpiries map[string]time.Time // Map of Jellyfin User IDs to their expiry times.
deprecatedInvites Invites
profiles map[string]Profile
defaultProfile string
displayprefs, ombi_template map[string]interface{}
emails emailStore // Map of Jellyfin User IDs to Email addresses.
telegram telegramStore // Map of Jellyfin User IDs to telegram users.
discord discordStore // Map of Jellyfin user IDs to discord users.
matrix matrixStore // Map of Jellyfin user IDs to Matrix users.
deprecatedEmails emailStore // Map of Jellyfin User IDs to Email addresses.
deprecatedTelegram telegramStore // Map of Jellyfin User IDs to telegram users.
deprecatedDiscord discordStore // Map of Jellyfin user IDs to discord users.
deprecatedMatrix matrixStore // Map of Jellyfin user IDs to Matrix users.
customEmails customEmails
userPage userPageContent
policy mediabrowser.Policy
configuration mediabrowser.Configuration
lang Lang
announcements map[string]announcementTemplate
invitesLock, usersLock, discordLock, telegramLock, matrixLock, emailsLock sync.Mutex
deprecatedAnnouncements map[string]announcementTemplate
}
func (app *appContext) ConnectDB() {
@ -203,36 +206,39 @@ func (st *Storage) DeleteMatrixKey(k string) {
}
// GetInvites returns a copy of the store.
func (st *Storage) GetInvites() Invites {
if st.invites == nil {
st.invites = Invites{}
func (st *Storage) GetInvites() []Invite {
result := []Invite{}
err := st.db.Find(&result, &badgerhold.Query{})
if err != nil {
// fmt.Printf("Failed to find invites: %v\n", err)
}
return st.invites
return result
}
// GetInvitesKey returns the value stored in the store's key.
func (st *Storage) GetInvitesKey(k string) (Invite, bool) {
v, ok := st.invites[k]
return v, ok
result := Invite{}
err := st.db.Get(k, &result)
ok := true
if err != nil {
// fmt.Printf("Failed to find invite: %v\n", err)
ok = false
}
return result, ok
}
// SetInvitesKey stores value v in key k.
func (st *Storage) SetInvitesKey(k string, v Invite) {
st.invitesLock.Lock()
if st.invites == nil {
st.invites = Invites{}
v.Code = k
err := st.db.Upsert(k, v)
if err != nil {
// fmt.Printf("Failed to set invite: %v\n", err)
}
st.invites[k] = v
st.storeInvites()
st.invitesLock.Unlock()
}
// DeleteInvitesKey deletes value at key k.
func (st *Storage) DeleteInvitesKey(k string) {
st.invitesLock.Lock()
delete(st.invites, k)
st.storeInvites()
st.invitesLock.Unlock()
st.db.Delete(k, Invite{})
}
// GetAnnouncements returns a copy of the store.
@ -270,6 +276,42 @@ func (st *Storage) DeleteAnnouncementsKey(k string) {
st.db.Delete(k, announcementTemplate{})
}
// GetUserExpiries returns a copy of the store.
func (st *Storage) GetUserExpiries() []UserExpiry {
result := []UserExpiry{}
err := st.db.Find(&result, &badgerhold.Query{})
if err != nil {
// fmt.Printf("Failed to find expiries: %v\n", err)
}
return result
}
// GetUserExpiryKey returns the value stored in the store's key.
func (st *Storage) GetUserExpiryKey(k string) (UserExpiry, bool) {
result := UserExpiry{}
err := st.db.Get(k, &result)
ok := true
if err != nil {
// fmt.Printf("Failed to find expiry: %v\n", err)
ok = false
}
return result, ok
}
// SetUserExpiryKey stores value v in key k.
func (st *Storage) SetUserExpiryKey(k string, v UserExpiry) {
v.JellyfinID = k
err := st.db.Upsert(k, v)
if err != nil {
// fmt.Printf("Failed to set expiry: %v\n", err)
}
}
// DeleteUserExpiryKey deletes value at key k.
func (st *Storage) DeleteUserExpiryKey(k string) {
st.db.Delete(k, UserExpiry{})
}
type TelegramUser struct {
JellyfinID string `badgerhold:"key"`
ChatID int64 `badgerhold:"index"`
@ -335,6 +377,7 @@ type Profile struct {
}
type Invite struct {
Code string `badgerhold:"key"`
Created time.Time `json:"created"`
NoLimit bool `json:"no-limit"`
RemainingUses int `json:"remaining-uses"`
@ -1036,18 +1079,16 @@ func (st *Storage) loadLangTelegram(filesystems ...fs.FS) error {
type Invites map[string]Invite
func (st *Storage) loadInvites() error {
return loadJSON(st.invite_path, &st.invites)
return loadJSON(st.invite_path, &st.deprecatedInvites)
}
func (st *Storage) storeInvites() error {
return storeJSON(st.invite_path, st.invites)
return storeJSON(st.invite_path, st.deprecatedInvites)
}
func (st *Storage) loadUsers() error {
st.usersLock.Lock()
defer st.usersLock.Unlock()
if st.users == nil {
st.users = map[string]time.Time{}
func (st *Storage) loadUserExpiries() error {
if st.deprecatedUserExpiries == nil {
st.deprecatedUserExpiries = map[string]time.Time{}
}
temp := map[string]time.Time{}
err := loadJSON(st.users_path, &temp)
@ -1055,47 +1096,47 @@ func (st *Storage) loadUsers() error {
return err
}
for id, t1 := range temp {
if _, ok := st.users[id]; !ok {
st.users[id] = t1
if _, ok := st.deprecatedUserExpiries[id]; !ok {
st.deprecatedUserExpiries[id] = t1
}
}
return nil
}
func (st *Storage) storeUsers() error {
return storeJSON(st.users_path, st.users)
func (st *Storage) storeUserExpiries() error {
return storeJSON(st.users_path, st.deprecatedUserExpiries)
}
func (st *Storage) loadEmails() error {
return loadJSON(st.emails_path, &st.emails)
return loadJSON(st.emails_path, &st.deprecatedEmails)
}
func (st *Storage) storeEmails() error {
return storeJSON(st.emails_path, st.emails)
return storeJSON(st.emails_path, st.deprecatedEmails)
}
func (st *Storage) loadTelegramUsers() error {
return loadJSON(st.telegram_path, &st.telegram)
return loadJSON(st.telegram_path, &st.deprecatedTelegram)
}
func (st *Storage) storeTelegramUsers() error {
return storeJSON(st.telegram_path, st.telegram)
return storeJSON(st.telegram_path, st.deprecatedTelegram)
}
func (st *Storage) loadDiscordUsers() error {
return loadJSON(st.discord_path, &st.discord)
return loadJSON(st.discord_path, &st.deprecatedDiscord)
}
func (st *Storage) storeDiscordUsers() error {
return storeJSON(st.discord_path, st.discord)
return storeJSON(st.discord_path, st.deprecatedDiscord)
}
func (st *Storage) loadMatrixUsers() error {
return loadJSON(st.matrix_path, &st.matrix)
return loadJSON(st.matrix_path, &st.deprecatedMatrix)
}
func (st *Storage) storeMatrixUsers() error {
return storeJSON(st.matrix_path, st.matrix)
return storeJSON(st.matrix_path, st.deprecatedMatrix)
}
func (st *Storage) loadCustomEmails() error {
@ -1147,11 +1188,11 @@ func (st *Storage) storeOmbiTemplate() error {
}
func (st *Storage) loadAnnouncements() error {
return loadJSON(st.announcements_path, &st.announcements)
return loadJSON(st.announcements_path, &st.deprecatedAnnouncements)
}
func (st *Storage) storeAnnouncements() error {
return storeJSON(st.announcements_path, st.announcements)
return storeJSON(st.announcements_path, st.deprecatedAnnouncements)
}
func (st *Storage) loadProfiles() error {

@ -221,9 +221,6 @@ func (t *TelegramDaemon) commandLang(upd *tg.Update, sects []string, lang string
if user.ChatID == upd.Message.Chat.ID {
user.Lang = sects[1]
t.app.storage.SetTelegramKey(user.JellyfinID, user)
if err := t.app.storage.storeTelegramUsers(); err != nil {
t.app.err.Printf("Failed to store Telegram users: %v", err)
}
break
}
}

@ -50,13 +50,7 @@ func (rt *userDaemon) shutdown() {
}
func (app *appContext) checkUsers() {
if err := app.storage.loadUsers(); err != nil {
app.err.Printf("Failed to load user expiries: %v", err)
return
}
app.storage.usersLock.Lock()
defer app.storage.usersLock.Unlock()
if len(app.storage.users) == 0 {
if len(app.storage.GetUserExpiries()) == 0 {
return
}
app.info.Println("Daemon: Checking for user expiry")
@ -80,11 +74,12 @@ func (app *appContext) checkUsers() {
for _, user := range users {
userExists[user.ID] = true
}
for id, expiry := range app.storage.users {
for _, expiry := range app.storage.GetUserExpiries() {
id := expiry.JellyfinID
if _, ok := userExists[id]; !ok {
app.info.Printf("Deleting expiry for non-existent user \"%s\"", id)
delete(app.storage.users, id)
} else if time.Now().After(expiry) {
app.storage.DeleteUserExpiryKey(expiry.JellyfinID)
} else if time.Now().After(expiry.Expiry) {
found := false
var user mediabrowser.User
for _, u := range users {
@ -96,7 +91,7 @@ func (app *appContext) checkUsers() {
}
if !found {
app.info.Printf("Expired user already deleted, ignoring.")
delete(app.storage.users, id)
app.storage.DeleteUserExpiryKey(expiry.JellyfinID)
continue
}
app.info.Printf("%s expired user \"%s\"", termPlural, user.Name)
@ -112,7 +107,7 @@ func (app *appContext) checkUsers() {
app.err.Printf("Failed to %s \"%s\" (%d): %s", mode, user.Name, status, err)
continue
}
delete(app.storage.users, id)
app.storage.DeleteUserExpiryKey(expiry.JellyfinID)
app.jf.CacheExpiry = time.Now()
if contact {
if !ok {
@ -130,8 +125,4 @@ func (app *appContext) checkUsers() {
}
}
}
err = app.storage.storeUsers()
if err != nil {
app.err.Printf("Failed to store user expiries: %s", err)
}
}

Loading…
Cancel
Save