1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-12-22 09:00:10 +00:00

db: migrate invites, user expiry

some fixes to stuff in there too, probably
This commit is contained in:
Harvey Tindall 2023-06-24 19:13:05 +01:00
parent a470d77938
commit 63948a6de0
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
9 changed files with 168 additions and 204 deletions

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
// }

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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)
}
}