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

storage: user set/get methods for contact method access

Get/GetKey/SetKey/DeleteKey methods are used for access to
email/discord/telegram/matrix, everywhere. Mutex added for each, avoids
concurrent read/write issues. Will also make potential transition to
database easier.
This commit is contained in:
Harvey Tindall 2023-06-20 12:19:24 +01:00
parent fcedea110d
commit 68004e1d34
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
15 changed files with 397 additions and 301 deletions

View File

@ -280,7 +280,7 @@ func (app *appContext) GetInvites(gc *gin.Context) {
var address string var address string
if app.config.Section("ui").Key("jellyfin_login").MustBool(false) { if app.config.Section("ui").Key("jellyfin_login").MustBool(false) {
app.storage.loadEmails() app.storage.loadEmails()
if addr, ok := app.storage.emails[gc.GetString("jfId")]; ok && addr.Addr != "" { if addr, ok := app.storage.GetEmailsKey(gc.GetString("jfId")); ok && addr.Addr != "" {
address = addr.Addr address = addr.Addr
} }
} else { } else {

View File

@ -305,10 +305,10 @@ func (app *appContext) TelegramAddUser(gc *gin.Context) {
if lang, ok := app.telegram.languages[tgToken.ChatID]; ok { if lang, ok := app.telegram.languages[tgToken.ChatID]; ok {
tgUser.Lang = lang tgUser.Lang = lang
} }
if app.storage.telegram == nil { if app.storage.GetTelegram() == nil {
app.storage.telegram = map[string]TelegramUser{} app.storage.telegram = telegramStore{}
} }
app.storage.telegram[req.ID] = tgUser app.storage.SetTelegramKey(req.ID, tgUser)
err := app.storage.storeTelegramUsers() err := app.storage.storeTelegramUsers()
if err != nil { if err != nil {
app.err.Printf("Failed to store Telegram users: %v", err) app.err.Printf("Failed to store Telegram users: %v", err)
@ -340,15 +340,10 @@ func (app *appContext) SetContactMethods(gc *gin.Context) {
} }
func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Context) { func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Context) {
if tgUser, ok := app.storage.telegram[req.ID]; ok { if tgUser, ok := app.storage.GetTelegramKey(req.ID); ok {
change := tgUser.Contact != req.Telegram change := tgUser.Contact != req.Telegram
tgUser.Contact = req.Telegram tgUser.Contact = req.Telegram
app.storage.telegram[req.ID] = tgUser app.storage.SetTelegramKey(req.ID, tgUser)
if err := app.storage.storeTelegramUsers(); err != nil {
respondBool(500, false, gc)
app.err.Printf("Telegram: Failed to store users: %v", err)
return
}
if change { if change {
msg := "" msg := ""
if !req.Telegram { if !req.Telegram {
@ -357,10 +352,10 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
app.debug.Printf("Telegram: User \"%s\" will%s be notified through Telegram.", tgUser.Username, msg) app.debug.Printf("Telegram: User \"%s\" will%s be notified through Telegram.", tgUser.Username, msg)
} }
} }
if dcUser, ok := app.storage.discord[req.ID]; ok { if dcUser, ok := app.storage.GetDiscordKey(req.ID); ok {
change := dcUser.Contact != req.Discord change := dcUser.Contact != req.Discord
dcUser.Contact = req.Discord dcUser.Contact = req.Discord
app.storage.discord[req.ID] = dcUser app.storage.SetDiscordKey(req.ID, dcUser)
if err := app.storage.storeDiscordUsers(); err != nil { if err := app.storage.storeDiscordUsers(); err != nil {
respondBool(500, false, gc) respondBool(500, false, gc)
app.err.Printf("Discord: Failed to store users: %v", err) app.err.Printf("Discord: Failed to store users: %v", err)
@ -374,10 +369,10 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
app.debug.Printf("Discord: User \"%s\" will%s be notified through Discord.", dcUser.Username, msg) app.debug.Printf("Discord: User \"%s\" will%s be notified through Discord.", dcUser.Username, msg)
} }
} }
if mxUser, ok := app.storage.matrix[req.ID]; ok { if mxUser, ok := app.storage.GetMatrixKey(req.ID); ok {
change := mxUser.Contact != req.Matrix change := mxUser.Contact != req.Matrix
mxUser.Contact = req.Matrix mxUser.Contact = req.Matrix
app.storage.matrix[req.ID] = mxUser app.storage.SetMatrixKey(req.ID, mxUser)
if err := app.storage.storeMatrixUsers(); err != nil { if err := app.storage.storeMatrixUsers(); err != nil {
respondBool(500, false, gc) respondBool(500, false, gc)
app.err.Printf("Matrix: Failed to store users: %v", err) app.err.Printf("Matrix: Failed to store users: %v", err)
@ -391,10 +386,10 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
app.debug.Printf("Matrix: User \"%s\" will%s be notified through Matrix.", mxUser.UserID, msg) app.debug.Printf("Matrix: User \"%s\" will%s be notified through Matrix.", mxUser.UserID, msg)
} }
} }
if email, ok := app.storage.emails[req.ID]; ok { if email, ok := app.storage.GetEmailsKey(req.ID); ok {
change := email.Contact != req.Email change := email.Contact != req.Email
email.Contact = req.Email email.Contact = req.Email
app.storage.emails[req.ID] = email app.storage.SetEmailsKey(req.ID, email)
if err := app.storage.storeEmails(); err != nil { if err := app.storage.storeEmails(); err != nil {
respondBool(500, false, gc) respondBool(500, false, gc)
app.err.Printf("Failed to store emails: %v", err) app.err.Printf("Failed to store emails: %v", err)
@ -458,7 +453,7 @@ func (app *appContext) TelegramVerifiedInvite(gc *gin.Context) {
} }
} }
if app.config.Section("telegram").Key("require_unique").MustBool(false) { if app.config.Section("telegram").Key("require_unique").MustBool(false) {
for _, u := range app.storage.telegram { for _, u := range app.storage.GetTelegram() {
if app.telegram.verifiedTokens[tokenIndex].Username == u.Username { if app.telegram.verifiedTokens[tokenIndex].Username == u.Username {
respondBool(400, false, gc) respondBool(400, false, gc)
return return
@ -490,7 +485,7 @@ func (app *appContext) DiscordVerifiedInvite(gc *gin.Context) {
pin := gc.Param("pin") pin := gc.Param("pin")
_, ok := app.discord.verifiedTokens[pin] _, ok := app.discord.verifiedTokens[pin]
if app.config.Section("discord").Key("require_unique").MustBool(false) { if app.config.Section("discord").Key("require_unique").MustBool(false) {
for _, u := range app.storage.discord { for _, u := range app.storage.GetDiscord() {
if app.discord.verifiedTokens[pin].ID == u.ID { if app.discord.verifiedTokens[pin].ID == u.ID {
delete(app.discord.verifiedTokens, pin) delete(app.discord.verifiedTokens, pin)
respondBool(400, false, gc) respondBool(400, false, gc)
@ -551,7 +546,7 @@ func (app *appContext) MatrixSendPIN(gc *gin.Context) {
return return
} }
if app.config.Section("matrix").Key("require_unique").MustBool(false) { if app.config.Section("matrix").Key("require_unique").MustBool(false) {
for _, u := range app.storage.matrix { for _, u := range app.storage.GetMatrix() {
if req.UserID == u.UserID { if req.UserID == u.UserID {
respondBool(400, false, gc) respondBool(400, false, gc)
return return
@ -648,8 +643,8 @@ func (app *appContext) MatrixLogin(gc *gin.Context) {
func (app *appContext) MatrixConnect(gc *gin.Context) { func (app *appContext) MatrixConnect(gc *gin.Context) {
var req MatrixConnectUserDTO var req MatrixConnectUserDTO
gc.BindJSON(&req) gc.BindJSON(&req)
if app.storage.matrix == nil { if app.storage.GetMatrix() == nil {
app.storage.matrix = map[string]MatrixUser{} app.storage.matrix = matrixStore{}
} }
roomID, encrypted, err := app.matrix.CreateRoom(req.UserID) roomID, encrypted, err := app.matrix.CreateRoom(req.UserID)
if err != nil { if err != nil {
@ -657,13 +652,13 @@ func (app *appContext) MatrixConnect(gc *gin.Context) {
respondBool(500, false, gc) respondBool(500, false, gc)
return return
} }
app.storage.matrix[req.JellyfinID] = MatrixUser{ app.storage.SetMatrixKey(req.JellyfinID, MatrixUser{
UserID: req.UserID, UserID: req.UserID,
RoomID: string(roomID), RoomID: string(roomID),
Lang: "en-us", Lang: "en-us",
Contact: true, Contact: true,
Encrypted: encrypted, Encrypted: encrypted,
} })
app.matrix.isEncrypted[roomID] = encrypted app.matrix.isEncrypted[roomID] = encrypted
if err := app.storage.storeMatrixUsers(); err != nil { if err := app.storage.storeMatrixUsers(); err != nil {
app.err.Printf("Failed to store Matrix users: %v", err) app.err.Printf("Failed to store Matrix users: %v", err)
@ -719,7 +714,7 @@ func (app *appContext) DiscordConnect(gc *gin.Context) {
respondBool(500, false, gc) respondBool(500, false, gc)
return return
} }
app.storage.discord[req.JellyfinID] = user app.storage.SetDiscordKey(req.JellyfinID, user)
if err := app.storage.storeDiscordUsers(); err != nil { if err := app.storage.storeDiscordUsers(); err != nil {
app.err.Printf("Failed to store Discord users: %v", err) app.err.Printf("Failed to store Discord users: %v", err)
respondBool(500, false, gc) respondBool(500, false, gc)
@ -743,8 +738,7 @@ func (app *appContext) UnlinkDiscord(gc *gin.Context) {
respond(400, "User not found", gc) respond(400, "User not found", gc)
return return
} */ } */
delete(app.storage.discord, req.ID) app.storage.DeleteDiscordKey(req.ID)
app.storage.storeDiscordUsers()
respondBool(200, true, gc) respondBool(200, true, gc)
} }
@ -762,8 +756,7 @@ func (app *appContext) UnlinkTelegram(gc *gin.Context) {
respond(400, "User not found", gc) respond(400, "User not found", gc)
return return
} */ } */
delete(app.storage.telegram, req.ID) app.storage.DeleteTelegramKey(req.ID)
app.storage.storeTelegramUsers()
respondBool(200, true, gc) respondBool(200, true, gc)
} }
@ -781,7 +774,6 @@ func (app *appContext) UnlinkMatrix(gc *gin.Context) {
respond(400, "User not found", gc) respond(400, "User not found", gc)
return return
} */ } */
delete(app.storage.matrix, req.ID) app.storage.DeleteMatrixKey(req.ID)
app.storage.storeMatrixUsers()
respondBool(200, true, gc) respondBool(200, true, gc)
} }

View File

@ -17,7 +17,7 @@ func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, int, er
} }
username := jfUser.Name username := jfUser.Name
email := "" email := ""
if e, ok := app.storage.emails[jfID]; ok { if e, ok := app.storage.GetEmailsKey(jfID); ok {
email = e.Addr email = e.Addr
} }
for _, ombiUser := range ombiUsers { for _, ombiUser := range ombiUsers {

View File

@ -41,7 +41,7 @@ func (app *appContext) MyDetails(gc *gin.Context) {
if emailEnabled { if emailEnabled {
resp.Email = &MyDetailsContactMethodsDTO{} resp.Email = &MyDetailsContactMethodsDTO{}
if email, ok := app.storage.emails[user.ID]; ok && email.Addr != "" { if email, ok := app.storage.GetEmailsKey(user.ID); ok && email.Addr != "" {
resp.Email.Value = email.Addr resp.Email.Value = email.Addr
resp.Email.Enabled = email.Contact resp.Email.Enabled = email.Contact
} }
@ -49,7 +49,7 @@ func (app *appContext) MyDetails(gc *gin.Context) {
if discordEnabled { if discordEnabled {
resp.Discord = &MyDetailsContactMethodsDTO{} resp.Discord = &MyDetailsContactMethodsDTO{}
if discord, ok := app.storage.discord[user.ID]; ok { if discord, ok := app.storage.GetDiscordKey(user.ID); ok {
resp.Discord.Value = RenderDiscordUsername(discord) resp.Discord.Value = RenderDiscordUsername(discord)
resp.Discord.Enabled = discord.Contact resp.Discord.Enabled = discord.Contact
} }
@ -57,7 +57,7 @@ func (app *appContext) MyDetails(gc *gin.Context) {
if telegramEnabled { if telegramEnabled {
resp.Telegram = &MyDetailsContactMethodsDTO{} resp.Telegram = &MyDetailsContactMethodsDTO{}
if telegram, ok := app.storage.telegram[user.ID]; ok { if telegram, ok := app.storage.GetTelegramKey(user.ID); ok {
resp.Telegram.Value = telegram.Username resp.Telegram.Value = telegram.Username
resp.Telegram.Enabled = telegram.Contact resp.Telegram.Enabled = telegram.Contact
} }
@ -65,7 +65,7 @@ func (app *appContext) MyDetails(gc *gin.Context) {
if matrixEnabled { if matrixEnabled {
resp.Matrix = &MyDetailsContactMethodsDTO{} resp.Matrix = &MyDetailsContactMethodsDTO{}
if matrix, ok := app.storage.matrix[user.ID]; ok { if matrix, ok := app.storage.GetMatrixKey(user.ID); ok {
resp.Matrix.Value = matrix.UserID resp.Matrix.Value = matrix.UserID
resp.Matrix.Enabled = matrix.Contact resp.Matrix.Enabled = matrix.Contact
} }
@ -172,14 +172,14 @@ func (app *appContext) confirmMyAction(gc *gin.Context, key string) {
gc.Redirect(http.StatusSeeOther, "/my/account") gc.Redirect(http.StatusSeeOther, "/my/account")
return return
} else if target == UserEmailChange { } else if target == UserEmailChange {
emailStore, ok := app.storage.emails[id] emailStore, ok := app.storage.GetEmailsKey(id)
if !ok { if !ok {
emailStore = EmailAddress{ emailStore = EmailAddress{
Contact: true, Contact: true,
} }
} }
emailStore.Addr = claims["email"].(string) emailStore.Addr = claims["email"].(string)
app.storage.emails[id] = emailStore app.storage.SetEmailsKey(id, emailStore)
if app.config.Section("ombi").Key("enabled").MustBool(false) { if app.config.Section("ombi").Key("enabled").MustBool(false) {
ombiUser, code, err := app.getOmbiUser(id) ombiUser, code, err := app.getOmbiUser(id)
if code == 200 && err == nil { if code == 200 && err == nil {
@ -320,7 +320,7 @@ func (app *appContext) MyDiscordVerifiedInvite(gc *gin.Context) {
return return
} }
if app.config.Section("discord").Key("require_unique").MustBool(false) { if app.config.Section("discord").Key("require_unique").MustBool(false) {
for _, u := range app.storage.discord { for _, u := range app.storage.GetDiscord() {
if app.discord.verifiedTokens[pin].ID == u.ID { if app.discord.verifiedTokens[pin].ID == u.ID {
delete(app.discord.verifiedTokens, pin) delete(app.discord.verifiedTokens, pin)
respondBool(400, false, gc) respondBool(400, false, gc)
@ -328,15 +328,12 @@ func (app *appContext) MyDiscordVerifiedInvite(gc *gin.Context) {
} }
} }
} }
dc := app.storage.discord existingUser, ok := app.storage.GetDiscordKey(gc.GetString("jfId"))
existingUser, ok := app.storage.discord[gc.GetString("jfId")]
if ok { if ok {
dcUser.Lang = existingUser.Lang dcUser.Lang = existingUser.Lang
dcUser.Contact = existingUser.Contact dcUser.Contact = existingUser.Contact
} }
dc[gc.GetString("jfId")] = dcUser app.storage.SetDiscordKey(gc.GetString("jfId"), dcUser)
app.storage.discord = dc
app.storage.storeDiscordUsers()
respondBool(200, true, gc) respondBool(200, true, gc)
} }
@ -361,7 +358,7 @@ func (app *appContext) MyTelegramVerifiedInvite(gc *gin.Context) {
return return
} }
if app.config.Section("telegram").Key("require_unique").MustBool(false) { if app.config.Section("telegram").Key("require_unique").MustBool(false) {
for _, u := range app.storage.telegram { for _, u := range app.storage.GetTelegram() {
if app.telegram.verifiedTokens[tokenIndex].Username == u.Username { if app.telegram.verifiedTokens[tokenIndex].Username == u.Username {
respondBool(400, false, gc) respondBool(400, false, gc)
return return
@ -374,13 +371,11 @@ func (app *appContext) MyTelegramVerifiedInvite(gc *gin.Context) {
Contact: true, Contact: true,
} }
tg := app.storage.telegram existingUser, ok := app.storage.GetTelegramKey(gc.GetString("jfId"))
existingUser, ok := app.storage.telegram[gc.GetString("jfId")]
if ok { if ok {
tgUser.Lang = existingUser.Lang tgUser.Lang = existingUser.Lang
tgUser.Contact = existingUser.Contact tgUser.Contact = existingUser.Contact
} }
tg[gc.GetString("jfId")] = tgUser app.storage.SetTelegramKey(gc.GetString("jfId"), tgUser)
app.storage.storeTelegramUsers()
respondBool(200, true, gc) respondBool(200, true, gc)
} }

View File

@ -61,7 +61,7 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
} }
app.jf.CacheExpiry = time.Now() app.jf.CacheExpiry = time.Now()
if emailEnabled { if emailEnabled {
app.storage.emails[id] = EmailAddress{Addr: req.Email, Contact: true} app.storage.SetEmailsKey(id, EmailAddress{Addr: req.Email, Contact: true})
app.storage.storeEmails() app.storage.storeEmails()
} }
if app.config.Section("ombi").Key("enabled").MustBool(false) { if app.config.Section("ombi").Key("enabled").MustBool(false) {
@ -131,7 +131,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
return return
} }
if app.config.Section("discord").Key("require_unique").MustBool(false) { if app.config.Section("discord").Key("require_unique").MustBool(false) {
for _, u := range app.storage.discord { for _, u := range app.storage.GetDiscord() {
if discordUser.ID == u.ID { if discordUser.ID == u.ID {
f = func(gc *gin.Context) { f = func(gc *gin.Context) {
app.debug.Printf("%s: New user failed: Discord user already linked", req.Code) app.debug.Printf("%s: New user failed: Discord user already linked", req.Code)
@ -177,7 +177,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
return return
} }
if app.config.Section("matrix").Key("require_unique").MustBool(false) { if app.config.Section("matrix").Key("require_unique").MustBool(false) {
for _, u := range app.storage.matrix { for _, u := range app.storage.GetMatrix() {
if user.User.UserID == u.UserID { if user.User.UserID == u.UserID {
f = func(gc *gin.Context) { f = func(gc *gin.Context) {
app.debug.Printf("%s: New user failed: Matrix user already linked", req.Code) app.debug.Printf("%s: New user failed: Matrix user already linked", req.Code)
@ -220,7 +220,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
return return
} }
if app.config.Section("telegram").Key("require_unique").MustBool(false) { if app.config.Section("telegram").Key("require_unique").MustBool(false) {
for _, u := range app.storage.telegram { for _, u := range app.storage.GetTelegram() {
if app.telegram.verifiedTokens[telegramTokenIndex].Username == u.Username { if app.telegram.verifiedTokens[telegramTokenIndex].Username == u.Username {
f = func(gc *gin.Context) { f = func(gc *gin.Context) {
app.debug.Printf("%s: New user failed: Telegram user already linked", req.Code) app.debug.Printf("%s: New user failed: Telegram user already linked", req.Code)
@ -339,7 +339,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
} }
// if app.config.Section("password_resets").Key("enabled").MustBool(false) { // if app.config.Section("password_resets").Key("enabled").MustBool(false) {
if req.Email != "" { if req.Email != "" {
app.storage.emails[id] = EmailAddress{Addr: req.Email, Contact: true} app.storage.SetEmailsKey(id, EmailAddress{Addr: req.Email, Contact: true})
app.storage.storeEmails() app.storage.storeEmails()
} }
expiry := time.Time{} expiry := time.Time{}
@ -355,9 +355,9 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
if discordEnabled && discordVerified { if discordEnabled && discordVerified {
discordUser.Contact = req.DiscordContact discordUser.Contact = req.DiscordContact
if app.storage.discord == nil { if app.storage.discord == nil {
app.storage.discord = map[string]DiscordUser{} app.storage.discord = discordStore{}
} }
app.storage.discord[user.ID] = discordUser app.storage.SetDiscordKey(user.ID, discordUser)
if err := app.storage.storeDiscordUsers(); err != nil { if err := app.storage.storeDiscordUsers(); err != nil {
app.err.Printf("Failed to store Discord users: %v", err) app.err.Printf("Failed to store Discord users: %v", err)
} else { } else {
@ -375,9 +375,9 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
tgUser.Lang = lang tgUser.Lang = lang
} }
if app.storage.telegram == nil { if app.storage.telegram == nil {
app.storage.telegram = map[string]TelegramUser{} app.storage.telegram = telegramStore{}
} }
app.storage.telegram[user.ID] = tgUser app.storage.SetTelegramKey(user.ID, tgUser)
if err := app.storage.storeTelegramUsers(); err != nil { if err := app.storage.storeTelegramUsers(); err != nil {
app.err.Printf("Failed to store Telegram users: %v", err) app.err.Printf("Failed to store Telegram users: %v", err)
} else { } else {
@ -405,7 +405,8 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
dID = discordUser.ID dID = discordUser.ID
} }
if telegramEnabled && telegramTokenIndex != -1 { if telegramEnabled && telegramTokenIndex != -1 {
tUser = app.storage.telegram[user.ID].Username u, _ := app.storage.GetTelegramKey(user.ID)
tUser = u.Username
} }
resp, status, err := app.ombi.SetNotificationPrefs(ombiUser, dID, tUser) resp, status, err := app.ombi.SetNotificationPrefs(ombiUser, dID, tUser)
if !(status == 200 || status == 204) || err != nil { if !(status == 200 || status == 204) || err != nil {
@ -423,9 +424,9 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
matrixUser.Contact = req.MatrixContact matrixUser.Contact = req.MatrixContact
delete(app.matrix.tokens, req.MatrixPIN) delete(app.matrix.tokens, req.MatrixPIN)
if app.storage.matrix == nil { if app.storage.matrix == nil {
app.storage.matrix = map[string]MatrixUser{} app.storage.matrix = matrixStore{}
} }
app.storage.matrix[user.ID] = matrixUser app.storage.SetMatrixKey(user.ID, matrixUser)
if err := app.storage.storeMatrixUsers(); err != nil { if err := app.storage.storeMatrixUsers(); err != nil {
app.err.Printf("Failed to store Matrix users: %v", err) app.err.Printf("Failed to store Matrix users: %v", err)
} }
@ -488,7 +489,7 @@ func (app *appContext) NewUser(gc *gin.Context) {
return return
} }
if app.config.Section("email").Key("require_unique").MustBool(false) && req.Email != "" { if app.config.Section("email").Key("require_unique").MustBool(false) && req.Email != "" {
for _, email := range app.storage.emails { for _, email := range app.storage.GetEmails() {
if req.Email == email.Addr { if req.Email == email.Addr {
app.info.Printf("%s: New user failed: Email already in use", req.Code) app.info.Printf("%s: New user failed: Email already in use", req.Code)
respond(400, "errorEmailLinked", gc) respond(400, "errorEmailLinked", gc)
@ -897,7 +898,7 @@ func (app *appContext) GetUsers(gc *gin.Context) {
if !jfUser.LastActivityDate.IsZero() { if !jfUser.LastActivityDate.IsZero() {
user.LastActive = jfUser.LastActivityDate.Unix() user.LastActive = jfUser.LastActivityDate.Unix()
} }
if email, ok := app.storage.emails[jfUser.ID]; ok { if email, ok := app.storage.GetEmailsKey(jfUser.ID); ok {
user.Email = email.Addr user.Email = email.Addr
user.NotifyThroughEmail = email.Contact user.NotifyThroughEmail = email.Contact
user.Label = email.Label user.Label = email.Label
@ -907,15 +908,15 @@ func (app *appContext) GetUsers(gc *gin.Context) {
if ok { if ok {
user.Expiry = expiry.Unix() user.Expiry = expiry.Unix()
} }
if tgUser, ok := app.storage.telegram[jfUser.ID]; ok { if tgUser, ok := app.storage.GetTelegramKey(jfUser.ID); ok {
user.Telegram = tgUser.Username user.Telegram = tgUser.Username
user.NotifyThroughTelegram = tgUser.Contact user.NotifyThroughTelegram = tgUser.Contact
} }
if mxUser, ok := app.storage.matrix[jfUser.ID]; ok { if mxUser, ok := app.storage.GetMatrixKey(jfUser.ID); ok {
user.Matrix = mxUser.UserID user.Matrix = mxUser.UserID
user.NotifyThroughMatrix = mxUser.Contact user.NotifyThroughMatrix = mxUser.Contact
} }
if dcUser, ok := app.storage.discord[jfUser.ID]; ok { if dcUser, ok := app.storage.GetDiscordKey(jfUser.ID); ok {
user.Discord = RenderDiscordUsername(dcUser) user.Discord = RenderDiscordUsername(dcUser)
// user.Discord = dcUser.Username + "#" + dcUser.Discriminator // user.Discord = dcUser.Username + "#" + dcUser.Discriminator
user.DiscordID = dcUser.ID user.DiscordID = dcUser.ID
@ -949,11 +950,11 @@ func (app *appContext) SetAccountsAdmin(gc *gin.Context) {
id := jfUser.ID id := jfUser.ID
if admin, ok := req[id]; ok { if admin, ok := req[id]; ok {
var emailStore = EmailAddress{} var emailStore = EmailAddress{}
if oldEmail, ok := app.storage.emails[id]; ok { if oldEmail, ok := app.storage.GetEmailsKey(id); ok {
emailStore = oldEmail emailStore = oldEmail
} }
emailStore.Admin = admin emailStore.Admin = admin
app.storage.emails[id] = emailStore app.storage.SetEmailsKey(id, emailStore)
} }
} }
if err := app.storage.storeEmails(); err != nil { if err := app.storage.storeEmails(); err != nil {
@ -986,11 +987,11 @@ func (app *appContext) ModifyLabels(gc *gin.Context) {
id := jfUser.ID id := jfUser.ID
if label, ok := req[id]; ok { if label, ok := req[id]; ok {
var emailStore = EmailAddress{} var emailStore = EmailAddress{}
if oldEmail, ok := app.storage.emails[id]; ok { if oldEmail, ok := app.storage.GetEmailsKey(id); ok {
emailStore = oldEmail emailStore = oldEmail
} }
emailStore.Label = label emailStore.Label = label
app.storage.emails[id] = emailStore app.storage.SetEmailsKey(id, emailStore)
} }
} }
if err := app.storage.storeEmails(); err != nil { if err := app.storage.storeEmails(); err != nil {
@ -1024,7 +1025,7 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
id := jfUser.ID id := jfUser.ID
if address, ok := req[id]; ok { if address, ok := req[id]; ok {
var emailStore = EmailAddress{} var emailStore = EmailAddress{}
oldEmail, ok := app.storage.emails[id] oldEmail, ok := app.storage.GetEmailsKey(id)
if ok { if ok {
emailStore = oldEmail emailStore = oldEmail
} }
@ -1035,7 +1036,7 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
} }
emailStore.Addr = address emailStore.Addr = address
app.storage.emails[id] = emailStore app.storage.SetEmailsKey(id, emailStore)
if ombiEnabled { if ombiEnabled {
ombiUser, code, err := app.getOmbiUser(id) ombiUser, code, err := app.getOmbiUser(id)
if code == 200 && err == nil { if code == 200 && err == nil {

View File

@ -209,7 +209,7 @@ func (app *appContext) getTokenLogin(gc *gin.Context) {
if !app.config.Section("ui").Key("allow_all").MustBool(false) { if !app.config.Section("ui").Key("allow_all").MustBool(false) {
accountsAdmin := false accountsAdmin := false
adminOnly := app.config.Section("ui").Key("admin_only").MustBool(true) adminOnly := app.config.Section("ui").Key("admin_only").MustBool(true)
if emailStore, ok := app.storage.emails[jfID]; ok { if emailStore, ok := app.storage.GetEmailsKey(jfID); ok {
accountsAdmin = emailStore.Admin accountsAdmin = emailStore.Admin
} }
accountsAdmin = accountsAdmin || (adminOnly && user.Policy.IsAdministrator) accountsAdmin = accountsAdmin || (adminOnly && user.Policy.IsAdministrator)

View File

@ -13,14 +13,16 @@ func (app *appContext) clearEmails() {
return return
} }
// Rebuild email storage to from existing users to reduce time complexity // Rebuild email storage to from existing users to reduce time complexity
emails := map[string]EmailAddress{} emails := emailStore{}
app.storage.emailsLock.Lock()
for _, user := range users { for _, user := range users {
if email, ok := app.storage.emails[user.ID]; ok { if email, ok := app.storage.GetEmailsKey(user.ID); ok {
emails[user.ID] = email emails[user.ID] = email
} }
} }
app.storage.emails = emails app.storage.emails = emails
app.storage.storeEmails() app.storage.storeEmails()
app.storage.emailsLock.Unlock()
} }
// clearDiscord does the same as clearEmails, but for Discord Users. // clearDiscord does the same as clearEmails, but for Discord Users.
@ -32,14 +34,16 @@ func (app *appContext) clearDiscord() {
return return
} }
// Rebuild discord storage to from existing users to reduce time complexity // Rebuild discord storage to from existing users to reduce time complexity
dcUsers := map[string]DiscordUser{} dcUsers := discordStore{}
app.storage.discordLock.Lock()
for _, user := range users { for _, user := range users {
if dcUser, ok := app.storage.discord[user.ID]; ok { if dcUser, ok := app.storage.GetDiscordKey(user.ID); ok {
dcUsers[user.ID] = dcUser dcUsers[user.ID] = dcUser
} }
} }
app.storage.discord = dcUsers app.storage.discord = dcUsers
app.storage.storeDiscordUsers() app.storage.storeDiscordUsers()
app.storage.discordLock.Unlock()
} }
// clearMatrix does the same as clearEmails, but for Matrix Users. // clearMatrix does the same as clearEmails, but for Matrix Users.
@ -51,14 +55,16 @@ func (app *appContext) clearMatrix() {
return return
} }
// Rebuild matrix storage to from existing users to reduce time complexity // Rebuild matrix storage to from existing users to reduce time complexity
mxUsers := map[string]MatrixUser{} mxUsers := matrixStore{}
app.storage.matrixLock.Lock()
for _, user := range users { for _, user := range users {
if mxUser, ok := app.storage.matrix[user.ID]; ok { if mxUser, ok := app.storage.GetMatrixKey(user.ID); ok {
mxUsers[user.ID] = mxUser mxUsers[user.ID] = mxUser
} }
} }
app.storage.matrix = mxUsers app.storage.matrix = mxUsers
app.storage.storeMatrixUsers() app.storage.storeMatrixUsers()
app.storage.matrixLock.Unlock()
} }
// clearTelegram does the same as clearEmails, but for Telegram Users. // clearTelegram does the same as clearEmails, but for Telegram Users.
@ -70,14 +76,16 @@ func (app *appContext) clearTelegram() {
return return
} }
// Rebuild telegram storage to from existing users to reduce time complexity // Rebuild telegram storage to from existing users to reduce time complexity
tgUsers := map[string]TelegramUser{} tgUsers := telegramStore{}
app.storage.telegramLock.Lock()
for _, user := range users { for _, user := range users {
if tgUser, ok := app.storage.telegram[user.ID]; ok { if tgUser, ok := app.storage.GetTelegramKey(user.ID); ok {
tgUsers[user.ID] = tgUser tgUsers[user.ID] = tgUser
} }
} }
app.storage.telegram = tgUsers app.storage.telegram = tgUsers
app.storage.storeTelegramUsers() app.storage.storeTelegramUsers()
app.storage.telegramLock.Unlock()
} }
// https://bbengfort.github.io/snippets/2016/06/26/background-work-goroutines-timer.html THANKS // https://bbengfort.github.io/snippets/2016/06/26/background-work-goroutines-timer.html THANKS

View File

@ -48,7 +48,7 @@ func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) {
dd.commandHandlers[app.config.Section("discord").Key("start_command").MustString("start")] = dd.cmdStart dd.commandHandlers[app.config.Section("discord").Key("start_command").MustString("start")] = dd.cmdStart
dd.commandHandlers["lang"] = dd.cmdLang dd.commandHandlers["lang"] = dd.cmdLang
dd.commandHandlers["pin"] = dd.cmdPIN dd.commandHandlers["pin"] = dd.cmdPIN
for _, user := range app.storage.discord { for _, user := range app.storage.GetDiscord() {
dd.users[user.ID] = user dd.users[user.ID] = user
} }
@ -472,14 +472,11 @@ func (d *DiscordDaemon) cmdLang(s *dg.Session, i *dg.InteractionCreate, lang str
code := i.ApplicationCommandData().Options[0].StringValue() code := i.ApplicationCommandData().Options[0].StringValue()
if _, ok := d.app.storage.lang.Telegram[code]; ok { if _, ok := d.app.storage.lang.Telegram[code]; ok {
var user DiscordUser var user DiscordUser
for jfID, u := range d.app.storage.discord { for jfID, u := range d.app.storage.GetDiscord() {
if u.ID == i.Interaction.Member.User.ID { if u.ID == i.Interaction.Member.User.ID {
u.Lang = code u.Lang = code
lang = code lang = code
d.app.storage.discord[jfID] = u d.app.storage.SetDiscordKey(jfID, u)
if err := d.app.storage.storeDiscordUsers(); err != nil {
d.app.err.Printf("Failed to store Discord users: %v", err)
}
user = u user = u
break break
} }
@ -582,13 +579,10 @@ func (d *DiscordDaemon) msgLang(s *dg.Session, m *dg.MessageCreate, sects []stri
} }
if _, ok := d.app.storage.lang.Telegram[sects[1]]; ok { if _, ok := d.app.storage.lang.Telegram[sects[1]]; ok {
var user DiscordUser var user DiscordUser
for jfID, u := range d.app.storage.discord { for jfID, u := range d.app.storage.GetDiscord() {
if u.ID == m.Author.ID { if u.ID == m.Author.ID {
u.Lang = sects[1] u.Lang = sects[1]
d.app.storage.discord[jfID] = u d.app.storage.SetDiscordKey(jfID, u)
if err := d.app.storage.storeDiscordUsers(); err != nil {
d.app.err.Printf("Failed to store Discord users: %v", err)
}
user = u user = u
break break
} }

View File

@ -838,25 +838,25 @@ func (emailer *Emailer) send(email *Message, address ...string) error {
func (app *appContext) sendByID(email *Message, ID ...string) error { func (app *appContext) sendByID(email *Message, ID ...string) error {
for _, id := range ID { for _, id := range ID {
var err error var err error
if tgChat, ok := app.storage.telegram[id]; ok && tgChat.Contact && telegramEnabled { if tgChat, ok := app.storage.GetTelegramKey(id); ok && tgChat.Contact && telegramEnabled {
err = app.telegram.Send(email, tgChat.ChatID) err = app.telegram.Send(email, tgChat.ChatID)
if err != nil { if err != nil {
return err return err
} }
} }
if dcChat, ok := app.storage.discord[id]; ok && dcChat.Contact && discordEnabled { if dcChat, ok := app.storage.GetDiscordKey(id); ok && dcChat.Contact && discordEnabled {
err = app.discord.Send(email, dcChat.ChannelID) err = app.discord.Send(email, dcChat.ChannelID)
if err != nil { if err != nil {
return err return err
} }
} }
if mxChat, ok := app.storage.matrix[id]; ok && mxChat.Contact && matrixEnabled { if mxChat, ok := app.storage.GetMatrixKey(id); ok && mxChat.Contact && matrixEnabled {
err = app.matrix.Send(email, mxChat) err = app.matrix.Send(email, mxChat)
if err != nil { if err != nil {
return err return err
} }
} }
if address, ok := app.storage.emails[id]; ok && address.Contact && emailEnabled { if address, ok := app.storage.GetEmailsKey(id); ok && address.Contact && emailEnabled {
err = app.email.send(email, address.Addr) err = app.email.send(email, address.Addr)
if err != nil { if err != nil {
return err return err
@ -870,13 +870,13 @@ func (app *appContext) sendByID(email *Message, ID ...string) error {
} }
func (app *appContext) getAddressOrName(jfID string) string { func (app *appContext) getAddressOrName(jfID string) string {
if dcChat, ok := app.storage.discord[jfID]; ok && dcChat.Contact && discordEnabled { if dcChat, ok := app.storage.GetDiscordKey(jfID); ok && dcChat.Contact && discordEnabled {
return RenderDiscordUsername(dcChat) return RenderDiscordUsername(dcChat)
} }
if tgChat, ok := app.storage.telegram[jfID]; ok && tgChat.Contact && telegramEnabled { if tgChat, ok := app.storage.GetTelegramKey(jfID); ok && tgChat.Contact && telegramEnabled {
return "@" + tgChat.Username return "@" + tgChat.Username
} }
if addr, ok := app.storage.emails[jfID]; ok { if addr, ok := app.storage.GetEmailsKey(jfID); ok {
return addr.Addr return addr.Addr
} }
return "" return ""

View File

@ -83,7 +83,7 @@ func newMatrixDaemon(app *appContext) (d *MatrixDaemon, err error) {
// return // return
// } // }
// d.bot.Store.SaveFilterID(d.userID, resp.FilterID) // d.bot.Store.SaveFilterID(d.userID, resp.FilterID)
for _, user := range app.storage.matrix { for _, user := range app.storage.GetMatrix() {
if user.Lang != "" { if user.Lang != "" {
d.languages[id.RoomID(user.RoomID)] = user.Lang d.languages[id.RoomID(user.RoomID)] = user.Lang
} }
@ -176,12 +176,9 @@ func (d *MatrixDaemon) commandLang(evt *event.Event, code, lang string) {
return return
} }
d.languages[evt.RoomID] = code d.languages[evt.RoomID] = code
if u, ok := d.app.storage.matrix[string(evt.RoomID)]; ok { if u, ok := d.app.storage.GetMatrixKey(string(evt.RoomID)); ok {
u.Lang = code u.Lang = code
d.app.storage.matrix[string(evt.RoomID)] = u d.app.storage.SetMatrixKey(string(evt.RoomID), u)
if err := d.app.storage.storeMatrixUsers(); err != nil {
d.app.err.Printf("Matrix: Failed to store Matrix users: %v", err)
}
} }
} }

View File

@ -139,7 +139,7 @@ func migrateNotificationMethods(app *appContext) error {
if !strings.Contains(address, "@") { if !strings.Contains(address, "@") {
continue continue
} }
for id, email := range app.storage.emails { for id, email := range app.storage.GetEmails() {
if email.Addr == address { if email.Addr == address {
invite.Notify[id] = notifyPrefs invite.Notify[id] = notifyPrefs
delete(invite.Notify, address) delete(invite.Notify, address)
@ -168,10 +168,10 @@ func linkExistingOmbiDiscordTelegram(app *appContext) error {
return nil return nil
} }
idList := map[string][2]string{} idList := map[string][2]string{}
for jfID, user := range app.storage.discord { for jfID, user := range app.storage.GetDiscord() {
idList[jfID] = [2]string{user.ID, ""} idList[jfID] = [2]string{user.ID, ""}
} }
for jfID, user := range app.storage.telegram { for jfID, user := range app.storage.GetTelegram() {
vals, ok := idList[jfID] vals, ok := idList[jfID]
if !ok { if !ok {
vals = [2]string{"", ""} vals = [2]string{"", ""}
@ -212,7 +212,7 @@ func linkExistingOmbiDiscordTelegram(app *appContext) error {
// app.jf.GetUsers(false) // app.jf.GetUsers(false)
// //
// noHyphens := true // noHyphens := true
// for id := range app.storage.emails { // for id := range app.storage.GetEmails() {
// if strings.Contains(id, "-") { // if strings.Contains(id, "-") {
// noHyphens = false // noHyphens = false
// break // break

366
package-lock.json generated
View File

@ -15,7 +15,7 @@
"any-date-parser": "^1.5.4", "any-date-parser": "^1.5.4",
"browserslist": "^4.21.7", "browserslist": "^4.21.7",
"cheerio": "^1.0.0-rc.12", "cheerio": "^1.0.0-rc.12",
"esbuild": "^0.18.4", "esbuild": "^0.18.5",
"fs-cheerio": "^3.0.0", "fs-cheerio": "^3.0.0",
"inline-source": "^8.0.2", "inline-source": "^8.0.2",
"jsdom": "^22.1.0", "jsdom": "^22.1.0",
@ -57,9 +57,9 @@
} }
}, },
"node_modules/@esbuild/android-arm": { "node_modules/@esbuild/android-arm": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.5.tgz",
"integrity": "sha512-yKmQC9IiuvHdsNEbPHSprnMHg6OhL1cSeQZLzPpgzJBJ9ppEg9GAZN8MKj1TcmB4tZZUrq5xjK7KCmhwZP8iDA==", "integrity": "sha512-+8GXQzuASxGg/rb47Z5zJe3vjOfL7RRce/DILuk6kbB/8HO0p3CPo72CbR349P2K8YP1h5NvNqU+2GDRbNJylw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -72,9 +72,9 @@
} }
}, },
"node_modules/@esbuild/android-arm64": { "node_modules/@esbuild/android-arm64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.5.tgz",
"integrity": "sha512-yQVgO+V307hA2XhzELQ6F91CBGX7gSnlVGAj5YIqjQOxThDpM7fOcHT2YLJbE6gNdPtgRSafQrsK8rJ9xHCaZg==", "integrity": "sha512-410IPUj7ZOxZ2dwK0B7o7Nibu7YEyaLBvYOfYBpuA1TpY0fOkDM5r4bwn+hT8Uma06DBI4RnYNN09fn55PYInQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -87,9 +87,9 @@
} }
}, },
"node_modules/@esbuild/android-x64": { "node_modules/@esbuild/android-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.5.tgz",
"integrity": "sha512-yLKXMxQg6sk1ntftxQ5uwyVgG4/S2E7UoOCc5N4YZW7fdkfRiYEXqm7CMuIfY2Vs3FTrNyKmSfNevIuIvJnMww==", "integrity": "sha512-+fdfceCYwcz9OReheSWYOGaAAt03n0BnG5/UW9tyGyo15PjSOF14ylxfjvz+0atDx0S/RxyezMsH/mbnWhnC8w==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -102,9 +102,9 @@
} }
}, },
"node_modules/@esbuild/darwin-arm64": { "node_modules/@esbuild/darwin-arm64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.5.tgz",
"integrity": "sha512-MVPEoZjZpk2xQ1zckZrb8eQuQib+QCzdmMs3YZAYEQPg+Rztk5pUxGyk8htZOC8Z38NMM29W+MqY9Sqo/sDGKw==", "integrity": "sha512-L7noeTaus5xEtgd5J7u/lGrZfSiYkvZb0gOD7rvKTuuWbdGM4bunz5DUFsWBbEIlloslpOO5PDy4Hnd6mZT20A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -117,9 +117,9 @@
} }
}, },
"node_modules/@esbuild/darwin-x64": { "node_modules/@esbuild/darwin-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.5.tgz",
"integrity": "sha512-uEsRtYRUDsz7i2tXg/t/SyF+5gU1cvi9B6B8i5ebJgtUUHJYWyIPIesmIOL4/+bywjxsDMA/XrNFMgMffLnh5A==", "integrity": "sha512-eA39B8SxbxRdSSILD4AsePzvJiVao6ZaYrcTOJqg89jnnMEGR/EAh+ehV7E4GOx4WXQoWeJRP1P9JQSzIrROeg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -132,9 +132,9 @@
} }
}, },
"node_modules/@esbuild/freebsd-arm64": { "node_modules/@esbuild/freebsd-arm64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.5.tgz",
"integrity": "sha512-I8EOigqWnOHRin6Zp5Y1cfH3oT54bd7Sdz/VnpUNksbOtfp8IWRTH4pgkgO5jWaRQPjCpJcOpdRjYAMjPt8wXg==", "integrity": "sha512-Eg1UnkTZHfsphgcy1Wj/McNModSO/F+kqtWqvtvEZc9BAgvdwxAt11BESgBczU+Gti0G2dLvHs0Sfb3gavwhGg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -147,9 +147,9 @@
} }
}, },
"node_modules/@esbuild/freebsd-x64": { "node_modules/@esbuild/freebsd-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.5.tgz",
"integrity": "sha512-1bHfgMz/cNMjbpsYxjVgMJ1iwKq+NdDPlACBrWULD7ZdFmBQrhMicMaKb5CdmdVyvIwXmasOuF4r6Iq574kUTA==", "integrity": "sha512-GNTMSJ55gl7Tf5VUqVRkMJhRGzH6vI9vFBfZCj4Zjm7RgfXCWxLnTyjMgZZKT8pOzW40KD2KlrGbqwnnJWyGWw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -162,9 +162,9 @@
} }
}, },
"node_modules/@esbuild/linux-arm": { "node_modules/@esbuild/linux-arm": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.5.tgz",
"integrity": "sha512-4XCGqM/Ay1LCXUBH59bL4JbSbbTK1K22dWHymWMGaEh2sQCDOUw+OQxozYV/YdBb91leK2NbuSrE2BRamwgaYw==", "integrity": "sha512-6R+vEIyfEvp+gOWKSc+m6hdnhWKQYzicqONQYiDGT6qepc6OGsLEZcyFwoz6BvFx5j233CBWMcJ69eXFrwXw9A==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@ -177,9 +177,9 @@
} }
}, },
"node_modules/@esbuild/linux-arm64": { "node_modules/@esbuild/linux-arm64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.5.tgz",
"integrity": "sha512-J42vLHaYREyiBwH0eQE4/7H1DTfZx8FuxyWSictx4d7ezzuKE3XOkIvOg+SQzRz7T9HLVKzq2tvbAov4UfufBw==", "integrity": "sha512-r08LmhqyPRj6FtuNPBTu8BliKh6h+oNEhMkWmmR/aWs4DWjDOivyDfLGznPdgtSThL23fk1QgSBUEbuCIzjA2A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -192,9 +192,9 @@
} }
}, },
"node_modules/@esbuild/linux-ia32": { "node_modules/@esbuild/linux-ia32": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.5.tgz",
"integrity": "sha512-4ksIqFwhq7OExty7Sl1n0vqQSCqTG4sU6i99G2yuMr28CEOUZ/60N+IO9hwI8sIxBqmKmDgncE1n5CMu/3m0IA==", "integrity": "sha512-ph6M9iEMc6BHgv2XuIE8qeQrQCH+2l116c8L9ysmmXYwpNXa3E7JNIu/O7hI0I9qDvh1P19AGbIh+/y0GAZijA==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -207,9 +207,9 @@
} }
}, },
"node_modules/@esbuild/linux-loong64": { "node_modules/@esbuild/linux-loong64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.5.tgz",
"integrity": "sha512-bsWtoVHkGQgAsFXioDueXRiUIfSGrVkJjBBz4gcBJxXcD461cWFQFyu8Fxdj9TP+zEeqJ8C/O4LFFMBNi6Fscw==", "integrity": "sha512-s6Nup5FMQ8R8OKJG2rSxtV40s8LRdfC73XGHGaFlGiC+2SeCyq4dl3MMfLdzLowYzyDjfc4GRrXWUNMX3kNxYA==",
"cpu": [ "cpu": [
"loong64" "loong64"
], ],
@ -222,9 +222,9 @@
} }
}, },
"node_modules/@esbuild/linux-mips64el": { "node_modules/@esbuild/linux-mips64el": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.5.tgz",
"integrity": "sha512-LRD9Fu8wJQgIOOV1o3nRyzrheFYjxA0C1IVWZ93eNRRWBKgarYFejd5WBtrp43cE4y4D4t3qWWyklm73Mrsd/g==", "integrity": "sha512-DxW4nNDIGbivZxnJD01C5PlwKPpin8YgSwWtToCy4w4lNigT7Iaf5A+wcPT2laibdgbcgPKpPOXUg6RFGTt8xA==",
"cpu": [ "cpu": [
"mips64el" "mips64el"
], ],
@ -237,9 +237,9 @@
} }
}, },
"node_modules/@esbuild/linux-ppc64": { "node_modules/@esbuild/linux-ppc64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.5.tgz",
"integrity": "sha512-jtQgoZjM92gauVRxNaaG/TpL3Pr4WcL3Pwqi9QgdrBGrEXzB+twohQiWNSTycs6lUygakos4mm2h0B9/SHveng==", "integrity": "sha512-BksOs2uYTafS+u75QiN4RoLbEMNjE192adJCBalncI3E2PWyR2i1kEs9rEghHK7pw0SD0uWgV9otRmV7G5b2lQ==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@ -252,9 +252,9 @@
} }
}, },
"node_modules/@esbuild/linux-riscv64": { "node_modules/@esbuild/linux-riscv64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.5.tgz",
"integrity": "sha512-7WaU/kRZG0VCV09Xdlkg6LNAsfU9SAxo6XEdaZ8ffO4lh+DZoAhGTx7+vTMOXKxa+r2w1LYDGxfJa2rcgagMRA==", "integrity": "sha512-mGv8BOJXsV7bZyjyMdeDs55CDXZ5vrY3oKa58DNRz2vPn54dREyj4BhhyWuqSuzSURJhFg7pM/1fI2vnAHGkHw==",
"cpu": [ "cpu": [
"riscv64" "riscv64"
], ],
@ -267,9 +267,9 @@
} }
}, },
"node_modules/@esbuild/linux-s390x": { "node_modules/@esbuild/linux-s390x": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.5.tgz",
"integrity": "sha512-D19ed0xreKQvC5t+ArE2njSnm18WPpE+1fhwaiJHf+Xwqsq+/SUaV8Mx0M27nszdU+Atq1HahrgCOZCNNEASUg==", "integrity": "sha512-m4uIYyrl5znGnNHgiM/Zsw6I9Se513NqdTxeUxZ66/VDWbuUp8ACe1KOSpwF4NNxfYy6Q3W8beZsIdF4F85q8Q==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@ -282,9 +282,9 @@
} }
}, },
"node_modules/@esbuild/linux-x64": { "node_modules/@esbuild/linux-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.5.tgz",
"integrity": "sha512-Rx3AY1sxyiO/gvCGP00nL69L60dfmWyjKWY06ugpB8Ydpdsfi3BHW58HWC24K3CAjAPSwxcajozC2PzA9JBS1g==", "integrity": "sha512-R1C7X30YjXmOZYOzx4dJ/QvRNfrkK/sDCFfcGNhlHFX6B/iodJdk81h7EhnKVUQy+3BaARxF7udd91iSSzMlbQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -297,9 +297,9 @@
} }
}, },
"node_modules/@esbuild/netbsd-x64": { "node_modules/@esbuild/netbsd-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.5.tgz",
"integrity": "sha512-AaShPmN9c6w1mKRpliKFlaWcSkpBT4KOlk93UfFgeI3F3cbjzdDKGsbKnOZozmYbE1izZKLmNJiW0sFM+A5JPA==", "integrity": "sha512-MABnKzjMcXjO0NEYyexOhqjcrgM6dE8BXnm+lctm2x2aPpYg5iL0Ew3aABSTZyp9dS3Z4VzFu5PPoOYEw8akTQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -312,9 +312,9 @@
} }
}, },
"node_modules/@esbuild/openbsd-x64": { "node_modules/@esbuild/openbsd-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.5.tgz",
"integrity": "sha512-tRGvGwou3BrvHVvF8HxTqEiC5VtPzySudS9fh2jBIKpLX7HCW8jIkW+LunkFDNwhslx4xMAgh0jAHsx/iCymaQ==", "integrity": "sha512-aU7R0tLIUMaQuAgBjKrq02Z98rcY9Pxk76hynSqcGeld2C/ro1uBbS2i9rh7vdwBAY0rG08Og4wnDnlx5rU+fQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -327,9 +327,9 @@
} }
}, },
"node_modules/@esbuild/sunos-x64": { "node_modules/@esbuild/sunos-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.5.tgz",
"integrity": "sha512-acORFDI95GKhmAnlH8EarBeuqoy/j3yxIU+FDB91H3+ZON+8HhTadtT450YkaMzX6lEWbhi+mjVUCj00M5yyOQ==", "integrity": "sha512-ngm3fVv2VxufI8zH/Phk0mYkgvFjFGnS+l7uxxd20mmeLTNI/8OXDJpNqTUbvzJh3tqhI/Gof0N2+5xJbqEaxA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -342,9 +342,9 @@
} }
}, },
"node_modules/@esbuild/win32-arm64": { "node_modules/@esbuild/win32-arm64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.5.tgz",
"integrity": "sha512-1NxP+iOk8KSvS1L9SSxEvBAJk39U0GiGZkiiJGbuDF9G4fG7DSDw6XLxZMecAgmvQrwwx7yVKdNN3GgNh0UfKg==", "integrity": "sha512-XqpS89+MGLzR8YtQQkBYsLCfAv1ySflMb+FEH99rOp6kOPv/ORO+ujEB5ICDBZZbvYqB75uFrNELo1BVEQbS3g==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -357,9 +357,9 @@
} }
}, },
"node_modules/@esbuild/win32-ia32": { "node_modules/@esbuild/win32-ia32": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.5.tgz",
"integrity": "sha512-OKr8jze93vbgqZ/r23woWciTixUwLa976C9W7yNBujtnVHyvsL/ocYG61tsktUfJOpyIz5TsohkBZ6Lo2+PCcQ==", "integrity": "sha512-V3xj/nb9uie0I4mn1f8nPZSgHldtNJrqTKYjTyMPMBnHbMYF5Loz8ZHsp7+La8kI6NxIF1ClQ9XBV+G3RtSkww==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -372,9 +372,9 @@
} }
}, },
"node_modules/@esbuild/win32-x64": { "node_modules/@esbuild/win32-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.5.tgz",
"integrity": "sha512-qJr3wVvcLjPFcV4AMDS3iquhBfTef2zo/jlm8RMxmiRp3Vy2HY8WMxrykJlcbCnqLXZPA0YZxZGND6eug85ogg==", "integrity": "sha512-gMxWvQeTQWDpa8ExPP41al+Ho7HyK24h7y41JdGKqE24KzXXQPxESUtrCoIES+HwF+OGq2smtibU9UvZ8WH3JQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1647,9 +1647,9 @@
} }
}, },
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.4.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.5.tgz",
"integrity": "sha512-9rxWV/Cb2DMUXfe9aUsYtqg0KTlw146ElFH22kYeK9KVV1qT082X4lpmiKsa12ePiCcIcB686TQJxaGAa9TFvA==", "integrity": "sha512-ztF1Z53Mc8ijEo1ZWFduHZXIqRWufo76JHm1ikvhGjIzO1mj84LdKXSGmRzahfgvWSwky48MkT+o5yUIkQtDPA==",
"hasInstallScript": true, "hasInstallScript": true,
"bin": { "bin": {
"esbuild": "bin/esbuild" "esbuild": "bin/esbuild"
@ -1658,28 +1658,28 @@
"node": ">=12" "node": ">=12"
}, },
"optionalDependencies": { "optionalDependencies": {
"@esbuild/android-arm": "0.18.4", "@esbuild/android-arm": "0.18.5",
"@esbuild/android-arm64": "0.18.4", "@esbuild/android-arm64": "0.18.5",
"@esbuild/android-x64": "0.18.4", "@esbuild/android-x64": "0.18.5",
"@esbuild/darwin-arm64": "0.18.4", "@esbuild/darwin-arm64": "0.18.5",
"@esbuild/darwin-x64": "0.18.4", "@esbuild/darwin-x64": "0.18.5",
"@esbuild/freebsd-arm64": "0.18.4", "@esbuild/freebsd-arm64": "0.18.5",
"@esbuild/freebsd-x64": "0.18.4", "@esbuild/freebsd-x64": "0.18.5",
"@esbuild/linux-arm": "0.18.4", "@esbuild/linux-arm": "0.18.5",
"@esbuild/linux-arm64": "0.18.4", "@esbuild/linux-arm64": "0.18.5",
"@esbuild/linux-ia32": "0.18.4", "@esbuild/linux-ia32": "0.18.5",
"@esbuild/linux-loong64": "0.18.4", "@esbuild/linux-loong64": "0.18.5",
"@esbuild/linux-mips64el": "0.18.4", "@esbuild/linux-mips64el": "0.18.5",
"@esbuild/linux-ppc64": "0.18.4", "@esbuild/linux-ppc64": "0.18.5",
"@esbuild/linux-riscv64": "0.18.4", "@esbuild/linux-riscv64": "0.18.5",
"@esbuild/linux-s390x": "0.18.4", "@esbuild/linux-s390x": "0.18.5",
"@esbuild/linux-x64": "0.18.4", "@esbuild/linux-x64": "0.18.5",
"@esbuild/netbsd-x64": "0.18.4", "@esbuild/netbsd-x64": "0.18.5",
"@esbuild/openbsd-x64": "0.18.4", "@esbuild/openbsd-x64": "0.18.5",
"@esbuild/sunos-x64": "0.18.4", "@esbuild/sunos-x64": "0.18.5",
"@esbuild/win32-arm64": "0.18.4", "@esbuild/win32-arm64": "0.18.5",
"@esbuild/win32-ia32": "0.18.4", "@esbuild/win32-ia32": "0.18.5",
"@esbuild/win32-x64": "0.18.4" "@esbuild/win32-x64": "0.18.5"
} }
}, },
"node_modules/escalade": { "node_modules/escalade": {
@ -6797,135 +6797,135 @@
} }
}, },
"@esbuild/android-arm": { "@esbuild/android-arm": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.5.tgz",
"integrity": "sha512-yKmQC9IiuvHdsNEbPHSprnMHg6OhL1cSeQZLzPpgzJBJ9ppEg9GAZN8MKj1TcmB4tZZUrq5xjK7KCmhwZP8iDA==", "integrity": "sha512-+8GXQzuASxGg/rb47Z5zJe3vjOfL7RRce/DILuk6kbB/8HO0p3CPo72CbR349P2K8YP1h5NvNqU+2GDRbNJylw==",
"optional": true "optional": true
}, },
"@esbuild/android-arm64": { "@esbuild/android-arm64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.5.tgz",
"integrity": "sha512-yQVgO+V307hA2XhzELQ6F91CBGX7gSnlVGAj5YIqjQOxThDpM7fOcHT2YLJbE6gNdPtgRSafQrsK8rJ9xHCaZg==", "integrity": "sha512-410IPUj7ZOxZ2dwK0B7o7Nibu7YEyaLBvYOfYBpuA1TpY0fOkDM5r4bwn+hT8Uma06DBI4RnYNN09fn55PYInQ==",
"optional": true "optional": true
}, },
"@esbuild/android-x64": { "@esbuild/android-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.5.tgz",
"integrity": "sha512-yLKXMxQg6sk1ntftxQ5uwyVgG4/S2E7UoOCc5N4YZW7fdkfRiYEXqm7CMuIfY2Vs3FTrNyKmSfNevIuIvJnMww==", "integrity": "sha512-+fdfceCYwcz9OReheSWYOGaAAt03n0BnG5/UW9tyGyo15PjSOF14ylxfjvz+0atDx0S/RxyezMsH/mbnWhnC8w==",
"optional": true "optional": true
}, },
"@esbuild/darwin-arm64": { "@esbuild/darwin-arm64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.5.tgz",
"integrity": "sha512-MVPEoZjZpk2xQ1zckZrb8eQuQib+QCzdmMs3YZAYEQPg+Rztk5pUxGyk8htZOC8Z38NMM29W+MqY9Sqo/sDGKw==", "integrity": "sha512-L7noeTaus5xEtgd5J7u/lGrZfSiYkvZb0gOD7rvKTuuWbdGM4bunz5DUFsWBbEIlloslpOO5PDy4Hnd6mZT20A==",
"optional": true "optional": true
}, },
"@esbuild/darwin-x64": { "@esbuild/darwin-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.5.tgz",
"integrity": "sha512-uEsRtYRUDsz7i2tXg/t/SyF+5gU1cvi9B6B8i5ebJgtUUHJYWyIPIesmIOL4/+bywjxsDMA/XrNFMgMffLnh5A==", "integrity": "sha512-eA39B8SxbxRdSSILD4AsePzvJiVao6ZaYrcTOJqg89jnnMEGR/EAh+ehV7E4GOx4WXQoWeJRP1P9JQSzIrROeg==",
"optional": true "optional": true
}, },
"@esbuild/freebsd-arm64": { "@esbuild/freebsd-arm64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.5.tgz",
"integrity": "sha512-I8EOigqWnOHRin6Zp5Y1cfH3oT54bd7Sdz/VnpUNksbOtfp8IWRTH4pgkgO5jWaRQPjCpJcOpdRjYAMjPt8wXg==", "integrity": "sha512-Eg1UnkTZHfsphgcy1Wj/McNModSO/F+kqtWqvtvEZc9BAgvdwxAt11BESgBczU+Gti0G2dLvHs0Sfb3gavwhGg==",
"optional": true "optional": true
}, },
"@esbuild/freebsd-x64": { "@esbuild/freebsd-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.5.tgz",
"integrity": "sha512-1bHfgMz/cNMjbpsYxjVgMJ1iwKq+NdDPlACBrWULD7ZdFmBQrhMicMaKb5CdmdVyvIwXmasOuF4r6Iq574kUTA==", "integrity": "sha512-GNTMSJ55gl7Tf5VUqVRkMJhRGzH6vI9vFBfZCj4Zjm7RgfXCWxLnTyjMgZZKT8pOzW40KD2KlrGbqwnnJWyGWw==",
"optional": true "optional": true
}, },
"@esbuild/linux-arm": { "@esbuild/linux-arm": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.5.tgz",
"integrity": "sha512-4XCGqM/Ay1LCXUBH59bL4JbSbbTK1K22dWHymWMGaEh2sQCDOUw+OQxozYV/YdBb91leK2NbuSrE2BRamwgaYw==", "integrity": "sha512-6R+vEIyfEvp+gOWKSc+m6hdnhWKQYzicqONQYiDGT6qepc6OGsLEZcyFwoz6BvFx5j233CBWMcJ69eXFrwXw9A==",
"optional": true "optional": true
}, },
"@esbuild/linux-arm64": { "@esbuild/linux-arm64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.5.tgz",
"integrity": "sha512-J42vLHaYREyiBwH0eQE4/7H1DTfZx8FuxyWSictx4d7ezzuKE3XOkIvOg+SQzRz7T9HLVKzq2tvbAov4UfufBw==", "integrity": "sha512-r08LmhqyPRj6FtuNPBTu8BliKh6h+oNEhMkWmmR/aWs4DWjDOivyDfLGznPdgtSThL23fk1QgSBUEbuCIzjA2A==",
"optional": true "optional": true
}, },
"@esbuild/linux-ia32": { "@esbuild/linux-ia32": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.5.tgz",
"integrity": "sha512-4ksIqFwhq7OExty7Sl1n0vqQSCqTG4sU6i99G2yuMr28CEOUZ/60N+IO9hwI8sIxBqmKmDgncE1n5CMu/3m0IA==", "integrity": "sha512-ph6M9iEMc6BHgv2XuIE8qeQrQCH+2l116c8L9ysmmXYwpNXa3E7JNIu/O7hI0I9qDvh1P19AGbIh+/y0GAZijA==",
"optional": true "optional": true
}, },
"@esbuild/linux-loong64": { "@esbuild/linux-loong64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.5.tgz",
"integrity": "sha512-bsWtoVHkGQgAsFXioDueXRiUIfSGrVkJjBBz4gcBJxXcD461cWFQFyu8Fxdj9TP+zEeqJ8C/O4LFFMBNi6Fscw==", "integrity": "sha512-s6Nup5FMQ8R8OKJG2rSxtV40s8LRdfC73XGHGaFlGiC+2SeCyq4dl3MMfLdzLowYzyDjfc4GRrXWUNMX3kNxYA==",
"optional": true "optional": true
}, },
"@esbuild/linux-mips64el": { "@esbuild/linux-mips64el": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.5.tgz",
"integrity": "sha512-LRD9Fu8wJQgIOOV1o3nRyzrheFYjxA0C1IVWZ93eNRRWBKgarYFejd5WBtrp43cE4y4D4t3qWWyklm73Mrsd/g==", "integrity": "sha512-DxW4nNDIGbivZxnJD01C5PlwKPpin8YgSwWtToCy4w4lNigT7Iaf5A+wcPT2laibdgbcgPKpPOXUg6RFGTt8xA==",
"optional": true "optional": true
}, },
"@esbuild/linux-ppc64": { "@esbuild/linux-ppc64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.5.tgz",
"integrity": "sha512-jtQgoZjM92gauVRxNaaG/TpL3Pr4WcL3Pwqi9QgdrBGrEXzB+twohQiWNSTycs6lUygakos4mm2h0B9/SHveng==", "integrity": "sha512-BksOs2uYTafS+u75QiN4RoLbEMNjE192adJCBalncI3E2PWyR2i1kEs9rEghHK7pw0SD0uWgV9otRmV7G5b2lQ==",
"optional": true "optional": true
}, },
"@esbuild/linux-riscv64": { "@esbuild/linux-riscv64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.5.tgz",
"integrity": "sha512-7WaU/kRZG0VCV09Xdlkg6LNAsfU9SAxo6XEdaZ8ffO4lh+DZoAhGTx7+vTMOXKxa+r2w1LYDGxfJa2rcgagMRA==", "integrity": "sha512-mGv8BOJXsV7bZyjyMdeDs55CDXZ5vrY3oKa58DNRz2vPn54dREyj4BhhyWuqSuzSURJhFg7pM/1fI2vnAHGkHw==",
"optional": true "optional": true
}, },
"@esbuild/linux-s390x": { "@esbuild/linux-s390x": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.5.tgz",
"integrity": "sha512-D19ed0xreKQvC5t+ArE2njSnm18WPpE+1fhwaiJHf+Xwqsq+/SUaV8Mx0M27nszdU+Atq1HahrgCOZCNNEASUg==", "integrity": "sha512-m4uIYyrl5znGnNHgiM/Zsw6I9Se513NqdTxeUxZ66/VDWbuUp8ACe1KOSpwF4NNxfYy6Q3W8beZsIdF4F85q8Q==",
"optional": true "optional": true
}, },
"@esbuild/linux-x64": { "@esbuild/linux-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.5.tgz",
"integrity": "sha512-Rx3AY1sxyiO/gvCGP00nL69L60dfmWyjKWY06ugpB8Ydpdsfi3BHW58HWC24K3CAjAPSwxcajozC2PzA9JBS1g==", "integrity": "sha512-R1C7X30YjXmOZYOzx4dJ/QvRNfrkK/sDCFfcGNhlHFX6B/iodJdk81h7EhnKVUQy+3BaARxF7udd91iSSzMlbQ==",
"optional": true "optional": true
}, },
"@esbuild/netbsd-x64": { "@esbuild/netbsd-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.5.tgz",
"integrity": "sha512-AaShPmN9c6w1mKRpliKFlaWcSkpBT4KOlk93UfFgeI3F3cbjzdDKGsbKnOZozmYbE1izZKLmNJiW0sFM+A5JPA==", "integrity": "sha512-MABnKzjMcXjO0NEYyexOhqjcrgM6dE8BXnm+lctm2x2aPpYg5iL0Ew3aABSTZyp9dS3Z4VzFu5PPoOYEw8akTQ==",
"optional": true "optional": true
}, },
"@esbuild/openbsd-x64": { "@esbuild/openbsd-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.5.tgz",
"integrity": "sha512-tRGvGwou3BrvHVvF8HxTqEiC5VtPzySudS9fh2jBIKpLX7HCW8jIkW+LunkFDNwhslx4xMAgh0jAHsx/iCymaQ==", "integrity": "sha512-aU7R0tLIUMaQuAgBjKrq02Z98rcY9Pxk76hynSqcGeld2C/ro1uBbS2i9rh7vdwBAY0rG08Og4wnDnlx5rU+fQ==",
"optional": true "optional": true
}, },
"@esbuild/sunos-x64": { "@esbuild/sunos-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.5.tgz",
"integrity": "sha512-acORFDI95GKhmAnlH8EarBeuqoy/j3yxIU+FDB91H3+ZON+8HhTadtT450YkaMzX6lEWbhi+mjVUCj00M5yyOQ==", "integrity": "sha512-ngm3fVv2VxufI8zH/Phk0mYkgvFjFGnS+l7uxxd20mmeLTNI/8OXDJpNqTUbvzJh3tqhI/Gof0N2+5xJbqEaxA==",
"optional": true "optional": true
}, },
"@esbuild/win32-arm64": { "@esbuild/win32-arm64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.5.tgz",
"integrity": "sha512-1NxP+iOk8KSvS1L9SSxEvBAJk39U0GiGZkiiJGbuDF9G4fG7DSDw6XLxZMecAgmvQrwwx7yVKdNN3GgNh0UfKg==", "integrity": "sha512-XqpS89+MGLzR8YtQQkBYsLCfAv1ySflMb+FEH99rOp6kOPv/ORO+ujEB5ICDBZZbvYqB75uFrNELo1BVEQbS3g==",
"optional": true "optional": true
}, },
"@esbuild/win32-ia32": { "@esbuild/win32-ia32": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.5.tgz",
"integrity": "sha512-OKr8jze93vbgqZ/r23woWciTixUwLa976C9W7yNBujtnVHyvsL/ocYG61tsktUfJOpyIz5TsohkBZ6Lo2+PCcQ==", "integrity": "sha512-V3xj/nb9uie0I4mn1f8nPZSgHldtNJrqTKYjTyMPMBnHbMYF5Loz8ZHsp7+La8kI6NxIF1ClQ9XBV+G3RtSkww==",
"optional": true "optional": true
}, },
"@esbuild/win32-x64": { "@esbuild/win32-x64": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.4.tgz", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.5.tgz",
"integrity": "sha512-qJr3wVvcLjPFcV4AMDS3iquhBfTef2zo/jlm8RMxmiRp3Vy2HY8WMxrykJlcbCnqLXZPA0YZxZGND6eug85ogg==", "integrity": "sha512-gMxWvQeTQWDpa8ExPP41al+Ho7HyK24h7y41JdGKqE24KzXXQPxESUtrCoIES+HwF+OGq2smtibU9UvZ8WH3JQ==",
"optional": true "optional": true
}, },
"@jridgewell/gen-mapping": { "@jridgewell/gen-mapping": {
@ -7896,32 +7896,32 @@
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
}, },
"esbuild": { "esbuild": {
"version": "0.18.4", "version": "0.18.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.4.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.5.tgz",
"integrity": "sha512-9rxWV/Cb2DMUXfe9aUsYtqg0KTlw146ElFH22kYeK9KVV1qT082X4lpmiKsa12ePiCcIcB686TQJxaGAa9TFvA==", "integrity": "sha512-ztF1Z53Mc8ijEo1ZWFduHZXIqRWufo76JHm1ikvhGjIzO1mj84LdKXSGmRzahfgvWSwky48MkT+o5yUIkQtDPA==",
"requires": { "requires": {
"@esbuild/android-arm": "0.18.4", "@esbuild/android-arm": "0.18.5",
"@esbuild/android-arm64": "0.18.4", "@esbuild/android-arm64": "0.18.5",
"@esbuild/android-x64": "0.18.4", "@esbuild/android-x64": "0.18.5",
"@esbuild/darwin-arm64": "0.18.4", "@esbuild/darwin-arm64": "0.18.5",
"@esbuild/darwin-x64": "0.18.4", "@esbuild/darwin-x64": "0.18.5",
"@esbuild/freebsd-arm64": "0.18.4", "@esbuild/freebsd-arm64": "0.18.5",
"@esbuild/freebsd-x64": "0.18.4", "@esbuild/freebsd-x64": "0.18.5",
"@esbuild/linux-arm": "0.18.4", "@esbuild/linux-arm": "0.18.5",
"@esbuild/linux-arm64": "0.18.4", "@esbuild/linux-arm64": "0.18.5",
"@esbuild/linux-ia32": "0.18.4", "@esbuild/linux-ia32": "0.18.5",
"@esbuild/linux-loong64": "0.18.4", "@esbuild/linux-loong64": "0.18.5",
"@esbuild/linux-mips64el": "0.18.4", "@esbuild/linux-mips64el": "0.18.5",
"@esbuild/linux-ppc64": "0.18.4", "@esbuild/linux-ppc64": "0.18.5",
"@esbuild/linux-riscv64": "0.18.4", "@esbuild/linux-riscv64": "0.18.5",
"@esbuild/linux-s390x": "0.18.4", "@esbuild/linux-s390x": "0.18.5",
"@esbuild/linux-x64": "0.18.4", "@esbuild/linux-x64": "0.18.5",
"@esbuild/netbsd-x64": "0.18.4", "@esbuild/netbsd-x64": "0.18.5",
"@esbuild/openbsd-x64": "0.18.4", "@esbuild/openbsd-x64": "0.18.5",
"@esbuild/sunos-x64": "0.18.4", "@esbuild/sunos-x64": "0.18.5",
"@esbuild/win32-arm64": "0.18.4", "@esbuild/win32-arm64": "0.18.5",
"@esbuild/win32-ia32": "0.18.4", "@esbuild/win32-ia32": "0.18.5",
"@esbuild/win32-x64": "0.18.4" "@esbuild/win32-x64": "0.18.5"
} }
}, },
"escalade": { "escalade": {

View File

@ -23,7 +23,7 @@
"any-date-parser": "^1.5.4", "any-date-parser": "^1.5.4",
"browserslist": "^4.21.7", "browserslist": "^4.21.7",
"cheerio": "^1.0.0-rc.12", "cheerio": "^1.0.0-rc.12",
"esbuild": "^0.18.4", "esbuild": "^0.18.5",
"fs-cheerio": "^3.0.0", "fs-cheerio": "^3.0.0",
"inline-source": "^8.0.2", "inline-source": "^8.0.2",
"jsdom": "^22.1.0", "jsdom": "^22.1.0",

View File

@ -15,6 +15,11 @@ import (
"github.com/steambap/captcha" "github.com/steambap/captcha"
) )
type discordStore map[string]DiscordUser
type telegramStore map[string]TelegramUser
type matrixStore map[string]MatrixUser
type emailStore map[string]EmailAddress
type Storage struct { type Storage struct {
timePattern string timePattern string
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 string 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 string
@ -23,16 +28,120 @@ type Storage struct {
profiles map[string]Profile profiles map[string]Profile
defaultProfile string defaultProfile string
displayprefs, ombi_template map[string]interface{} displayprefs, ombi_template map[string]interface{}
emails map[string]EmailAddress emails emailStore
telegram map[string]TelegramUser // Map of Jellyfin User IDs to telegram users. telegram telegramStore // Map of Jellyfin User IDs to telegram users.
discord map[string]DiscordUser // Map of Jellyfin user IDs to discord users. discord discordStore // Map of Jellyfin user IDs to discord users.
matrix map[string]MatrixUser // Map of Jellyfin user IDs to Matrix users. matrix matrixStore // Map of Jellyfin user IDs to Matrix users.
customEmails customEmails customEmails customEmails
policy mediabrowser.Policy policy mediabrowser.Policy
configuration mediabrowser.Configuration configuration mediabrowser.Configuration
lang Lang lang Lang
announcements map[string]announcementTemplate announcements map[string]announcementTemplate
invitesLock, usersLock sync.Mutex invitesLock, usersLock, discordLock, telegramLock, matrixLock, emailsLock sync.Mutex
}
// GetEmails returns a copy of the store.
func (st *Storage) GetEmails() emailStore {
return st.emails
}
// GetEmailsKey returns the value stored in the store's key.
func (st *Storage) GetEmailsKey(k string) (EmailAddress, bool) {
v, ok := st.emails[k]
return v, ok
}
// SetEmailsKey stores value v in key k.
func (st *Storage) SetEmailsKey(k string, v EmailAddress) {
st.emailsLock.Lock()
st.emails[k] = v
st.storeEmails()
st.emailsLock.Unlock()
}
// DeleteEmailKey deletes value at key k.
func (st *Storage) DeleteEmailsKey(k string) {
st.emailsLock.Lock()
delete(st.emails, k)
st.emailsLock.Unlock()
}
// GetDiscord returns a copy of the store.
func (st *Storage) GetDiscord() discordStore {
return st.discord
}
// GetDiscordKey returns the value stored in the store's key.
func (st *Storage) GetDiscordKey(k string) (DiscordUser, bool) {
v, ok := st.discord[k]
return v, ok
}
// SetDiscordKey stores value v in key k.
func (st *Storage) SetDiscordKey(k string, v DiscordUser) {
st.discordLock.Lock()
st.discord[k] = v
st.storeDiscordUsers()
st.discordLock.Unlock()
}
// DeleteDiscordKey deletes value at key k.
func (st *Storage) DeleteDiscordKey(k string) {
st.discordLock.Lock()
delete(st.discord, k)
st.discordLock.Unlock()
}
// GetTelegram returns a copy of the store.
func (st *Storage) GetTelegram() telegramStore {
return st.telegram
}
// GetTelegramKey returns the value stored in the store's key.
func (st *Storage) GetTelegramKey(k string) (TelegramUser, bool) {
v, ok := st.telegram[k]
return v, ok
}
// SetTelegramKey stores value v in key k.
func (st *Storage) SetTelegramKey(k string, v TelegramUser) {
st.telegramLock.Lock()
st.telegram[k] = v
st.storeTelegramUsers()
st.telegramLock.Unlock()
}
// DeleteTelegramKey deletes value at key k.
func (st *Storage) DeleteTelegramKey(k string) {
st.telegramLock.Lock()
delete(st.telegram, k)
st.telegramLock.Unlock()
}
// GetMatrix returns a copy of the store.
func (st *Storage) GetMatrix() matrixStore {
return st.matrix
}
// GetMatrixKey returns the value stored in the store's key.
func (st *Storage) GetMatrixKey(k string) (MatrixUser, bool) {
v, ok := st.matrix[k]
return v, ok
}
// SetMatrixKey stores value v in key k.
func (st *Storage) SetMatrixKey(k string, v MatrixUser) {
st.matrixLock.Lock()
st.matrix[k] = v
st.storeMatrixUsers()
st.matrixLock.Unlock()
}
// DeleteMatrixKey deletes value at key k.
func (st *Storage) DeleteMatrixKey(k string) {
st.matrixLock.Lock()
delete(st.matrix, k)
st.matrixLock.Unlock()
} }
type TelegramUser struct { type TelegramUser struct {

View File

@ -46,7 +46,7 @@ func newTelegramDaemon(app *appContext) (*TelegramDaemon, error) {
link: "https://t.me/" + bot.Self.UserName, link: "https://t.me/" + bot.Self.UserName,
app: app, app: app,
} }
for _, user := range app.storage.telegram { for _, user := range app.storage.GetTelegram() {
if user.Lang != "" { if user.Lang != "" {
td.languages[user.ChatID] = user.Lang td.languages[user.ChatID] = user.Lang
} }
@ -198,10 +198,10 @@ func (t *TelegramDaemon) commandLang(upd *tg.Update, sects []string, lang string
} }
if _, ok := t.app.storage.lang.Telegram[sects[1]]; ok { if _, ok := t.app.storage.lang.Telegram[sects[1]]; ok {
t.languages[upd.Message.Chat.ID] = sects[1] t.languages[upd.Message.Chat.ID] = sects[1]
for jfID, user := range t.app.storage.telegram { for jfID, user := range t.app.storage.GetTelegram() {
if user.ChatID == upd.Message.Chat.ID { if user.ChatID == upd.Message.Chat.ID {
user.Lang = sects[1] user.Lang = sects[1]
t.app.storage.telegram[jfID] = user t.app.storage.SetTelegramKey(jfID, user)
if err := t.app.storage.storeTelegramUsers(); err != nil { if err := t.app.storage.storeTelegramUsers(); err != nil {
t.app.err.Printf("Failed to store Telegram users: %v", err) t.app.err.Printf("Failed to store Telegram users: %v", err)
} }