mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-29 12:30:11 +00:00
Compare commits
12 Commits
fc7ae0ec4e
...
0946b3a1da
Author | SHA1 | Date | |
---|---|---|---|
0946b3a1da | |||
e1c215b72e | |||
ea0598e507 | |||
28c3d9d2e4 | |||
e9f9d9dc98 | |||
bb75bfd15d | |||
9c84fb5887 | |||
3bb9272f06 | |||
a735e4ff29 | |||
63948a6de0 | |||
a470d77938 | |||
833be688ac |
@ -10,21 +10,20 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/itchyny/timefmt-go"
|
"github.com/itchyny/timefmt-go"
|
||||||
"github.com/lithammer/shortuuid/v3"
|
"github.com/lithammer/shortuuid/v3"
|
||||||
|
"github.com/timshannon/badgerhold/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (app *appContext) checkInvites() {
|
func (app *appContext) checkInvites() {
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
app.storage.loadInvites()
|
for _, data := range app.storage.GetInvites() {
|
||||||
changed := false
|
|
||||||
for code, data := range app.storage.GetInvites() {
|
|
||||||
expiry := data.ValidTill
|
expiry := data.ValidTill
|
||||||
if !currentTime.After(expiry) {
|
if !currentTime.After(expiry) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
app.debug.Printf("Housekeeping: Deleting old invite %s", code)
|
app.debug.Printf("Housekeeping: Deleting old invite %s", data.Code)
|
||||||
notify := data.Notify
|
notify := data.Notify
|
||||||
if emailEnabled && app.config.Section("notifications").Key("enabled").MustBool(false) && len(notify) != 0 {
|
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
|
var wait sync.WaitGroup
|
||||||
for address, settings := range notify {
|
for address, settings := range notify {
|
||||||
if !settings["notify-expiry"] {
|
if !settings["notify-expiry"] {
|
||||||
@ -33,9 +32,9 @@ func (app *appContext) checkInvites() {
|
|||||||
wait.Add(1)
|
wait.Add(1)
|
||||||
go func(addr string) {
|
go func(addr string) {
|
||||||
defer wait.Done()
|
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 {
|
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 {
|
} else {
|
||||||
// Check whether notify "address" is an email address of Jellyfin ID
|
// Check whether notify "address" is an email address of Jellyfin ID
|
||||||
if strings.Contains(addr, "@") {
|
if strings.Contains(addr, "@") {
|
||||||
@ -44,7 +43,7 @@ func (app *appContext) checkInvites() {
|
|||||||
err = app.sendByID(msg, addr)
|
err = app.sendByID(msg, addr)
|
||||||
}
|
}
|
||||||
if err != nil {
|
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 {
|
} else {
|
||||||
app.info.Printf("Sent expiry notification to %s", addr)
|
app.info.Printf("Sent expiry notification to %s", addr)
|
||||||
}
|
}
|
||||||
@ -53,18 +52,12 @@ func (app *appContext) checkInvites() {
|
|||||||
}
|
}
|
||||||
wait.Wait()
|
wait.Wait()
|
||||||
}
|
}
|
||||||
changed = true
|
app.storage.DeleteInvitesKey(data.Code)
|
||||||
app.storage.DeleteInvitesKey(code)
|
|
||||||
}
|
|
||||||
if changed {
|
|
||||||
app.storage.storeInvites()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *appContext) checkInvite(code string, used bool, username string) bool {
|
func (app *appContext) checkInvite(code string, used bool, username string) bool {
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
app.storage.loadInvites()
|
|
||||||
changed := false
|
|
||||||
inv, match := app.storage.GetInvitesKey(code)
|
inv, match := app.storage.GetInvitesKey(code)
|
||||||
if !match {
|
if !match {
|
||||||
return false
|
return false
|
||||||
@ -103,11 +96,9 @@ func (app *appContext) checkInvite(code string, used bool, username string) bool
|
|||||||
}
|
}
|
||||||
wait.Wait()
|
wait.Wait()
|
||||||
}
|
}
|
||||||
changed = true
|
|
||||||
match = false
|
match = false
|
||||||
app.storage.DeleteInvitesKey(code)
|
app.storage.DeleteInvitesKey(code)
|
||||||
} else if used {
|
} else if used {
|
||||||
changed = true
|
|
||||||
del := false
|
del := false
|
||||||
newInv := inv
|
newInv := inv
|
||||||
if newInv.RemainingUses == 1 {
|
if newInv.RemainingUses == 1 {
|
||||||
@ -122,9 +113,6 @@ func (app *appContext) checkInvite(code string, used bool, username string) bool
|
|||||||
app.storage.SetInvitesKey(code, newInv)
|
app.storage.SetInvitesKey(code, newInv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if changed {
|
|
||||||
app.storage.storeInvites()
|
|
||||||
}
|
|
||||||
return match
|
return match
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +126,6 @@ func (app *appContext) checkInvite(code string, used bool, username string) bool
|
|||||||
func (app *appContext) GenerateInvite(gc *gin.Context) {
|
func (app *appContext) GenerateInvite(gc *gin.Context) {
|
||||||
var req generateInviteDTO
|
var req generateInviteDTO
|
||||||
app.debug.Println("Generating new invite")
|
app.debug.Println("Generating new invite")
|
||||||
app.storage.loadInvites()
|
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
validTill := currentTime.AddDate(0, req.Months, req.Days)
|
validTill := currentTime.AddDate(0, req.Months, req.Days)
|
||||||
@ -213,14 +200,13 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if req.Profile != "" {
|
if req.Profile != "" {
|
||||||
if _, ok := app.storage.profiles[req.Profile]; ok {
|
if _, ok := app.storage.GetProfileKey(req.Profile); ok {
|
||||||
invite.Profile = req.Profile
|
invite.Profile = req.Profile
|
||||||
} else {
|
} else {
|
||||||
invite.Profile = "Default"
|
invite.Profile = "Default"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.storage.SetInvitesKey(inviteCode, invite)
|
app.storage.SetInvitesKey(inviteCode, invite)
|
||||||
app.storage.storeInvites()
|
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,13 +219,12 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
|
|||||||
func (app *appContext) GetInvites(gc *gin.Context) {
|
func (app *appContext) GetInvites(gc *gin.Context) {
|
||||||
app.debug.Println("Invites requested")
|
app.debug.Println("Invites requested")
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
app.storage.loadInvites()
|
|
||||||
app.checkInvites()
|
app.checkInvites()
|
||||||
var invites []inviteDTO
|
var invites []inviteDTO
|
||||||
for code, inv := range app.storage.GetInvites() {
|
for _, inv := range app.storage.GetInvites() {
|
||||||
_, months, days, hours, minutes, _ := timeDiff(inv.ValidTill, currentTime)
|
_, months, days, hours, minutes, _ := timeDiff(inv.ValidTill, currentTime)
|
||||||
invite := inviteDTO{
|
invite := inviteDTO{
|
||||||
Code: code,
|
Code: inv.Code,
|
||||||
Months: months,
|
Months: months,
|
||||||
Days: days,
|
Days: days,
|
||||||
Hours: hours,
|
Hours: hours,
|
||||||
@ -277,37 +262,36 @@ func (app *appContext) GetInvites(gc *gin.Context) {
|
|||||||
invite.SendTo = inv.SendTo
|
invite.SendTo = inv.SendTo
|
||||||
}
|
}
|
||||||
if len(inv.Notify) != 0 {
|
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) {
|
if app.config.Section("ui").Key("jellyfin_login").MustBool(false) {
|
||||||
app.storage.loadEmails()
|
addressOrID = gc.GetString("jfId")
|
||||||
if addr, ok := app.storage.GetEmailsKey(gc.GetString("jfId")); ok && addr.Addr != "" {
|
|
||||||
address = addr.Addr
|
|
||||||
}
|
|
||||||
} else {
|
} 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[addressOrID]; ok {
|
||||||
if _, ok = inv.Notify[address]["notify-expiry"]; ok {
|
if _, ok = inv.Notify[addressOrID]["notify-expiry"]; ok {
|
||||||
invite.NotifyExpiry = inv.Notify[address]["notify-expiry"]
|
invite.NotifyExpiry = inv.Notify[addressOrID]["notify-expiry"]
|
||||||
}
|
}
|
||||||
if _, ok = inv.Notify[address]["notify-creation"]; ok {
|
if _, ok = inv.Notify[addressOrID]["notify-creation"]; ok {
|
||||||
invite.NotifyCreation = inv.Notify[address]["notify-creation"]
|
invite.NotifyCreation = inv.Notify[addressOrID]["notify-creation"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invites = append(invites, invite)
|
invites = append(invites, invite)
|
||||||
}
|
}
|
||||||
profiles := make([]string, len(app.storage.profiles))
|
fullProfileList := app.storage.GetProfiles()
|
||||||
if len(app.storage.profiles) != 0 {
|
profiles := make([]string, len(fullProfileList))
|
||||||
profiles[0] = app.storage.defaultProfile
|
if len(profiles) != 0 {
|
||||||
|
defaultProfile := app.storage.GetDefaultProfile()
|
||||||
|
profiles[0] = defaultProfile.Name
|
||||||
i := 1
|
i := 1
|
||||||
if len(app.storage.profiles) > 1 {
|
if len(fullProfileList) > 1 {
|
||||||
for p := range app.storage.profiles {
|
app.storage.db.ForEach(badgerhold.Where("Name").Ne(profiles[0]), func(p *Profile) error {
|
||||||
if p != app.storage.defaultProfile {
|
profiles[i] = p.Name
|
||||||
profiles[i] = p
|
i++
|
||||||
i++
|
return nil
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp := getInvitesDTO{
|
resp := getInvitesDTO{
|
||||||
@ -330,7 +314,7 @@ func (app *appContext) SetProfile(gc *gin.Context) {
|
|||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
app.debug.Printf("%s: Setting profile to \"%s\"", req.Invite, req.Profile)
|
app.debug.Printf("%s: Setting profile to \"%s\"", req.Invite, req.Profile)
|
||||||
// "" means "Don't apply profile"
|
// "" means "Don't apply profile"
|
||||||
if _, ok := app.storage.profiles[req.Profile]; !ok && req.Profile != "" {
|
if _, ok := app.storage.GetProfileKey(req.Profile); !ok && req.Profile != "" {
|
||||||
app.err.Printf("%s: Profile \"%s\" not found", req.Invite, req.Profile)
|
app.err.Printf("%s: Profile \"%s\" not found", req.Invite, req.Profile)
|
||||||
respond(500, "Profile not found", gc)
|
respond(500, "Profile not found", gc)
|
||||||
return
|
return
|
||||||
@ -338,7 +322,6 @@ func (app *appContext) SetProfile(gc *gin.Context) {
|
|||||||
inv, _ := app.storage.GetInvitesKey(req.Invite)
|
inv, _ := app.storage.GetInvitesKey(req.Invite)
|
||||||
inv.Profile = req.Profile
|
inv.Profile = req.Profile
|
||||||
app.storage.SetInvitesKey(req.Invite, inv)
|
app.storage.SetInvitesKey(req.Invite, inv)
|
||||||
app.storage.storeInvites()
|
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,8 +340,6 @@ func (app *appContext) SetNotify(gc *gin.Context) {
|
|||||||
changed := false
|
changed := false
|
||||||
for code, settings := range req {
|
for code, settings := range req {
|
||||||
app.debug.Printf("%s: Notification settings change requested", code)
|
app.debug.Printf("%s: Notification settings change requested", code)
|
||||||
app.storage.loadInvites()
|
|
||||||
app.storage.loadEmails()
|
|
||||||
invite, ok := app.storage.GetInvitesKey(code)
|
invite, ok := app.storage.GetInvitesKey(code)
|
||||||
if !ok {
|
if !ok {
|
||||||
app.err.Printf("%s Notification setting change failed: Invalid code", code)
|
app.err.Printf("%s Notification setting change failed: Invalid code", code)
|
||||||
@ -401,9 +382,6 @@ func (app *appContext) SetNotify(gc *gin.Context) {
|
|||||||
app.storage.SetInvitesKey(code, invite)
|
app.storage.SetInvitesKey(code, invite)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if changed {
|
|
||||||
app.storage.storeInvites()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Delete an invite.
|
// @Summary Delete an invite.
|
||||||
@ -422,7 +400,6 @@ func (app *appContext) DeleteInvite(gc *gin.Context) {
|
|||||||
_, ok = app.storage.GetInvitesKey(req.Code)
|
_, ok = app.storage.GetInvitesKey(req.Code)
|
||||||
if ok {
|
if ok {
|
||||||
app.storage.DeleteInvitesKey(req.Code)
|
app.storage.DeleteInvitesKey(req.Code)
|
||||||
app.storage.storeInvites()
|
|
||||||
app.info.Printf("%s: Invite deleted", req.Code)
|
app.info.Printf("%s: Invite deleted", req.Code)
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
return
|
return
|
||||||
|
108
api-messages.go
108
api-messages.go
@ -25,18 +25,18 @@ func (app *appContext) GetCustomContent(gc *gin.Context) {
|
|||||||
adminLang = app.storage.lang.chosenAdminLang
|
adminLang = app.storage.lang.chosenAdminLang
|
||||||
}
|
}
|
||||||
list := emailListDTO{
|
list := emailListDTO{
|
||||||
"UserCreated": {Name: app.storage.lang.Email[lang].UserCreated["name"], Enabled: app.storage.customEmails.UserCreated.Enabled},
|
"UserCreated": {Name: app.storage.lang.Email[lang].UserCreated["name"], Enabled: app.storage.MustGetCustomContentKey("UserCreated").Enabled},
|
||||||
"InviteExpiry": {Name: app.storage.lang.Email[lang].InviteExpiry["name"], Enabled: app.storage.customEmails.InviteExpiry.Enabled},
|
"InviteExpiry": {Name: app.storage.lang.Email[lang].InviteExpiry["name"], Enabled: app.storage.MustGetCustomContentKey("InviteExpiry").Enabled},
|
||||||
"PasswordReset": {Name: app.storage.lang.Email[lang].PasswordReset["name"], Enabled: app.storage.customEmails.PasswordReset.Enabled},
|
"PasswordReset": {Name: app.storage.lang.Email[lang].PasswordReset["name"], Enabled: app.storage.MustGetCustomContentKey("PasswordReset").Enabled},
|
||||||
"UserDeleted": {Name: app.storage.lang.Email[lang].UserDeleted["name"], Enabled: app.storage.customEmails.UserDeleted.Enabled},
|
"UserDeleted": {Name: app.storage.lang.Email[lang].UserDeleted["name"], Enabled: app.storage.MustGetCustomContentKey("UserDeleted").Enabled},
|
||||||
"UserDisabled": {Name: app.storage.lang.Email[lang].UserDisabled["name"], Enabled: app.storage.customEmails.UserDisabled.Enabled},
|
"UserDisabled": {Name: app.storage.lang.Email[lang].UserDisabled["name"], Enabled: app.storage.MustGetCustomContentKey("UserDisabled").Enabled},
|
||||||
"UserEnabled": {Name: app.storage.lang.Email[lang].UserEnabled["name"], Enabled: app.storage.customEmails.UserEnabled.Enabled},
|
"UserEnabled": {Name: app.storage.lang.Email[lang].UserEnabled["name"], Enabled: app.storage.MustGetCustomContentKey("UserEnabled").Enabled},
|
||||||
"InviteEmail": {Name: app.storage.lang.Email[lang].InviteEmail["name"], Enabled: app.storage.customEmails.InviteEmail.Enabled},
|
"InviteEmail": {Name: app.storage.lang.Email[lang].InviteEmail["name"], Enabled: app.storage.MustGetCustomContentKey("InviteEmail").Enabled},
|
||||||
"WelcomeEmail": {Name: app.storage.lang.Email[lang].WelcomeEmail["name"], Enabled: app.storage.customEmails.WelcomeEmail.Enabled},
|
"WelcomeEmail": {Name: app.storage.lang.Email[lang].WelcomeEmail["name"], Enabled: app.storage.MustGetCustomContentKey("WelcomeEmail").Enabled},
|
||||||
"EmailConfirmation": {Name: app.storage.lang.Email[lang].EmailConfirmation["name"], Enabled: app.storage.customEmails.EmailConfirmation.Enabled},
|
"EmailConfirmation": {Name: app.storage.lang.Email[lang].EmailConfirmation["name"], Enabled: app.storage.MustGetCustomContentKey("EmailConfirmation").Enabled},
|
||||||
"UserExpired": {Name: app.storage.lang.Email[lang].UserExpired["name"], Enabled: app.storage.customEmails.UserExpired.Enabled},
|
"UserExpired": {Name: app.storage.lang.Email[lang].UserExpired["name"], Enabled: app.storage.MustGetCustomContentKey("UserExpired").Enabled},
|
||||||
"UserLogin": {Name: app.storage.lang.Admin[adminLang].Strings["userPageLogin"], Enabled: app.storage.userPage.Login.Enabled},
|
"UserLogin": {Name: app.storage.lang.Admin[adminLang].Strings["userPageLogin"], Enabled: app.storage.MustGetCustomContentKey("Login").Enabled},
|
||||||
"UserPage": {Name: app.storage.lang.Admin[adminLang].Strings["userPagePage"], Enabled: app.storage.userPage.Page.Enabled},
|
"UserPage": {Name: app.storage.lang.Admin[adminLang].Strings["userPagePage"], Enabled: app.storage.MustGetCustomContentKey("Page").Enabled},
|
||||||
}
|
}
|
||||||
|
|
||||||
filter := gc.Query("filter")
|
filter := gc.Query("filter")
|
||||||
@ -50,10 +50,11 @@ func (app *appContext) GetCustomContent(gc *gin.Context) {
|
|||||||
gc.JSON(200, list)
|
gc.JSON(200, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *appContext) getCustomMessage(id string) *customContent {
|
// No longer needed, these are stored by string keys in the database now.
|
||||||
|
/* func (app *appContext) getCustomMessage(id string) *CustomContent {
|
||||||
switch id {
|
switch id {
|
||||||
case "Announcement":
|
case "Announcement":
|
||||||
return &customContent{}
|
return &CustomContent{}
|
||||||
case "UserCreated":
|
case "UserCreated":
|
||||||
return &app.storage.customEmails.UserCreated
|
return &app.storage.customEmails.UserCreated
|
||||||
case "InviteExpiry":
|
case "InviteExpiry":
|
||||||
@ -80,45 +81,38 @@ func (app *appContext) getCustomMessage(id string) *customContent {
|
|||||||
return &app.storage.userPage.Page
|
return &app.storage.userPage.Page
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
} */
|
||||||
|
|
||||||
// @Summary Sets the corresponding custom email.
|
// @Summary Sets the corresponding custom content.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param customEmails body customEmails true "Content = email (in markdown)."
|
// @Param CustomContent body CustomContent true "Content = email (in markdown)."
|
||||||
// @Success 200 {object} boolResponse
|
// @Success 200 {object} boolResponse
|
||||||
// @Failure 400 {object} boolResponse
|
// @Failure 400 {object} boolResponse
|
||||||
// @Failure 500 {object} boolResponse
|
// @Failure 500 {object} boolResponse
|
||||||
// @Param id path string true "ID of email"
|
// @Param id path string true "ID of content"
|
||||||
// @Router /config/emails/{id} [post]
|
// @Router /config/emails/{id} [post]
|
||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
// @tags Configuration
|
// @tags Configuration
|
||||||
func (app *appContext) SetCustomMessage(gc *gin.Context) {
|
func (app *appContext) SetCustomMessage(gc *gin.Context) {
|
||||||
var req customContent
|
var req CustomContent
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
id := gc.Param("id")
|
id := gc.Param("id")
|
||||||
if req.Content == "" {
|
if req.Content == "" {
|
||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
message := app.getCustomMessage(id)
|
message, ok := app.storage.GetCustomContentKey(id)
|
||||||
if message == nil {
|
if !ok {
|
||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
message.Content = req.Content
|
message.Content = req.Content
|
||||||
message.Enabled = true
|
message.Enabled = true
|
||||||
if app.storage.storeCustomEmails() != nil {
|
app.storage.SetCustomContentKey(id, message)
|
||||||
respondBool(500, false, gc)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if app.storage.storeUserPageContent() != nil {
|
|
||||||
respondBool(500, false, gc)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Enable/Disable custom email.
|
// @Summary Enable/Disable custom content.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} boolResponse
|
// @Success 200 {object} boolResponse
|
||||||
// @Failure 400 {object} boolResponse
|
// @Failure 400 {object} boolResponse
|
||||||
@ -137,24 +131,17 @@ func (app *appContext) SetCustomMessageState(gc *gin.Context) {
|
|||||||
} else if s != "disable" {
|
} else if s != "disable" {
|
||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
}
|
}
|
||||||
message := app.getCustomMessage(id)
|
message, ok := app.storage.GetCustomContentKey(id)
|
||||||
if message == nil {
|
if !ok {
|
||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
message.Enabled = enabled
|
message.Enabled = enabled
|
||||||
if app.storage.storeCustomEmails() != nil {
|
app.storage.SetCustomContentKey(id, message)
|
||||||
respondBool(500, false, gc)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if app.storage.storeUserPageContent() != nil {
|
|
||||||
respondBool(500, false, gc)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Returns the custom email/message (generating it if not set) and list of used variables in it.
|
// @Summary Returns the custom content/message (generating it if not set) and list of used variables in it.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} customEmailDTO
|
// @Success 200 {object} customEmailDTO
|
||||||
// @Failure 400 {object} boolResponse
|
// @Failure 400 {object} boolResponse
|
||||||
@ -174,8 +161,8 @@ func (app *appContext) GetCustomMessageTemplate(gc *gin.Context) {
|
|||||||
var values map[string]interface{}
|
var values map[string]interface{}
|
||||||
username := app.storage.lang.Email[lang].Strings.get("username")
|
username := app.storage.lang.Email[lang].Strings.get("username")
|
||||||
emailAddress := app.storage.lang.Email[lang].Strings.get("emailAddress")
|
emailAddress := app.storage.lang.Email[lang].Strings.get("emailAddress")
|
||||||
customMessage := app.getCustomMessage(id)
|
customMessage, ok := app.storage.GetCustomContentKey(id)
|
||||||
if customMessage == nil {
|
if !ok {
|
||||||
app.err.Printf("Failed to get custom message with ID \"%s\"", id)
|
app.err.Printf("Failed to get custom message with ID \"%s\"", id)
|
||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
@ -280,13 +267,7 @@ func (app *appContext) GetCustomMessageTemplate(gc *gin.Context) {
|
|||||||
if variables == nil {
|
if variables == nil {
|
||||||
variables = []string{}
|
variables = []string{}
|
||||||
}
|
}
|
||||||
if app.storage.storeCustomEmails() != nil {
|
app.storage.SetCustomContentKey(id, customMessage)
|
||||||
respondBool(500, false, gc)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if app.storage.storeUserPageContent() != nil {
|
|
||||||
respondBool(500, false, gc)
|
|
||||||
}
|
|
||||||
var mail *Message
|
var mail *Message
|
||||||
if id != "UserLogin" && id != "UserPage" {
|
if id != "UserLogin" && id != "UserPage" {
|
||||||
mail, err = app.email.constructTemplate("", "<div class=\"preview-content\"></div>", app)
|
mail, err = app.email.constructTemplate("", "<div class=\"preview-content\"></div>", app)
|
||||||
@ -387,11 +368,6 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
|
|||||||
change := dcUser.Contact != req.Discord
|
change := dcUser.Contact != req.Discord
|
||||||
dcUser.Contact = req.Discord
|
dcUser.Contact = req.Discord
|
||||||
app.storage.SetDiscordKey(req.ID, dcUser)
|
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 {
|
if change {
|
||||||
msg := ""
|
msg := ""
|
||||||
if !req.Discord {
|
if !req.Discord {
|
||||||
@ -404,11 +380,6 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
|
|||||||
change := mxUser.Contact != req.Matrix
|
change := mxUser.Contact != req.Matrix
|
||||||
mxUser.Contact = req.Matrix
|
mxUser.Contact = req.Matrix
|
||||||
app.storage.SetMatrixKey(req.ID, mxUser)
|
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 {
|
if change {
|
||||||
msg := ""
|
msg := ""
|
||||||
if !req.Matrix {
|
if !req.Matrix {
|
||||||
@ -421,11 +392,6 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
|
|||||||
change := email.Contact != req.Email
|
change := email.Contact != req.Email
|
||||||
email.Contact = req.Email
|
email.Contact = req.Email
|
||||||
app.storage.SetEmailsKey(req.ID, 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 {
|
if change {
|
||||||
msg := ""
|
msg := ""
|
||||||
if !req.Email {
|
if !req.Email {
|
||||||
@ -646,7 +612,7 @@ func (app *appContext) MatrixConnect(gc *gin.Context) {
|
|||||||
var req MatrixConnectUserDTO
|
var req MatrixConnectUserDTO
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
if app.storage.GetMatrix() == nil {
|
if app.storage.GetMatrix() == nil {
|
||||||
app.storage.matrix = matrixStore{}
|
app.storage.deprecatedMatrix = matrixStore{}
|
||||||
}
|
}
|
||||||
roomID, encrypted, err := app.matrix.CreateRoom(req.UserID)
|
roomID, encrypted, err := app.matrix.CreateRoom(req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -662,11 +628,6 @@ func (app *appContext) MatrixConnect(gc *gin.Context) {
|
|||||||
Encrypted: encrypted,
|
Encrypted: encrypted,
|
||||||
})
|
})
|
||||||
app.matrix.isEncrypted[roomID] = 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)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -717,11 +678,6 @@ func (app *appContext) DiscordConnect(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
app.storage.SetDiscordKey(req.JellyfinID, user)
|
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)
|
linkExistingOmbiDiscordTelegram(app)
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
18
api-ombi.go
18
api-ombi.go
@ -71,7 +71,7 @@ func (app *appContext) SetOmbiProfile(gc *gin.Context) {
|
|||||||
var req ombiUser
|
var req ombiUser
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
profileName := gc.Param("profile")
|
profileName := gc.Param("profile")
|
||||||
profile, ok := app.storage.profiles[profileName]
|
profile, ok := app.storage.GetProfileKey(profileName)
|
||||||
if !ok {
|
if !ok {
|
||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
@ -83,12 +83,7 @@ func (app *appContext) SetOmbiProfile(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
profile.Ombi = template
|
profile.Ombi = template
|
||||||
app.storage.profiles[profileName] = profile
|
app.storage.SetProfileKey(profileName, profile)
|
||||||
if err := app.storage.storeProfiles(); err != nil {
|
|
||||||
respond(500, "Failed to store profile", gc)
|
|
||||||
app.err.Printf("Failed to store profiles: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respondBool(204, true, gc)
|
respondBool(204, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,17 +98,12 @@ func (app *appContext) SetOmbiProfile(gc *gin.Context) {
|
|||||||
// @tags Ombi
|
// @tags Ombi
|
||||||
func (app *appContext) DeleteOmbiProfile(gc *gin.Context) {
|
func (app *appContext) DeleteOmbiProfile(gc *gin.Context) {
|
||||||
profileName := gc.Param("profile")
|
profileName := gc.Param("profile")
|
||||||
profile, ok := app.storage.profiles[profileName]
|
profile, ok := app.storage.GetProfileKey(profileName)
|
||||||
if !ok {
|
if !ok {
|
||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
profile.Ombi = nil
|
profile.Ombi = nil
|
||||||
app.storage.profiles[profileName] = profile
|
app.storage.SetProfileKey(profileName, profile)
|
||||||
if err := app.storage.storeProfiles(); err != nil {
|
|
||||||
respond(500, "Failed to store profile", gc)
|
|
||||||
app.err.Printf("Failed to store profiles: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respondBool(204, true, gc)
|
respondBool(204, true, gc)
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/timshannon/badgerhold/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @Summary Get a list of profiles
|
// @Summary Get a list of profiles
|
||||||
@ -13,14 +14,13 @@ import (
|
|||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
// @tags Profiles & Settings
|
// @tags Profiles & Settings
|
||||||
func (app *appContext) GetProfiles(gc *gin.Context) {
|
func (app *appContext) GetProfiles(gc *gin.Context) {
|
||||||
app.storage.loadProfiles()
|
|
||||||
app.debug.Println("Profiles requested")
|
app.debug.Println("Profiles requested")
|
||||||
out := getProfilesDTO{
|
out := getProfilesDTO{
|
||||||
DefaultProfile: app.storage.defaultProfile,
|
DefaultProfile: app.storage.GetDefaultProfile().Name,
|
||||||
Profiles: map[string]profileDTO{},
|
Profiles: map[string]profileDTO{},
|
||||||
}
|
}
|
||||||
for name, p := range app.storage.profiles {
|
for _, p := range app.storage.GetProfiles() {
|
||||||
out.Profiles[name] = profileDTO{
|
out.Profiles[p.Name] = profileDTO{
|
||||||
Admin: p.Admin,
|
Admin: p.Admin,
|
||||||
LibraryAccess: p.LibraryAccess,
|
LibraryAccess: p.LibraryAccess,
|
||||||
FromUser: p.FromUser,
|
FromUser: p.FromUser,
|
||||||
@ -42,20 +42,20 @@ func (app *appContext) SetDefaultProfile(gc *gin.Context) {
|
|||||||
req := profileChangeDTO{}
|
req := profileChangeDTO{}
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
app.info.Printf("Setting default profile to \"%s\"", req.Name)
|
app.info.Printf("Setting default profile to \"%s\"", req.Name)
|
||||||
if _, ok := app.storage.profiles[req.Name]; !ok {
|
if _, ok := app.storage.GetProfileKey(req.Name); !ok {
|
||||||
app.err.Printf("Profile not found: \"%s\"", req.Name)
|
app.err.Printf("Profile not found: \"%s\"", req.Name)
|
||||||
respond(500, "Profile not found", gc)
|
respond(500, "Profile not found", gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for name, profile := range app.storage.profiles {
|
app.storage.db.ForEach(&badgerhold.Query{}, func(profile *Profile) error {
|
||||||
if name == req.Name {
|
if profile.Name == req.Name {
|
||||||
profile.Admin = true
|
profile.Default = true
|
||||||
app.storage.profiles[name] = profile
|
|
||||||
} else {
|
} else {
|
||||||
profile.Admin = false
|
profile.Default = false
|
||||||
}
|
}
|
||||||
}
|
app.storage.SetProfileKey(profile.Name, *profile)
|
||||||
app.storage.defaultProfile = req.Name
|
return nil
|
||||||
|
})
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,10 +92,7 @@ func (app *appContext) CreateProfile(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.storage.loadProfiles()
|
app.storage.SetProfileKey(req.Name, profile)
|
||||||
app.storage.profiles[req.Name] = profile
|
|
||||||
app.storage.storeProfiles()
|
|
||||||
app.storage.loadProfiles()
|
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,12 +107,6 @@ func (app *appContext) DeleteProfile(gc *gin.Context) {
|
|||||||
req := profileChangeDTO{}
|
req := profileChangeDTO{}
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
name := req.Name
|
name := req.Name
|
||||||
if _, ok := app.storage.profiles[name]; ok {
|
app.storage.DeleteProfileKey(name)
|
||||||
if app.storage.defaultProfile == name {
|
|
||||||
app.storage.defaultProfile = ""
|
|
||||||
}
|
|
||||||
delete(app.storage.profiles, name)
|
|
||||||
}
|
|
||||||
app.storage.storeProfiles()
|
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
@ -38,15 +38,10 @@ func (app *appContext) MyDetails(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
resp.Disabled = user.Policy.IsDisabled
|
resp.Disabled = user.Policy.IsDisabled
|
||||||
|
|
||||||
if exp, ok := app.storage.users[user.ID]; ok {
|
if exp, ok := app.storage.GetUserExpiryKey(user.ID); ok {
|
||||||
resp.Expiry = exp.Unix()
|
resp.Expiry = exp.Expiry.Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
app.storage.loadEmails()
|
|
||||||
app.storage.loadDiscordUsers()
|
|
||||||
app.storage.loadMatrixUsers()
|
|
||||||
app.storage.loadTelegramUsers()
|
|
||||||
|
|
||||||
if emailEnabled {
|
if emailEnabled {
|
||||||
resp.Email = &MyDetailsContactMethodsDTO{}
|
resp.Email = &MyDetailsContactMethodsDTO{}
|
||||||
if email, ok := app.storage.GetEmailsKey(user.ID); ok && email.Addr != "" {
|
if email, ok := app.storage.GetEmailsKey(user.ID); ok && email.Addr != "" {
|
||||||
@ -199,7 +194,6 @@ func (app *appContext) confirmMyAction(gc *gin.Context, key string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.storage.storeEmails()
|
|
||||||
app.info.Println("Email list modified")
|
app.info.Println("Email list modified")
|
||||||
gc.Redirect(http.StatusSeeOther, "/my/account")
|
gc.Redirect(http.StatusSeeOther, "/my/account")
|
||||||
return
|
return
|
||||||
@ -511,8 +505,8 @@ func (app *appContext) ResetMyPassword(gc *gin.Context) {
|
|||||||
var pwr InternalPWR
|
var pwr InternalPWR
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
jfID := app.ReverseUserSearch(address)
|
jfUser, ok := app.ReverseUserSearch(address)
|
||||||
if jfID == "" {
|
if !ok {
|
||||||
app.debug.Printf("Ignoring PWR request: User not found")
|
app.debug.Printf("Ignoring PWR request: User not found")
|
||||||
|
|
||||||
for range timerWait {
|
for range timerWait {
|
||||||
@ -521,7 +515,7 @@ func (app *appContext) ResetMyPassword(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pwr, err = app.GenInternalReset(jfID)
|
pwr, err = app.GenInternalReset(jfUser.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf("Failed to get user from Jellyfin: %v", err)
|
app.err.Printf("Failed to get user from Jellyfin: %v", err)
|
||||||
for range timerWait {
|
for range timerWait {
|
||||||
@ -550,7 +544,7 @@ func (app *appContext) ResetMyPassword(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} else if err := app.sendByID(msg, jfID); err != nil {
|
} else if err := app.sendByID(msg, jfUser.ID); err != nil {
|
||||||
app.err.Printf("Failed to send password reset message to \"%s\": %v", address, err)
|
app.err.Printf("Failed to send password reset message to \"%s\": %v", address, err)
|
||||||
} else {
|
} else {
|
||||||
app.info.Printf("Sent password reset message to \"%s\"", address)
|
app.info.Printf("Sent password reset message to \"%s\"", address)
|
||||||
|
181
api-users.go
181
api-users.go
@ -44,16 +44,16 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := user.ID
|
id := user.ID
|
||||||
if app.storage.policy.BlockedTags != nil {
|
profile := app.storage.GetDefaultProfile()
|
||||||
status, err = app.jf.SetPolicy(id, app.storage.policy)
|
// Check profile isn't empty
|
||||||
|
if profile.Policy.BlockedTags != nil {
|
||||||
|
status, err = app.jf.SetPolicy(id, profile.Policy)
|
||||||
if !(status == 200 || status == 204 || err == nil) {
|
if !(status == 200 || status == 204 || err == nil) {
|
||||||
app.err.Printf("%s: Failed to set user policy (%d): %v", req.Username, status, err)
|
app.err.Printf("%s: Failed to set user policy (%d): %v", req.Username, status, err)
|
||||||
}
|
}
|
||||||
}
|
status, err = app.jf.SetConfiguration(id, profile.Configuration)
|
||||||
if app.storage.configuration.GroupedFolders != nil && len(app.storage.displayprefs) != 0 {
|
|
||||||
status, err = app.jf.SetConfiguration(id, app.storage.configuration)
|
|
||||||
if (status == 200 || status == 204) && err == nil {
|
if (status == 200 || status == 204) && err == nil {
|
||||||
status, err = app.jf.SetDisplayPreferences(id, app.storage.displayprefs)
|
status, err = app.jf.SetDisplayPreferences(id, profile.Displayprefs)
|
||||||
}
|
}
|
||||||
if !((status == 200 || status == 204) && err == nil) {
|
if !((status == 200 || status == 204) && err == nil) {
|
||||||
app.err.Printf("%s: Failed to set configuration template (%d): %v", req.Username, status, err)
|
app.err.Printf("%s: Failed to set configuration template (%d): %v", req.Username, status, err)
|
||||||
@ -62,18 +62,18 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
|
|||||||
app.jf.CacheExpiry = time.Now()
|
app.jf.CacheExpiry = time.Now()
|
||||||
if emailEnabled {
|
if emailEnabled {
|
||||||
app.storage.SetEmailsKey(id, EmailAddress{Addr: req.Email, Contact: true})
|
app.storage.SetEmailsKey(id, EmailAddress{Addr: req.Email, Contact: true})
|
||||||
app.storage.storeEmails()
|
|
||||||
}
|
}
|
||||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
app.storage.loadOmbiTemplate()
|
profile := app.storage.GetDefaultProfile()
|
||||||
if len(app.storage.ombi_template) != 0 {
|
if profile.Ombi == nil {
|
||||||
errors, code, err := app.ombi.NewUser(req.Username, req.Password, req.Email, app.storage.ombi_template)
|
profile.Ombi = map[string]interface{}{}
|
||||||
if err != nil || code != 200 {
|
}
|
||||||
app.err.Printf("Failed to create Ombi user (%d): %v", code, err)
|
errors, code, err := app.ombi.NewUser(req.Username, req.Password, req.Email, profile.Ombi)
|
||||||
app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", "))
|
if err != nil || code != 200 {
|
||||||
} else {
|
app.err.Printf("Failed to create Ombi user (%d): %v", code, err)
|
||||||
app.info.Println("Created Ombi user")
|
app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", "))
|
||||||
}
|
} else {
|
||||||
|
app.info.Println("Created Ombi user")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "" {
|
if emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "" {
|
||||||
@ -130,17 +130,13 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
success = false
|
success = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if app.config.Section("discord").Key("require_unique").MustBool(false) {
|
if app.config.Section("discord").Key("require_unique").MustBool(false) && app.discord.UserExists(discordUser.ID) {
|
||||||
for _, u := range app.storage.GetDiscord() {
|
f = func(gc *gin.Context) {
|
||||||
if discordUser.ID == u.ID {
|
app.debug.Printf("%s: New user failed: Discord user already linked", req.Code)
|
||||||
f = func(gc *gin.Context) {
|
respond(400, "errorAccountLinked", gc)
|
||||||
app.debug.Printf("%s: New user failed: Discord user already linked", req.Code)
|
|
||||||
respond(400, "errorAccountLinked", gc)
|
|
||||||
}
|
|
||||||
success = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
success = false
|
||||||
|
return
|
||||||
}
|
}
|
||||||
err := app.discord.ApplyRole(discordUser.ID)
|
err := app.discord.ApplyRole(discordUser.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -176,17 +172,13 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
success = false
|
success = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if app.config.Section("matrix").Key("require_unique").MustBool(false) {
|
if app.config.Section("matrix").Key("require_unique").MustBool(false) && app.matrix.UserExists(user.User.UserID) {
|
||||||
for _, u := range app.storage.GetMatrix() {
|
f = func(gc *gin.Context) {
|
||||||
if user.User.UserID == u.UserID {
|
app.debug.Printf("%s: New user failed: Matrix user already linked", req.Code)
|
||||||
f = func(gc *gin.Context) {
|
respond(400, "errorAccountLinked", gc)
|
||||||
app.debug.Printf("%s: New user failed: Matrix user already linked", req.Code)
|
|
||||||
respond(400, "errorAccountLinked", gc)
|
|
||||||
}
|
|
||||||
success = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
success = false
|
||||||
|
return
|
||||||
}
|
}
|
||||||
matrixVerified = user.Verified
|
matrixVerified = user.Verified
|
||||||
matrixUser = *user.User
|
matrixUser = *user.User
|
||||||
@ -278,7 +270,6 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
success = false
|
success = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
app.storage.loadProfiles()
|
|
||||||
invite, _ := app.storage.GetInvitesKey(req.Code)
|
invite, _ := app.storage.GetInvitesKey(req.Code)
|
||||||
app.checkInvite(req.Code, true, req.Username)
|
app.checkInvite(req.Code, true, req.Username)
|
||||||
if emailEnabled && app.config.Section("notifications").Key("enabled").MustBool(false) {
|
if emailEnabled && app.config.Section("notifications").Key("enabled").MustBool(false) {
|
||||||
@ -310,9 +301,9 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
if invite.Profile != "" {
|
if invite.Profile != "" {
|
||||||
app.debug.Printf("Applying settings from profile \"%s\"", invite.Profile)
|
app.debug.Printf("Applying settings from profile \"%s\"", invite.Profile)
|
||||||
var ok bool
|
var ok bool
|
||||||
profile, ok = app.storage.profiles[invite.Profile]
|
profile, ok = app.storage.GetProfileKey(invite.Profile)
|
||||||
if !ok {
|
if !ok {
|
||||||
profile = app.storage.profiles["Default"]
|
profile = app.storage.GetDefaultProfile()
|
||||||
}
|
}
|
||||||
if profile.Policy.BlockedTags != nil {
|
if profile.Policy.BlockedTags != nil {
|
||||||
app.debug.Printf("Applying policy from profile \"%s\"", invite.Profile)
|
app.debug.Printf("Applying policy from profile \"%s\"", invite.Profile)
|
||||||
@ -335,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 app.config.Section("password_resets").Key("enabled").MustBool(false) {
|
||||||
if req.Email != "" {
|
if req.Email != "" {
|
||||||
app.storage.SetEmailsKey(id, EmailAddress{Addr: req.Email, Contact: true})
|
app.storage.SetEmailsKey(id, EmailAddress{Addr: req.Email, Contact: true})
|
||||||
app.storage.storeEmails()
|
|
||||||
}
|
}
|
||||||
expiry := time.Time{}
|
expiry := time.Time{}
|
||||||
if invite.UserExpiry {
|
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)
|
expiry = time.Now().AddDate(0, invite.UserMonths, invite.UserDays).Add(time.Duration((60*invite.UserHours)+invite.UserMinutes) * time.Minute)
|
||||||
app.storage.users[id] = expiry
|
app.storage.SetUserExpiryKey(id, UserExpiry{Expiry: expiry})
|
||||||
if err := app.storage.storeUsers(); err != nil {
|
|
||||||
app.err.Printf("Failed to store user duration: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if discordVerified {
|
if discordVerified {
|
||||||
discordUser.Contact = req.DiscordContact
|
discordUser.Contact = req.DiscordContact
|
||||||
if app.storage.discord == nil {
|
if app.storage.deprecatedDiscord == nil {
|
||||||
app.storage.discord = discordStore{}
|
app.storage.deprecatedDiscord = discordStore{}
|
||||||
}
|
}
|
||||||
app.storage.SetDiscordKey(user.ID, discordUser)
|
app.storage.SetDiscordKey(user.ID, discordUser)
|
||||||
if err := app.storage.storeDiscordUsers(); err != nil {
|
delete(app.discord.verifiedTokens, req.DiscordPIN)
|
||||||
app.err.Printf("Failed to store Discord users: %v", err)
|
|
||||||
} else {
|
|
||||||
delete(app.discord.verifiedTokens, req.DiscordPIN)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if telegramVerified {
|
if telegramVerified {
|
||||||
tgUser := TelegramUser{
|
tgUser := TelegramUser{
|
||||||
@ -368,8 +349,8 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
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.deprecatedTelegram == nil {
|
||||||
app.storage.telegram = telegramStore{}
|
app.storage.deprecatedTelegram = telegramStore{}
|
||||||
}
|
}
|
||||||
app.telegram.DeleteVerifiedToken(req.TelegramPIN)
|
app.telegram.DeleteVerifiedToken(req.TelegramPIN)
|
||||||
app.storage.SetTelegramKey(user.ID, tgUser)
|
app.storage.SetTelegramKey(user.ID, tgUser)
|
||||||
@ -412,13 +393,10 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
if matrixVerified {
|
if matrixVerified {
|
||||||
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.deprecatedMatrix == nil {
|
||||||
app.storage.matrix = matrixStore{}
|
app.storage.deprecatedMatrix = matrixStore{}
|
||||||
}
|
}
|
||||||
app.storage.SetMatrixKey(user.ID, matrixUser)
|
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 {
|
if (emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "") || telegramVerified || discordVerified || matrixVerified {
|
||||||
name := app.getAddressOrName(user.ID)
|
name := app.getAddressOrName(user.ID)
|
||||||
@ -478,14 +456,10 @@ func (app *appContext) NewUser(gc *gin.Context) {
|
|||||||
respond(400, "errorNoEmail", gc)
|
respond(400, "errorNoEmail", gc)
|
||||||
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 != "" && app.EmailAddressExists(req.Email) {
|
||||||
for _, email := range app.storage.GetEmails() {
|
app.info.Printf("%s: New user failed: Email already in use", req.Code)
|
||||||
if req.Email == email.Addr {
|
respond(400, "errorEmailLinked", gc)
|
||||||
app.info.Printf("%s: New user failed: Email already in use", req.Code)
|
return
|
||||||
respond(400, "errorEmailLinked", gc)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f, success := app.newUser(req, false)
|
f, success := app.newUser(req, false)
|
||||||
@ -641,21 +615,16 @@ func (app *appContext) ExtendExpiry(gc *gin.Context) {
|
|||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
app.storage.usersLock.Lock()
|
|
||||||
defer app.storage.usersLock.Unlock()
|
|
||||||
for _, id := range req.Users {
|
for _, id := range req.Users {
|
||||||
if expiry, ok := app.storage.users[id]; ok {
|
base := time.Now()
|
||||||
app.storage.users[id] = expiry.AddDate(0, req.Months, req.Days).Add(time.Duration(((60 * req.Hours) + req.Minutes)) * time.Minute)
|
if expiry, ok := app.storage.GetUserExpiryKey(id); ok {
|
||||||
|
base = expiry.Expiry
|
||||||
app.debug.Printf("Expiry extended for \"%s\"", id)
|
app.debug.Printf("Expiry extended for \"%s\"", id)
|
||||||
} else {
|
} 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)
|
app.debug.Printf("Created expiry for \"%s\"", id)
|
||||||
}
|
}
|
||||||
}
|
expiry := UserExpiry{Expiry: base.AddDate(0, req.Months, req.Days).Add(time.Duration(((60 * req.Hours) + req.Minutes)) * time.Minute)}
|
||||||
if err := app.storage.storeUsers(); err != nil {
|
app.storage.SetUserExpiryKey(id, expiry)
|
||||||
app.err.Printf("Failed to store user duration: %v", err)
|
|
||||||
respondBool(500, false, gc)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
respondBool(204, true, gc)
|
respondBool(204, true, gc)
|
||||||
}
|
}
|
||||||
@ -727,27 +696,21 @@ func (app *appContext) SaveAnnounceTemplate(gc *gin.Context) {
|
|||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
app.storage.announcements[req.Name] = req
|
|
||||||
if err := app.storage.storeAnnouncements(); err != nil {
|
app.storage.SetAnnouncementsKey(req.Name, req)
|
||||||
respondBool(500, false, gc)
|
|
||||||
app.err.Printf("Failed to store announcement templates: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Save an announcement as a template for use or editing later.
|
// @Summary Save an announcement as a template for use or editing later.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} getAnnouncementsDTO
|
// @Success 200 {object} getAnnouncementsDTO
|
||||||
// @Router /users/announce/template [get]
|
// @Router /users/announce [get]
|
||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
// @tags Users
|
// @tags Users
|
||||||
func (app *appContext) GetAnnounceTemplates(gc *gin.Context) {
|
func (app *appContext) GetAnnounceTemplates(gc *gin.Context) {
|
||||||
resp := &getAnnouncementsDTO{make([]string, len(app.storage.announcements))}
|
resp := &getAnnouncementsDTO{make([]string, len(app.storage.GetAnnouncements()))}
|
||||||
i := 0
|
for i, a := range app.storage.GetAnnouncements() {
|
||||||
for name := range app.storage.announcements {
|
resp.Announcements[i] = a.Name
|
||||||
resp.Announcements[i] = name
|
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
gc.JSON(200, resp)
|
gc.JSON(200, resp)
|
||||||
}
|
}
|
||||||
@ -762,7 +725,7 @@ func (app *appContext) GetAnnounceTemplates(gc *gin.Context) {
|
|||||||
// @tags Users
|
// @tags Users
|
||||||
func (app *appContext) GetAnnounceTemplate(gc *gin.Context) {
|
func (app *appContext) GetAnnounceTemplate(gc *gin.Context) {
|
||||||
name := gc.Param("name")
|
name := gc.Param("name")
|
||||||
if announcement, ok := app.storage.announcements[name]; ok {
|
if announcement, ok := app.storage.GetAnnouncementsKey(name); ok {
|
||||||
gc.JSON(200, announcement)
|
gc.JSON(200, announcement)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -779,12 +742,7 @@ func (app *appContext) GetAnnounceTemplate(gc *gin.Context) {
|
|||||||
// @tags Users
|
// @tags Users
|
||||||
func (app *appContext) DeleteAnnounceTemplate(gc *gin.Context) {
|
func (app *appContext) DeleteAnnounceTemplate(gc *gin.Context) {
|
||||||
name := gc.Param("name")
|
name := gc.Param("name")
|
||||||
delete(app.storage.announcements, name)
|
app.storage.DeleteAnnouncementsKey(name)
|
||||||
if err := app.storage.storeAnnouncements(); err != nil {
|
|
||||||
respondBool(500, false, gc)
|
|
||||||
app.err.Printf("Failed to store announcement templates: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
respondBool(200, false, gc)
|
respondBool(200, false, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -876,8 +834,6 @@ func (app *appContext) GetUsers(gc *gin.Context) {
|
|||||||
adminOnly := app.config.Section("ui").Key("admin_only").MustBool(true)
|
adminOnly := app.config.Section("ui").Key("admin_only").MustBool(true)
|
||||||
allowAll := app.config.Section("ui").Key("allow_all").MustBool(false)
|
allowAll := app.config.Section("ui").Key("allow_all").MustBool(false)
|
||||||
i := 0
|
i := 0
|
||||||
app.storage.usersLock.Lock()
|
|
||||||
defer app.storage.usersLock.Unlock()
|
|
||||||
for _, jfUser := range users {
|
for _, jfUser := range users {
|
||||||
user := respUser{
|
user := respUser{
|
||||||
ID: jfUser.ID,
|
ID: jfUser.ID,
|
||||||
@ -894,9 +850,9 @@ func (app *appContext) GetUsers(gc *gin.Context) {
|
|||||||
user.Label = email.Label
|
user.Label = email.Label
|
||||||
user.AccountsAdmin = (app.jellyfinLogin) && (email.Admin || (adminOnly && jfUser.Policy.IsAdministrator) || allowAll)
|
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 {
|
if ok {
|
||||||
user.Expiry = expiry.Unix()
|
user.Expiry = expiry.Expiry.Unix()
|
||||||
}
|
}
|
||||||
if tgUser, ok := app.storage.GetTelegramKey(jfUser.ID); ok {
|
if tgUser, ok := app.storage.GetTelegramKey(jfUser.ID); ok {
|
||||||
user.Telegram = tgUser.Username
|
user.Telegram = tgUser.Username
|
||||||
@ -947,10 +903,6 @@ func (app *appContext) SetAccountsAdmin(gc *gin.Context) {
|
|||||||
app.storage.SetEmailsKey(id, emailStore)
|
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")
|
app.info.Println("Email list modified")
|
||||||
respondBool(204, true, gc)
|
respondBool(204, true, gc)
|
||||||
}
|
}
|
||||||
@ -984,10 +936,6 @@ func (app *appContext) ModifyLabels(gc *gin.Context) {
|
|||||||
app.storage.SetEmailsKey(id, emailStore)
|
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")
|
app.info.Println("Email list modified")
|
||||||
respondBool(204, true, gc)
|
respondBool(204, true, gc)
|
||||||
}
|
}
|
||||||
@ -1022,7 +970,6 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
|
|||||||
// Auto enable contact by email for newly added addresses
|
// Auto enable contact by email for newly added addresses
|
||||||
if !ok || oldEmail.Addr == "" {
|
if !ok || oldEmail.Addr == "" {
|
||||||
emailStore.Contact = true
|
emailStore.Contact = true
|
||||||
app.storage.storeEmails()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emailStore.Addr = address
|
emailStore.Addr = address
|
||||||
@ -1039,7 +986,6 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.storage.storeEmails()
|
|
||||||
app.info.Println("Email list modified")
|
app.info.Println("Email list modified")
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
@ -1062,25 +1008,24 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
var displayprefs map[string]interface{}
|
var displayprefs map[string]interface{}
|
||||||
var ombi map[string]interface{}
|
var ombi map[string]interface{}
|
||||||
if req.From == "profile" {
|
if req.From == "profile" {
|
||||||
app.storage.loadProfiles()
|
|
||||||
// Check profile exists & isn't empty
|
// Check profile exists & isn't empty
|
||||||
if _, ok := app.storage.profiles[req.Profile]; !ok || app.storage.profiles[req.Profile].Policy.BlockedTags == nil {
|
profile, ok := app.storage.GetProfileKey(req.Profile)
|
||||||
|
if !ok || profile.Policy.BlockedTags == nil {
|
||||||
app.err.Printf("Couldn't find profile \"%s\" or profile was empty", req.Profile)
|
app.err.Printf("Couldn't find profile \"%s\" or profile was empty", req.Profile)
|
||||||
respond(500, "Couldn't find profile", gc)
|
respond(500, "Couldn't find profile", gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if req.Homescreen {
|
if req.Homescreen {
|
||||||
if app.storage.profiles[req.Profile].Configuration.GroupedFolders == nil || len(app.storage.profiles[req.Profile].Displayprefs) == 0 {
|
if profile.Configuration.GroupedFolders == nil || len(profile.Displayprefs) == 0 {
|
||||||
app.err.Printf("No homescreen saved in profile \"%s\"", req.Profile)
|
app.err.Printf("No homescreen saved in profile \"%s\"", req.Profile)
|
||||||
respond(500, "No homescreen template available", gc)
|
respond(500, "No homescreen template available", gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
configuration = app.storage.profiles[req.Profile].Configuration
|
configuration = profile.Configuration
|
||||||
displayprefs = app.storage.profiles[req.Profile].Displayprefs
|
displayprefs = profile.Displayprefs
|
||||||
}
|
}
|
||||||
policy = app.storage.profiles[req.Profile].Policy
|
policy = profile.Policy
|
||||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
profile := app.storage.profiles[req.Profile]
|
|
||||||
if profile.Ombi != nil && len(profile.Ombi) != 0 {
|
if profile.Ombi != nil && len(profile.Ombi) != 0 {
|
||||||
ombi = profile.Ombi
|
ombi = profile.Ombi
|
||||||
}
|
}
|
||||||
|
@ -157,15 +157,6 @@ func (app *appContext) loadConfig() error {
|
|||||||
app.MustSetValue("updates", "channel", releaseChannel)
|
app.MustSetValue("updates", "channel", releaseChannel)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.storage.customEmails_path = app.config.Section("files").Key("custom_emails").String()
|
|
||||||
app.storage.loadCustomEmails()
|
|
||||||
|
|
||||||
app.MustSetValue("user_page", "enabled", "true")
|
|
||||||
if app.config.Section("user_page").Key("enabled").MustBool(false) {
|
|
||||||
app.storage.userPage_path = app.config.Section("files").Key("custom_user_page_content").String()
|
|
||||||
app.storage.loadUserPageContent()
|
|
||||||
}
|
|
||||||
|
|
||||||
substituteStrings = app.config.Section("jellyfin").Key("substitute_jellyfin_strings").MustString("")
|
substituteStrings = app.config.Section("jellyfin").Key("substitute_jellyfin_strings").MustString("")
|
||||||
|
|
||||||
if substituteStrings != "" {
|
if substituteStrings != "" {
|
||||||
|
81
daemon.go
81
daemon.go
@ -7,85 +7,53 @@ import "time"
|
|||||||
// the user cache is fresh.
|
// the user cache is fresh.
|
||||||
func (app *appContext) clearEmails() {
|
func (app *appContext) clearEmails() {
|
||||||
app.debug.Println("Housekeeping: removing unused email addresses")
|
app.debug.Println("Housekeeping: removing unused email addresses")
|
||||||
users, status, err := app.jf.GetUsers(false)
|
emails := app.storage.GetEmails()
|
||||||
if status != 200 || err != nil || len(users) == 0 {
|
for _, email := range emails {
|
||||||
app.err.Printf("Failed to get users from Jellyfin (%d): %v", status, err)
|
_, status, err := app.jf.UserByID(email.JellyfinID, false)
|
||||||
return
|
if status == 200 && err != nil {
|
||||||
}
|
continue
|
||||||
// Rebuild email storage to from existing users to reduce time complexity
|
|
||||||
emails := emailStore{}
|
|
||||||
app.storage.emailsLock.Lock()
|
|
||||||
for _, user := range users {
|
|
||||||
if email, ok := app.storage.GetEmailsKey(user.ID); ok {
|
|
||||||
emails[user.ID] = email
|
|
||||||
}
|
}
|
||||||
|
app.storage.DeleteEmailsKey(email.JellyfinID)
|
||||||
}
|
}
|
||||||
app.storage.emails = emails
|
|
||||||
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.
|
||||||
func (app *appContext) clearDiscord() {
|
func (app *appContext) clearDiscord() {
|
||||||
app.debug.Println("Housekeeping: removing unused Discord IDs")
|
app.debug.Println("Housekeeping: removing unused Discord IDs")
|
||||||
users, status, err := app.jf.GetUsers(false)
|
discordUsers := app.storage.GetDiscord()
|
||||||
if status != 200 || err != nil || len(users) == 0 {
|
for _, discordUser := range discordUsers {
|
||||||
app.err.Printf("Failed to get users from Jellyfin (%d): %v", status, err)
|
_, status, err := app.jf.UserByID(discordUser.JellyfinID, false)
|
||||||
return
|
if status == 200 && err != nil {
|
||||||
}
|
continue
|
||||||
// Rebuild discord storage to from existing users to reduce time complexity
|
|
||||||
dcUsers := discordStore{}
|
|
||||||
app.storage.discordLock.Lock()
|
|
||||||
for _, user := range users {
|
|
||||||
if dcUser, ok := app.storage.GetDiscordKey(user.ID); ok {
|
|
||||||
dcUsers[user.ID] = dcUser
|
|
||||||
}
|
}
|
||||||
|
app.storage.DeleteDiscordKey(discordUser.JellyfinID)
|
||||||
}
|
}
|
||||||
app.storage.discord = dcUsers
|
|
||||||
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.
|
||||||
func (app *appContext) clearMatrix() {
|
func (app *appContext) clearMatrix() {
|
||||||
app.debug.Println("Housekeeping: removing unused Matrix IDs")
|
app.debug.Println("Housekeeping: removing unused Matrix IDs")
|
||||||
users, status, err := app.jf.GetUsers(false)
|
matrixUsers := app.storage.GetMatrix()
|
||||||
if status != 200 || err != nil || len(users) == 0 {
|
for _, matrixUser := range matrixUsers {
|
||||||
app.err.Printf("Failed to get users from Jellyfin (%d): %v", status, err)
|
_, status, err := app.jf.UserByID(matrixUser.JellyfinID, false)
|
||||||
return
|
if status == 200 && err != nil {
|
||||||
}
|
continue
|
||||||
// Rebuild matrix storage to from existing users to reduce time complexity
|
|
||||||
mxUsers := matrixStore{}
|
|
||||||
app.storage.matrixLock.Lock()
|
|
||||||
for _, user := range users {
|
|
||||||
if mxUser, ok := app.storage.GetMatrixKey(user.ID); ok {
|
|
||||||
mxUsers[user.ID] = mxUser
|
|
||||||
}
|
}
|
||||||
|
app.storage.DeleteMatrixKey(matrixUser.JellyfinID)
|
||||||
}
|
}
|
||||||
app.storage.matrix = mxUsers
|
|
||||||
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.
|
||||||
func (app *appContext) clearTelegram() {
|
func (app *appContext) clearTelegram() {
|
||||||
app.debug.Println("Housekeeping: removing unused Telegram IDs")
|
app.debug.Println("Housekeeping: removing unused Telegram IDs")
|
||||||
users, status, err := app.jf.GetUsers(false)
|
telegramUsers := app.storage.GetTelegram()
|
||||||
if status != 200 || err != nil || len(users) == 0 {
|
for _, telegramUser := range telegramUsers {
|
||||||
app.err.Printf("Failed to get users from Jellyfin (%d): %v", status, err)
|
_, status, err := app.jf.UserByID(telegramUser.JellyfinID, false)
|
||||||
return
|
if status == 200 && err != nil {
|
||||||
}
|
continue
|
||||||
// Rebuild telegram storage to from existing users to reduce time complexity
|
|
||||||
tgUsers := telegramStore{}
|
|
||||||
app.storage.telegramLock.Lock()
|
|
||||||
for _, user := range users {
|
|
||||||
if tgUser, ok := app.storage.GetTelegramKey(user.ID); ok {
|
|
||||||
tgUsers[user.ID] = tgUser
|
|
||||||
}
|
}
|
||||||
|
app.storage.DeleteTelegramKey(telegramUser.JellyfinID)
|
||||||
}
|
}
|
||||||
app.storage.telegram = tgUsers
|
|
||||||
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
|
||||||
@ -148,7 +116,6 @@ func (rt *housekeepingDaemon) run() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
started := time.Now()
|
started := time.Now()
|
||||||
rt.app.storage.loadInvites()
|
|
||||||
|
|
||||||
for _, job := range rt.jobs {
|
for _, job := range rt.jobs {
|
||||||
job(rt.app)
|
job(rt.app)
|
||||||
|
21
discord.go
21
discord.go
@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
dg "github.com/bwmarrin/discordgo"
|
dg "github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/timshannon/badgerhold/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DiscordDaemon struct {
|
type DiscordDaemon struct {
|
||||||
@ -478,11 +479,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.GetDiscord() {
|
for _, 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.SetDiscordKey(jfID, u)
|
d.app.storage.SetDiscordKey(u.JellyfinID, u)
|
||||||
user = u
|
user = u
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -585,10 +586,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.GetDiscord() {
|
for _, 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.SetDiscordKey(jfID, u)
|
d.app.storage.SetDiscordKey(u.JellyfinID, u)
|
||||||
user = u
|
user = u
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -708,15 +709,9 @@ func (d *DiscordDaemon) AssignedUserVerified(pin string, jfID string) (user Disc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UserExists returns whether or not a user with the given ID exists.
|
// UserExists returns whether or not a user with the given ID exists.
|
||||||
func (d *DiscordDaemon) UserExists(id string) (ok bool) {
|
func (d *DiscordDaemon) UserExists(id string) bool {
|
||||||
ok = false
|
c, err := d.app.storage.db.Count(&DiscordUser{}, badgerhold.Where("ID").Eq(id))
|
||||||
for _, u := range d.app.storage.GetDiscord() {
|
return err != nil || c > 0
|
||||||
if u.ID == id {
|
|
||||||
ok = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteVerifiedUser removes the token with the given PIN.
|
// DeleteVerifiedUser removes the token with the given PIN.
|
||||||
|
136
email.go
136
email.go
@ -19,8 +19,10 @@ import (
|
|||||||
|
|
||||||
"github.com/gomarkdown/markdown"
|
"github.com/gomarkdown/markdown"
|
||||||
"github.com/gomarkdown/markdown/html"
|
"github.com/gomarkdown/markdown/html"
|
||||||
|
"github.com/hrfee/mediabrowser"
|
||||||
"github.com/itchyny/timefmt-go"
|
"github.com/itchyny/timefmt-go"
|
||||||
"github.com/mailgun/mailgun-go/v4"
|
"github.com/mailgun/mailgun-go/v4"
|
||||||
|
"github.com/timshannon/badgerhold/v4"
|
||||||
sMail "github.com/xhit/go-simple-mail/v2"
|
sMail "github.com/xhit/go-simple-mail/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -329,10 +331,11 @@ func (emailer *Emailer) constructConfirmation(code, username, key string, app *a
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
template := emailer.confirmationValues(code, username, key, app, noSub)
|
template := emailer.confirmationValues(code, username, key, app, noSub)
|
||||||
if app.storage.customEmails.EmailConfirmation.Enabled {
|
message := app.storage.MustGetCustomContentKey("EmailConfirmation")
|
||||||
|
if message.Enabled {
|
||||||
content := templateEmail(
|
content := templateEmail(
|
||||||
app.storage.customEmails.EmailConfirmation.Content,
|
message.Content,
|
||||||
app.storage.customEmails.EmailConfirmation.Variables,
|
message.Variables,
|
||||||
nil,
|
nil,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
@ -412,10 +415,11 @@ func (emailer *Emailer) constructInvite(code string, invite Invite, app *appCont
|
|||||||
}
|
}
|
||||||
template := emailer.inviteValues(code, invite, app, noSub)
|
template := emailer.inviteValues(code, invite, app, noSub)
|
||||||
var err error
|
var err error
|
||||||
if app.storage.customEmails.InviteEmail.Enabled {
|
message := app.storage.MustGetCustomContentKey("InviteEmail")
|
||||||
|
if message.Enabled {
|
||||||
content := templateEmail(
|
content := templateEmail(
|
||||||
app.storage.customEmails.InviteEmail.Content,
|
message.Content,
|
||||||
app.storage.customEmails.InviteEmail.Variables,
|
message.Variables,
|
||||||
nil,
|
nil,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
@ -451,10 +455,11 @@ func (emailer *Emailer) constructExpiry(code string, invite Invite, app *appCont
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
template := emailer.expiryValues(code, invite, app, noSub)
|
template := emailer.expiryValues(code, invite, app, noSub)
|
||||||
if app.storage.customEmails.InviteExpiry.Enabled {
|
message := app.storage.MustGetCustomContentKey("InviteExpiry")
|
||||||
|
if message.Enabled {
|
||||||
content := templateEmail(
|
content := templateEmail(
|
||||||
app.storage.customEmails.InviteExpiry.Content,
|
message.Content,
|
||||||
app.storage.customEmails.InviteExpiry.Variables,
|
message.Variables,
|
||||||
nil,
|
nil,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
@ -505,10 +510,11 @@ func (emailer *Emailer) constructCreated(code, username, address string, invite
|
|||||||
}
|
}
|
||||||
template := emailer.createdValues(code, username, address, invite, app, noSub)
|
template := emailer.createdValues(code, username, address, invite, app, noSub)
|
||||||
var err error
|
var err error
|
||||||
if app.storage.customEmails.UserCreated.Enabled {
|
message := app.storage.MustGetCustomContentKey("UserCreated")
|
||||||
|
if message.Enabled {
|
||||||
content := templateEmail(
|
content := templateEmail(
|
||||||
app.storage.customEmails.UserCreated.Content,
|
message.Content,
|
||||||
app.storage.customEmails.UserCreated.Variables,
|
message.Variables,
|
||||||
nil,
|
nil,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
@ -578,10 +584,11 @@ func (emailer *Emailer) constructReset(pwr PasswordReset, app *appContext, noSub
|
|||||||
}
|
}
|
||||||
template := emailer.resetValues(pwr, app, noSub)
|
template := emailer.resetValues(pwr, app, noSub)
|
||||||
var err error
|
var err error
|
||||||
if app.storage.customEmails.PasswordReset.Enabled {
|
message := app.storage.MustGetCustomContentKey("PasswordReset")
|
||||||
|
if message.Enabled {
|
||||||
content := templateEmail(
|
content := templateEmail(
|
||||||
app.storage.customEmails.PasswordReset.Content,
|
message.Content,
|
||||||
app.storage.customEmails.PasswordReset.Variables,
|
message.Variables,
|
||||||
nil,
|
nil,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
@ -619,10 +626,11 @@ func (emailer *Emailer) constructDeleted(reason string, app *appContext, noSub b
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
template := emailer.deletedValues(reason, app, noSub)
|
template := emailer.deletedValues(reason, app, noSub)
|
||||||
if app.storage.customEmails.UserDeleted.Enabled {
|
message := app.storage.MustGetCustomContentKey("UserDeleted")
|
||||||
|
if message.Enabled {
|
||||||
content := templateEmail(
|
content := templateEmail(
|
||||||
app.storage.customEmails.UserDeleted.Content,
|
message.Content,
|
||||||
app.storage.customEmails.UserDeleted.Variables,
|
message.Variables,
|
||||||
nil,
|
nil,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
@ -660,10 +668,11 @@ func (emailer *Emailer) constructDisabled(reason string, app *appContext, noSub
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
template := emailer.disabledValues(reason, app, noSub)
|
template := emailer.disabledValues(reason, app, noSub)
|
||||||
if app.storage.customEmails.UserDisabled.Enabled {
|
message := app.storage.MustGetCustomContentKey("UserDisabled")
|
||||||
|
if message.Enabled {
|
||||||
content := templateEmail(
|
content := templateEmail(
|
||||||
app.storage.customEmails.UserDisabled.Content,
|
message.Content,
|
||||||
app.storage.customEmails.UserDisabled.Variables,
|
message.Variables,
|
||||||
nil,
|
nil,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
@ -701,10 +710,11 @@ func (emailer *Emailer) constructEnabled(reason string, app *appContext, noSub b
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
template := emailer.enabledValues(reason, app, noSub)
|
template := emailer.enabledValues(reason, app, noSub)
|
||||||
if app.storage.customEmails.UserEnabled.Enabled {
|
message := app.storage.MustGetCustomContentKey("UserEnabled")
|
||||||
|
if message.Enabled {
|
||||||
content := templateEmail(
|
content := templateEmail(
|
||||||
app.storage.customEmails.UserEnabled.Content,
|
message.Content,
|
||||||
app.storage.customEmails.UserEnabled.Variables,
|
message.Variables,
|
||||||
nil,
|
nil,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
@ -756,7 +766,8 @@ func (emailer *Emailer) constructWelcome(username string, expiry time.Time, app
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
var template map[string]interface{}
|
var template map[string]interface{}
|
||||||
if app.storage.customEmails.WelcomeEmail.Enabled {
|
message := app.storage.MustGetCustomContentKey("WelcomeEmail")
|
||||||
|
if message.Enabled {
|
||||||
template = emailer.welcomeValues(username, expiry, app, noSub, true)
|
template = emailer.welcomeValues(username, expiry, app, noSub, true)
|
||||||
} else {
|
} else {
|
||||||
template = emailer.welcomeValues(username, expiry, app, noSub, false)
|
template = emailer.welcomeValues(username, expiry, app, noSub, false)
|
||||||
@ -766,11 +777,11 @@ func (emailer *Emailer) constructWelcome(username string, expiry time.Time, app
|
|||||||
"date": "{yourAccountWillExpire}",
|
"date": "{yourAccountWillExpire}",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if app.storage.customEmails.WelcomeEmail.Enabled {
|
if message.Enabled {
|
||||||
content := templateEmail(
|
content := templateEmail(
|
||||||
app.storage.customEmails.WelcomeEmail.Content,
|
message.Content,
|
||||||
app.storage.customEmails.WelcomeEmail.Variables,
|
message.Variables,
|
||||||
app.storage.customEmails.WelcomeEmail.Conditionals,
|
message.Conditionals,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
email, err = emailer.constructTemplate(email.Subject, content, app)
|
email, err = emailer.constructTemplate(email.Subject, content, app)
|
||||||
@ -801,10 +812,11 @@ func (emailer *Emailer) constructUserExpired(app *appContext, noSub bool) (*Mess
|
|||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
template := emailer.userExpiredValues(app, noSub)
|
template := emailer.userExpiredValues(app, noSub)
|
||||||
if app.storage.customEmails.UserExpired.Enabled {
|
message := app.storage.MustGetCustomContentKey("UserExpired")
|
||||||
|
if message.Enabled {
|
||||||
content := templateEmail(
|
content := templateEmail(
|
||||||
app.storage.customEmails.UserExpired.Content,
|
message.Content,
|
||||||
app.storage.customEmails.UserExpired.Variables,
|
message.Variables,
|
||||||
nil,
|
nil,
|
||||||
template,
|
template,
|
||||||
)
|
)
|
||||||
@ -874,31 +886,63 @@ func (app *appContext) getAddressOrName(jfID string) string {
|
|||||||
|
|
||||||
// ReverseUserSearch returns the jellyfin ID of the user with the given username, email, or contact method username.
|
// ReverseUserSearch returns the jellyfin ID of the user with the given username, email, or contact method username.
|
||||||
// returns "" if none found. returns only the first match, might be an issue if there are users with the same contact method usernames.
|
// returns "" if none found. returns only the first match, might be an issue if there are users with the same contact method usernames.
|
||||||
func (app *appContext) ReverseUserSearch(address string) string {
|
func (app *appContext) ReverseUserSearch(address string) (user mediabrowser.User, ok bool) {
|
||||||
|
ok = false
|
||||||
user, status, err := app.jf.UserByName(address, false)
|
user, status, err := app.jf.UserByName(address, false)
|
||||||
if status == 200 && err == nil {
|
if status == 200 && err == nil {
|
||||||
return user.ID
|
ok = true
|
||||||
|
return
|
||||||
}
|
}
|
||||||
for id, email := range app.storage.GetEmails() {
|
emailAddresses := []EmailAddress{}
|
||||||
if strings.ToLower(address) == strings.ToLower(email.Addr) {
|
err = app.storage.db.Find(&emailAddresses, badgerhold.Where("Addr").Eq(address))
|
||||||
return id
|
if err == nil && len(emailAddresses) > 0 {
|
||||||
|
for _, emailUser := range emailAddresses {
|
||||||
|
user, status, err = app.jf.UserByID(emailUser.JellyfinID, false)
|
||||||
|
if status == 200 && err == nil {
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for id, dcUser := range app.storage.GetDiscord() {
|
// Dont know how we'd use badgerhold when we need to render each username,
|
||||||
|
// Apart from storing the rendered name in the db.
|
||||||
|
for _, dcUser := range app.storage.GetDiscord() {
|
||||||
if RenderDiscordUsername(dcUser) == strings.ToLower(address) {
|
if RenderDiscordUsername(dcUser) == strings.ToLower(address) {
|
||||||
return id
|
user, status, err = app.jf.UserByID(dcUser.JellyfinID, false)
|
||||||
|
if status == 200 && err == nil {
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tgUsername := strings.TrimPrefix(address, "@")
|
tgUsername := strings.TrimPrefix(address, "@")
|
||||||
for id, tgUser := range app.storage.GetTelegram() {
|
telegramUsers := []TelegramUser{}
|
||||||
if tgUsername == tgUser.Username {
|
err = app.storage.db.Find(&telegramUsers, badgerhold.Where("Username").Eq(tgUsername))
|
||||||
return id
|
if err == nil && len(telegramUsers) > 0 {
|
||||||
|
for _, telegramUser := range telegramUsers {
|
||||||
|
user, status, err = app.jf.UserByID(telegramUser.JellyfinID, false)
|
||||||
|
if status == 200 && err == nil {
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for id, mxUser := range app.storage.GetMatrix() {
|
matrixUsers := []MatrixUser{}
|
||||||
if address == mxUser.UserID {
|
err = app.storage.db.Find(&matrixUsers, badgerhold.Where("UserID").Eq(address))
|
||||||
return id
|
if err == nil && len(matrixUsers) > 0 {
|
||||||
|
for _, matrixUser := range matrixUsers {
|
||||||
|
user, status, err = app.jf.UserByID(matrixUser.JellyfinID, false)
|
||||||
|
if status == 200 && err == nil {
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ""
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmailAddressExists returns whether or not a user with the given email address exists.
|
||||||
|
func (app *appContext) EmailAddressExists(address string) bool {
|
||||||
|
c, err := app.storage.db.Count(&EmailAddress{}, badgerhold.Where("Addr").Eq(address))
|
||||||
|
return err != nil || c > 0
|
||||||
}
|
}
|
||||||
|
14
go.mod
14
go.mod
@ -48,7 +48,12 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/bytedance/sonic v1.9.1 // indirect
|
github.com/bytedance/sonic v1.9.1 // indirect
|
||||||
|
github.com/cespare/xxhash v1.1.0 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
|
github.com/dgraph-io/badger/v3 v3.2103.1 // indirect
|
||||||
|
github.com/dgraph-io/ristretto v0.1.0 // indirect
|
||||||
|
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
github.com/getlantern/context v0.0.0-20220418194847-3d5e7a086201 // indirect
|
github.com/getlantern/context v0.0.0-20220418194847-3d5e7a086201 // indirect
|
||||||
github.com/getlantern/errors v1.0.3 // indirect
|
github.com/getlantern/errors v1.0.3 // indirect
|
||||||
@ -69,12 +74,19 @@ require (
|
|||||||
github.com/go-stack/stack v1.8.1 // indirect
|
github.com/go-stack/stack v1.8.1 // indirect
|
||||||
github.com/go-test/deep v1.1.0 // indirect
|
github.com/go-test/deep v1.1.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
|
github.com/golang/glog v0.0.0-20210429001901-424d2337a529 // indirect
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
github.com/google/flatbuffers v2.0.0+incompatible // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/gorilla/mux v1.8.0 // indirect
|
github.com/gorilla/mux v1.8.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/compress v1.13.1 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
@ -92,9 +104,11 @@ require (
|
|||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.1 // indirect
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
github.com/tidwall/sjson v1.2.5 // indirect
|
github.com/tidwall/sjson v1.2.5 // indirect
|
||||||
|
github.com/timshannon/badgerhold/v4 v4.0.2 // indirect
|
||||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
|
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
|
go.opencensus.io v0.23.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.16.0 // indirect
|
go.opentelemetry.io/otel/metric v1.16.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||||
|
149
go.sum
149
go.sum
@ -1,11 +1,14 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY=
|
github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY=
|
||||||
@ -13,17 +16,39 @@ github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0
|
|||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgraph-io/badger/v3 v3.2103.1 h1:zaX53IRg7ycxVlkd5pYdCeFp1FynD6qBGQoQql3R3Hk=
|
||||||
|
github.com/dgraph-io/badger/v3 v3.2103.1/go.mod h1:dULbq6ehJ5K0cGW/1TQ9iSfUk0gbSiToDWmWmTsJ53E=
|
||||||
|
github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI=
|
||||||
|
github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug=
|
||||||
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||||
|
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||||
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:M88ob4TyDnEqNuL3PgsE/p3bDujfspnulR+0dQWNYZs=
|
github.com/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:M88ob4TyDnEqNuL3PgsE/p3bDujfspnulR+0dQWNYZs=
|
||||||
github.com/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:buzQsO8HHkZX2Q45fdfGH1xejPjuDQaXH8btcYMFzPM=
|
github.com/emersion/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:buzQsO8HHkZX2Q45fdfGH1xejPjuDQaXH8btcYMFzPM=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
||||||
@ -33,6 +58,7 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+ne
|
|||||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||||
@ -131,20 +157,54 @@ github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGF
|
|||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/glog v0.0.0-20210429001901-424d2337a529 h1:2voWjNECnrZRbfwXxHB1/j8wa6xdKn85B5NzgVL/pTU=
|
||||||
|
github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a h1:AWZzzFrqyjYlRloN6edwTLTUbKxf5flLXNuTBDm3Ews=
|
github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a h1:AWZzzFrqyjYlRloN6edwTLTUbKxf5flLXNuTBDm3Ews=
|
||||||
github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
|
github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
|
||||||
|
github.com/google/flatbuffers v1.12.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||||
|
github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI=
|
||||||
|
github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
@ -153,8 +213,10 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
|
|||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hrfee/mediabrowser v0.3.8 h1:y0iBCb6jE3QKcsiCJSYva2fFPHRn4UA+sGRzoPuJ/Dk=
|
github.com/hrfee/mediabrowser v0.3.8 h1:y0iBCb6jE3QKcsiCJSYva2fFPHRn4UA+sGRzoPuJ/Dk=
|
||||||
github.com/hrfee/mediabrowser v0.3.8/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=
|
github.com/hrfee/mediabrowser v0.3.8/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
|
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
|
||||||
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
|
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
@ -165,6 +227,11 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
|
|||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||||
|
github.com/klauspost/compress v1.13.1 h1:wXr2uRxZTJXHLly6qhJabee5JqIhTRoLBhDOA74hDEQ=
|
||||||
|
github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
@ -185,6 +252,7 @@ github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJV
|
|||||||
github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts=
|
github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts=
|
||||||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
|
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
|
||||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||||
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mailgun/mailgun-go/v4 v4.9.0 h1:wRbxvVQ5QObFewLxc1uVvipA16D8gxeiO+cBOca51Iw=
|
github.com/mailgun/mailgun-go/v4 v4.9.0 h1:wRbxvVQ5QObFewLxc1uVvipA16D8gxeiO+cBOca51Iw=
|
||||||
github.com/mailgun/mailgun-go/v4 v4.9.0/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40=
|
github.com/mailgun/mailgun-go/v4 v4.9.0/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40=
|
||||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
@ -206,6 +274,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
|||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@ -216,6 +286,7 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
|
|||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||||
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||||
@ -225,6 +296,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/robert-nix/ansihtml v1.0.1 h1:VTiyQ6/+AxSJoSSLsMecnkh8i0ZqOEdiRl/odOc64fc=
|
github.com/robert-nix/ansihtml v1.0.1 h1:VTiyQ6/+AxSJoSSLsMecnkh8i0ZqOEdiRl/odOc64fc=
|
||||||
github.com/robert-nix/ansihtml v1.0.1/go.mod h1:CJwclxYaTPc2RfcxtanEACsYuTksh4yDXcNeHHKZINE=
|
github.com/robert-nix/ansihtml v1.0.1/go.mod h1:CJwclxYaTPc2RfcxtanEACsYuTksh4yDXcNeHHKZINE=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
@ -233,10 +305,19 @@ github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6po
|
|||||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
|
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
|
||||||
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
|
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
|
||||||
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||||
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
github.com/steambap/captcha v1.4.1 h1:OmMdxLCWCqJvsFaFYwRpvMckIuvI6s8s1LsBrBw97P0=
|
github.com/steambap/captcha v1.4.1 h1:OmMdxLCWCqJvsFaFYwRpvMckIuvI6s8s1LsBrBw97P0=
|
||||||
github.com/steambap/captcha v1.4.1/go.mod h1:oC9T7IfEgnrhzjDz5Djf1H7GPffCzRMbsQfFkJmhlnk=
|
github.com/steambap/captcha v1.4.1/go.mod h1:oC9T7IfEgnrhzjDz5Djf1H7GPffCzRMbsQfFkJmhlnk=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@ -276,6 +357,9 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
|||||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||||
|
github.com/timshannon/badgerhold/v3 v3.0.0-20210909134927-2b6764d68c1e/go.mod h1:/Seq5xGNo8jLhSbDX3jdbeZrp4yFIpQ6/7n4TjziEWs=
|
||||||
|
github.com/timshannon/badgerhold/v4 v4.0.2 h1:83OLY/NFnEaMnHEPd84bYtkLipVkjTsMbzQRYbk47g4=
|
||||||
|
github.com/timshannon/badgerhold/v4 v4.0.2/go.mod h1:rh6RyXLQFsvrvcKondPQQFZnNovpRzu+gS0FlLxYuHY=
|
||||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM=
|
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 h1:PM5hJF7HVfNWmCjMdEfbuOBNXSVF2cMFGgQTPdKCbwM=
|
||||||
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
|
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208/go.mod h1:BzWtXXrXzZUvMacR0oF/fbDDgUPO8L36tDMmRAf14ns=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
@ -285,6 +369,7 @@ github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/o
|
|||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
|
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||||
@ -296,8 +381,14 @@ github.com/writeas/go-strip-markdown v2.0.1+incompatible h1:IIqxTM5Jr7RzhigcL6Fk
|
|||||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE=
|
github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE=
|
||||||
github.com/xhit/go-simple-mail/v2 v2.13.0 h1:OANWU9jHZrVfBkNkvLf8Ww0fexwpQVF/v/5f96fFTLI=
|
github.com/xhit/go-simple-mail/v2 v2.13.0 h1:OANWU9jHZrVfBkNkvLf8Ww0fexwpQVF/v/5f96fFTLI=
|
||||||
github.com/xhit/go-simple-mail/v2 v2.13.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
|
github.com/xhit/go-simple-mail/v2 v2.13.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98=
|
||||||
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||||
|
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
||||||
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
go.opentelemetry.io/otel v1.9.0/go.mod h1:np4EoPGzoPs3O67xUVNoPPcmSvsfOxNlNA4F4AC+0Eo=
|
go.opentelemetry.io/otel v1.9.0/go.mod h1:np4EoPGzoPs3O67xUVNoPPcmSvsfOxNlNA4F4AC+0Eo=
|
||||||
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||||
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||||
@ -320,26 +411,37 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
|||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||||
golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw=
|
golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw=
|
||||||
golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg=
|
golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
@ -347,29 +449,45 @@ golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -396,11 +514,16 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
@ -410,13 +533,37 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
|
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
@ -435,6 +582,8 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
maunium.net/go/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8=
|
maunium.net/go/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8=
|
||||||
maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho=
|
maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho=
|
||||||
maunium.net/go/mautrix v0.15.2 h1:fUiVajeoOR92uJoSShHbCvh7uG6lDY4ZO4Mvt90LbjU=
|
maunium.net/go/mautrix v0.15.2 h1:fUiVajeoOR92uJoSShHbCvh7uG6lDY4ZO4Mvt90LbjU=
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
"ombiProfile": "Ombi user profile",
|
"ombiProfile": "Ombi user profile",
|
||||||
"ombiUserDefaultsDescription": "Create an Ombi user and configure it, then select it below. It's settings/permissions will be stored and applied to new Ombi users created by jfa-go when this profile is selected.",
|
"ombiUserDefaultsDescription": "Create an Ombi user and configure it, then select it below. It's settings/permissions will be stored and applied to new Ombi users created by jfa-go when this profile is selected.",
|
||||||
"userProfiles": "User Profiles",
|
"userProfiles": "User Profiles",
|
||||||
"userProfilesDescription": "Profiles are applied to users when they create an account. A profile include library access rights and homescreen layout.",
|
"userProfilesDescription": "Profiles are applied to users when they create an account. A profile includes library access rights and homescreen layout.",
|
||||||
"userProfilesIsDefault": "Default",
|
"userProfilesIsDefault": "Default",
|
||||||
"userProfilesLibraries": "Libraries",
|
"userProfilesLibraries": "Libraries",
|
||||||
"addProfile": "Add Profile",
|
"addProfile": "Add Profile",
|
||||||
|
56
main.go
56
main.go
@ -335,59 +335,8 @@ func start(asDaemon, firstCall bool) {
|
|||||||
|
|
||||||
app.debug.Printf("Loaded config file \"%s\"", app.configPath)
|
app.debug.Printf("Loaded config file \"%s\"", app.configPath)
|
||||||
|
|
||||||
app.debug.Println("Loading storage")
|
|
||||||
|
|
||||||
app.storage.invite_path = app.config.Section("files").Key("invites").String()
|
|
||||||
if err := app.storage.loadInvites(); err != nil {
|
|
||||||
app.err.Printf("Failed to load Invites: %v", err)
|
|
||||||
}
|
|
||||||
app.storage.emails_path = app.config.Section("files").Key("emails").String()
|
|
||||||
if err := app.storage.loadEmails(); err != nil {
|
|
||||||
app.err.Printf("Failed to load Emails: %v", err)
|
|
||||||
err := migrateEmailStorage(app)
|
|
||||||
if err != nil {
|
|
||||||
app.err.Printf("Failed to migrate Email storage: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.storage.policy_path = app.config.Section("files").Key("user_template").String()
|
|
||||||
if err := app.storage.loadPolicy(); err != nil {
|
|
||||||
app.err.Printf("Failed to load Policy: %v", err)
|
|
||||||
}
|
|
||||||
app.storage.configuration_path = app.config.Section("files").Key("user_configuration").String()
|
|
||||||
if err := app.storage.loadConfiguration(); err != nil {
|
|
||||||
app.err.Printf("Failed to load Configuration: %v", err)
|
|
||||||
}
|
|
||||||
app.storage.displayprefs_path = app.config.Section("files").Key("user_displayprefs").String()
|
|
||||||
if err := app.storage.loadDisplayprefs(); err != nil {
|
|
||||||
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 {
|
|
||||||
app.err.Printf("Failed to load Users: %v", err)
|
|
||||||
}
|
|
||||||
app.storage.telegram_path = app.config.Section("files").Key("telegram_users").String()
|
|
||||||
if err := app.storage.loadTelegramUsers(); err != nil {
|
|
||||||
app.err.Printf("Failed to load Telegram users: %v", err)
|
|
||||||
}
|
|
||||||
app.storage.discord_path = app.config.Section("files").Key("discord_users").String()
|
|
||||||
if err := app.storage.loadDiscordUsers(); err != nil {
|
|
||||||
app.err.Printf("Failed to load Discord users: %v", err)
|
|
||||||
}
|
|
||||||
app.storage.matrix_path = app.config.Section("files").Key("matrix_users").String()
|
|
||||||
if err := app.storage.loadMatrixUsers(); err != nil {
|
|
||||||
app.err.Printf("Failed to load Matrix users: %v", err)
|
|
||||||
}
|
|
||||||
app.storage.announcements_path = app.config.Section("files").Key("announcements").String()
|
|
||||||
if err := app.storage.loadAnnouncements(); err != nil {
|
|
||||||
app.err.Printf("Failed to load announcement templates: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
app.storage.profiles_path = app.config.Section("files").Key("user_profiles").String()
|
|
||||||
app.storage.loadProfiles()
|
|
||||||
|
|
||||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
app.storage.ombi_path = app.config.Section("files").Key("ombi_template").String()
|
app.debug.Printf("Connecting to Ombi")
|
||||||
app.storage.loadOmbiTemplate()
|
|
||||||
ombiServer := app.config.Section("ombi").Key("server").String()
|
ombiServer := app.config.Section("ombi").Key("server").String()
|
||||||
app.ombi = ombi.NewOmbi(
|
app.ombi = ombi.NewOmbi(
|
||||||
ombiServer,
|
ombiServer,
|
||||||
@ -397,6 +346,9 @@ func start(asDaemon, firstCall bool) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.storage.db_path = filepath.Join(app.dataPath, "db")
|
||||||
|
app.ConnectDB()
|
||||||
|
defer app.storage.db.Close()
|
||||||
// Read config-base for settings on web.
|
// Read config-base for settings on web.
|
||||||
app.configBasePath = "config-base.json"
|
app.configBasePath = "config-base.json"
|
||||||
configBase, _ := fs.ReadFile(localFS, app.configBasePath)
|
configBase, _ := fs.ReadFile(localFS, app.configBasePath)
|
||||||
|
18
matrix.go
18
matrix.go
@ -6,6 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gomarkdown/markdown"
|
"github.com/gomarkdown/markdown"
|
||||||
|
"github.com/timshannon/badgerhold/v4"
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/event"
|
"maunium.net/go/mautrix/event"
|
||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/id"
|
||||||
@ -31,11 +32,12 @@ type UnverifiedUser struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MatrixUser struct {
|
type MatrixUser struct {
|
||||||
RoomID string
|
RoomID string
|
||||||
Encrypted bool
|
Encrypted bool
|
||||||
UserID string
|
UserID string
|
||||||
Lang string
|
Lang string
|
||||||
Contact bool
|
Contact bool
|
||||||
|
JellyfinID string `badgerhold:"key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var matrixFilter = mautrix.Filter{
|
var matrixFilter = mautrix.Filter{
|
||||||
@ -268,6 +270,12 @@ func (d *MatrixDaemon) Send(message *Message, users ...MatrixUser) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserExists returns whether or not a user with the given User ID exists.
|
||||||
|
func (d *MatrixDaemon) UserExists(userID string) bool {
|
||||||
|
c, err := d.app.storage.db.Count(&MatrixUser{}, badgerhold.Where("UserID").Eq(userID))
|
||||||
|
return err != nil || c > 0
|
||||||
|
}
|
||||||
|
|
||||||
// User enters ID on sign-up, a PIN is sent to them. They enter it on sign-up.
|
// User enters ID on sign-up, a PIN is sent to them. They enter it on sign-up.
|
||||||
|
|
||||||
// Message the user first, to avoid E2EE by default
|
// Message the user first, to avoid E2EE by default
|
||||||
|
189
migrations.go
189
migrations.go
@ -16,26 +16,28 @@ func runMigrations(app *appContext) {
|
|||||||
migrateNotificationMethods(app)
|
migrateNotificationMethods(app)
|
||||||
linkExistingOmbiDiscordTelegram(app)
|
linkExistingOmbiDiscordTelegram(app)
|
||||||
// migrateHyphens(app)
|
// migrateHyphens(app)
|
||||||
|
migrateToBadger(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate pre-0.2.0 user templates to profiles
|
// Migrate pre-0.2.0 user templates to profiles
|
||||||
func migrateProfiles(app *appContext) {
|
func migrateProfiles(app *appContext) {
|
||||||
if !(app.storage.policy.BlockedTags == nil && app.storage.configuration.GroupedFolders == nil && len(app.storage.displayprefs) == 0) {
|
if app.storage.deprecatedPolicy.BlockedTags == nil && app.storage.deprecatedConfiguration.GroupedFolders == nil && len(app.storage.deprecatedDisplayprefs) == 0 {
|
||||||
app.info.Println("Migrating user template files to new profile format")
|
return
|
||||||
app.storage.migrateToProfile()
|
}
|
||||||
for _, path := range [3]string{app.storage.policy_path, app.storage.configuration_path, app.storage.displayprefs_path} {
|
app.info.Println("Migrating user template files to new profile format")
|
||||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
app.storage.migrateToProfile()
|
||||||
dir, fname := filepath.Split(path)
|
for _, path := range [3]string{app.storage.policy_path, app.storage.configuration_path, app.storage.displayprefs_path} {
|
||||||
newFname := strings.Replace(fname, ".json", ".old.json", 1)
|
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||||
err := os.Rename(path, filepath.Join(dir, newFname))
|
dir, fname := filepath.Split(path)
|
||||||
if err != nil {
|
newFname := strings.Replace(fname, ".json", ".old.json", 1)
|
||||||
app.err.Fatalf("Failed to rename %s: %s", fname, err)
|
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.
|
// Migrate pre-0.2.5 bootstrap theme choice to a17t version.
|
||||||
@ -131,7 +133,7 @@ func migrateNotificationMethods(app *appContext) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
changes := false
|
changes := false
|
||||||
for code, invite := range app.storage.invites {
|
for code, invite := range app.storage.deprecatedInvites {
|
||||||
if invite.Notify == nil {
|
if invite.Notify == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -139,9 +141,9 @@ func migrateNotificationMethods(app *appContext) error {
|
|||||||
if !strings.Contains(address, "@") {
|
if !strings.Contains(address, "@") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for id, email := range app.storage.GetEmails() {
|
for _, email := range app.storage.GetEmails() {
|
||||||
if email.Addr == address {
|
if email.Addr == address {
|
||||||
invite.Notify[id] = notifyPrefs
|
invite.Notify[email.JellyfinID] = notifyPrefs
|
||||||
delete(invite.Notify, address)
|
delete(invite.Notify, address)
|
||||||
changes = true
|
changes = true
|
||||||
break
|
break
|
||||||
@ -149,7 +151,7 @@ func migrateNotificationMethods(app *appContext) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if changes {
|
if changes {
|
||||||
app.storage.invites[code] = invite
|
app.storage.deprecatedInvites[code] = invite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if changes {
|
if changes {
|
||||||
@ -168,16 +170,16 @@ 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.GetDiscord() {
|
for _, user := range app.storage.GetDiscord() {
|
||||||
idList[jfID] = [2]string{user.ID, ""}
|
idList[user.JellyfinID] = [2]string{user.ID, ""}
|
||||||
}
|
}
|
||||||
for jfID, user := range app.storage.GetTelegram() {
|
for _, user := range app.storage.GetTelegram() {
|
||||||
vals, ok := idList[jfID]
|
vals, ok := idList[user.JellyfinID]
|
||||||
if !ok {
|
if !ok {
|
||||||
vals = [2]string{"", ""}
|
vals = [2]string{"", ""}
|
||||||
}
|
}
|
||||||
vals[1] = user.Username
|
vals[1] = user.Username
|
||||||
idList[jfID] = vals
|
idList[user.JellyfinID] = vals
|
||||||
}
|
}
|
||||||
for jfID, ids := range idList {
|
for jfID, ids := range idList {
|
||||||
ombiUser, status, err := app.getOmbiUser(jfID)
|
ombiUser, status, err := app.getOmbiUser(jfID)
|
||||||
@ -194,6 +196,143 @@ func linkExistingOmbiDiscordTelegram(app *appContext) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MigrationStatus is just used to store whether data from JSON files has been migrated to the DB.
|
||||||
|
type MigrationStatus struct {
|
||||||
|
Done bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadLegacyData(app *appContext) {
|
||||||
|
app.storage.invite_path = app.config.Section("files").Key("invites").String()
|
||||||
|
if err := app.storage.loadInvites(); err != nil {
|
||||||
|
app.err.Printf("LegacyData: Failed to load Invites: %v", err)
|
||||||
|
}
|
||||||
|
app.storage.emails_path = app.config.Section("files").Key("emails").String()
|
||||||
|
if err := app.storage.loadEmails(); err != nil {
|
||||||
|
app.err.Printf("LegacyData: Failed to load Emails: %v", err)
|
||||||
|
err := migrateEmailStorage(app)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("LegacyData: Failed to migrate Email storage: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
app.storage.users_path = app.config.Section("files").Key("users").String()
|
||||||
|
if err := app.storage.loadUserExpiries(); err != nil {
|
||||||
|
app.err.Printf("LegacyData: Failed to load Users: %v", err)
|
||||||
|
}
|
||||||
|
app.storage.telegram_path = app.config.Section("files").Key("telegram_users").String()
|
||||||
|
if err := app.storage.loadTelegramUsers(); err != nil {
|
||||||
|
app.err.Printf("LegacyData: Failed to load Telegram users: %v", err)
|
||||||
|
}
|
||||||
|
app.storage.discord_path = app.config.Section("files").Key("discord_users").String()
|
||||||
|
if err := app.storage.loadDiscordUsers(); err != nil {
|
||||||
|
app.err.Printf("LegacyData: Failed to load Discord users: %v", err)
|
||||||
|
}
|
||||||
|
app.storage.matrix_path = app.config.Section("files").Key("matrix_users").String()
|
||||||
|
if err := app.storage.loadMatrixUsers(); err != nil {
|
||||||
|
app.err.Printf("LegacyData: Failed to load Matrix users: %v", err)
|
||||||
|
}
|
||||||
|
app.storage.announcements_path = app.config.Section("files").Key("announcements").String()
|
||||||
|
if err := app.storage.loadAnnouncements(); err != nil {
|
||||||
|
app.err.Printf("LegacyData: Failed to load announcement templates: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
app.storage.profiles_path = app.config.Section("files").Key("user_profiles").String()
|
||||||
|
app.storage.loadProfiles()
|
||||||
|
|
||||||
|
app.storage.customEmails_path = app.config.Section("files").Key("custom_emails").String()
|
||||||
|
app.storage.loadCustomEmails()
|
||||||
|
|
||||||
|
app.MustSetValue("user_page", "enabled", "true")
|
||||||
|
if app.config.Section("user_page").Key("enabled").MustBool(false) {
|
||||||
|
app.storage.userPage_path = app.config.Section("files").Key("custom_user_page_content").String()
|
||||||
|
app.storage.loadUserPageContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func migrateToBadger(app *appContext) {
|
||||||
|
// Check the DB to see if we've already migrated
|
||||||
|
migrated := MigrationStatus{}
|
||||||
|
app.storage.db.Get("migrated_to_db", &migrated)
|
||||||
|
if migrated.Done {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.info.Println("Migrating to Badger(hold)")
|
||||||
|
loadLegacyData(app)
|
||||||
|
for k, v := range app.storage.deprecatedAnnouncements {
|
||||||
|
app.storage.SetAnnouncementsKey(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
for jfID, v := range app.storage.deprecatedDiscord {
|
||||||
|
app.storage.SetDiscordKey(jfID, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
for jfID, v := range app.storage.deprecatedTelegram {
|
||||||
|
app.storage.SetTelegramKey(jfID, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
for jfID, v := range app.storage.deprecatedMatrix {
|
||||||
|
app.storage.SetMatrixKey(jfID, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
for jfID, v := range app.storage.deprecatedEmails {
|
||||||
|
app.storage.SetEmailsKey(jfID, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range app.storage.deprecatedInvites {
|
||||||
|
app.storage.SetInvitesKey(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range app.storage.deprecatedUserExpiries {
|
||||||
|
app.storage.SetUserExpiryKey(k, UserExpiry{Expiry: v})
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range app.storage.deprecatedProfiles {
|
||||||
|
app.storage.SetProfileKey(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("UserCreated"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("UserCreated", app.storage.deprecatedCustomEmails.UserCreated)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("InviteExpiry"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("InviteExpiry", app.storage.deprecatedCustomEmails.InviteExpiry)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("PasswordReset"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("PasswordReset", app.storage.deprecatedCustomEmails.PasswordReset)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("UserDeleted"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("UserDeleted", app.storage.deprecatedCustomEmails.UserDeleted)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("UserDisabled"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("UserDisabled", app.storage.deprecatedCustomEmails.UserDisabled)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("UserEnabled"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("UserEnabled", app.storage.deprecatedCustomEmails.UserEnabled)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("InviteEmail"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("InviteEmail", app.storage.deprecatedCustomEmails.InviteEmail)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("WelcomeEmail"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("WelcomeEmail", app.storage.deprecatedCustomEmails.WelcomeEmail)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("EmailConfirmation"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("EmailConfirmation", app.storage.deprecatedCustomEmails.EmailConfirmation)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("UserExpired"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("UserExpired", app.storage.deprecatedCustomEmails.UserExpired)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("UserLogin"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("UserLogin", app.storage.deprecatedUserPageContent.Login)
|
||||||
|
}
|
||||||
|
if _, ok := app.storage.GetCustomContentKey("UserPage"); !ok {
|
||||||
|
app.storage.SetCustomContentKey("UserPage", app.storage.deprecatedUserPageContent.Page)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.storage.db.Upsert("migrated_to_db", MigrationStatus{true})
|
||||||
|
if err != nil {
|
||||||
|
app.err.Fatalf("Failed to migrate to DB: %v\n", err)
|
||||||
|
}
|
||||||
|
app.info.Println("All data migrated to database. JSON files in the config folder can be deleted if you are sure all data is correct in the app. Create an issue if you have problems.")
|
||||||
|
}
|
||||||
|
|
||||||
// Migrate between hyphenated & non-hyphenated user IDs. Doesn't seem to happen anymore, so disabled.
|
// Migrate between hyphenated & non-hyphenated user IDs. Doesn't seem to happen anymore, so disabled.
|
||||||
// func migrateHyphens(app *appContext) {
|
// func migrateHyphens(app *appContext) {
|
||||||
// checkVersion := func(version string) int {
|
// checkVersion := func(version string) int {
|
||||||
@ -212,8 +351,8 @@ func linkExistingOmbiDiscordTelegram(app *appContext) error {
|
|||||||
// app.jf.GetUsers(false)
|
// app.jf.GetUsers(false)
|
||||||
//
|
//
|
||||||
// noHyphens := true
|
// noHyphens := true
|
||||||
// for id := range app.storage.GetEmails() {
|
// for _, e := range app.storage.GetEmails() {
|
||||||
// if strings.Contains(id, "-") {
|
// if strings.Contains(e.JellyfinID, "-") {
|
||||||
// noHyphens = false
|
// noHyphens = false
|
||||||
// break
|
// break
|
||||||
// }
|
// }
|
||||||
@ -255,7 +394,7 @@ func linkExistingOmbiDiscordTelegram(app *appContext) error {
|
|||||||
// app.storage.emails = newEmails
|
// app.storage.emails = newEmails
|
||||||
// app.storage.users = newUsers
|
// app.storage.users = newUsers
|
||||||
// err = app.storage.storeEmails()
|
// err = app.storage.storeEmails()
|
||||||
// err2 = app.storage.storeUsers()
|
// err2 = app.storage.storeUserExpiries()
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// app.err.Fatalf("couldn't store emails.json: %v", err)
|
// app.err.Fatalf("couldn't store emails.json: %v", err)
|
||||||
// }
|
// }
|
||||||
|
@ -100,7 +100,6 @@ func pwrMonitor(app *appContext, watcher *fsnotify.Watcher) {
|
|||||||
app.debug.Printf("Error: %s", err)
|
app.debug.Printf("Error: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
app.storage.loadEmails()
|
|
||||||
uid := user.ID
|
uid := user.ID
|
||||||
if uid == "" {
|
if uid == "" {
|
||||||
app.err.Printf("Couldn't get user ID for user \"%s\"", pwr.Username)
|
app.err.Printf("Couldn't get user ID for user \"%s\"", pwr.Username)
|
||||||
|
549
storage.go
549
storage.go
@ -8,11 +8,11 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hrfee/mediabrowser"
|
"github.com/hrfee/mediabrowser"
|
||||||
"github.com/steambap/captcha"
|
"github.com/steambap/captcha"
|
||||||
|
"github.com/timshannon/badgerhold/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type discordStore map[string]DiscordUser
|
type discordStore map[string]DiscordUser
|
||||||
@ -20,224 +20,439 @@ type telegramStore map[string]TelegramUser
|
|||||||
type matrixStore map[string]MatrixUser
|
type matrixStore map[string]MatrixUser
|
||||||
type emailStore map[string]EmailAddress
|
type emailStore map[string]EmailAddress
|
||||||
|
|
||||||
|
type UserExpiry struct {
|
||||||
|
JellyfinID string `badgerhold:"key"`
|
||||||
|
Expiry time.Time
|
||||||
|
}
|
||||||
|
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
timePattern string
|
timePattern string
|
||||||
|
|
||||||
|
db_path string
|
||||||
|
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
|
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.
|
deprecatedUserExpiries map[string]time.Time // Map of Jellyfin User IDs to their expiry times.
|
||||||
invites Invites
|
deprecatedInvites Invites
|
||||||
profiles map[string]Profile
|
deprecatedProfiles map[string]Profile
|
||||||
defaultProfile string
|
deprecatedDisplayprefs, deprecatedOmbiTemplate map[string]interface{}
|
||||||
displayprefs, ombi_template map[string]interface{}
|
deprecatedEmails emailStore // Map of Jellyfin User IDs to Email addresses.
|
||||||
emails emailStore
|
deprecatedTelegram telegramStore // Map of Jellyfin User IDs to telegram users.
|
||||||
telegram telegramStore // Map of Jellyfin User IDs to telegram users.
|
deprecatedDiscord discordStore // Map of Jellyfin user IDs to discord users.
|
||||||
discord discordStore // Map of Jellyfin user IDs to discord users.
|
deprecatedMatrix matrixStore // Map of Jellyfin user IDs to Matrix users.
|
||||||
matrix matrixStore // Map of Jellyfin user IDs to Matrix users.
|
deprecatedPolicy mediabrowser.Policy
|
||||||
customEmails customEmails
|
deprecatedConfiguration mediabrowser.Configuration
|
||||||
userPage userPageContent
|
deprecatedAnnouncements map[string]announcementTemplate
|
||||||
policy mediabrowser.Policy
|
deprecatedCustomEmails customEmails
|
||||||
configuration mediabrowser.Configuration
|
deprecatedUserPageContent userPageContent
|
||||||
lang Lang
|
lang Lang
|
||||||
announcements map[string]announcementTemplate
|
}
|
||||||
invitesLock, usersLock, discordLock, telegramLock, matrixLock, emailsLock sync.Mutex
|
|
||||||
|
func (app *appContext) ConnectDB() {
|
||||||
|
opts := badgerhold.DefaultOptions
|
||||||
|
opts.Dir = app.storage.db_path
|
||||||
|
opts.ValueDir = app.storage.db_path
|
||||||
|
db, err := badgerhold.Open(opts)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Fatalf("Failed to open db \"%s\": %v", app.storage.db_path, err)
|
||||||
|
}
|
||||||
|
app.storage.db = db
|
||||||
|
app.info.Printf("Connected to DB \"%s\"", app.storage.db_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmails returns a copy of the store.
|
// GetEmails returns a copy of the store.
|
||||||
func (st *Storage) GetEmails() emailStore {
|
func (st *Storage) GetEmails() []EmailAddress {
|
||||||
return st.emails
|
result := []EmailAddress{}
|
||||||
|
err := st.db.Find(&result, &badgerhold.Query{})
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find emails: %v\n", err)
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmailsKey returns the value stored in the store's key.
|
// GetEmailsKey returns the value stored in the store's key.
|
||||||
func (st *Storage) GetEmailsKey(k string) (EmailAddress, bool) {
|
func (st *Storage) GetEmailsKey(k string) (EmailAddress, bool) {
|
||||||
v, ok := st.emails[k]
|
result := EmailAddress{}
|
||||||
return v, ok
|
err := st.db.Get(k, &result)
|
||||||
|
ok := true
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find email: %v\n", err)
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
return result, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEmailsKey stores value v in key k.
|
// SetEmailsKey stores value v in key k.
|
||||||
func (st *Storage) SetEmailsKey(k string, v EmailAddress) {
|
func (st *Storage) SetEmailsKey(k string, v EmailAddress) {
|
||||||
st.emailsLock.Lock()
|
v.JellyfinID = k
|
||||||
st.emails[k] = v
|
err := st.db.Upsert(k, v)
|
||||||
st.storeEmails()
|
if err != nil {
|
||||||
st.emailsLock.Unlock()
|
// fmt.Printf("Failed to set email: %v\n", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteEmailKey deletes value at key k.
|
// DeleteEmailKey deletes value at key k.
|
||||||
func (st *Storage) DeleteEmailsKey(k string) {
|
func (st *Storage) DeleteEmailsKey(k string) {
|
||||||
st.emailsLock.Lock()
|
st.db.Delete(k, EmailAddress{})
|
||||||
delete(st.emails, k)
|
|
||||||
st.storeEmails()
|
|
||||||
st.emailsLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDiscord returns a copy of the store.
|
// GetDiscord returns a copy of the store.
|
||||||
func (st *Storage) GetDiscord() discordStore {
|
func (st *Storage) GetDiscord() []DiscordUser {
|
||||||
if st.discord == nil {
|
result := []DiscordUser{}
|
||||||
st.discord = discordStore{}
|
err := st.db.Find(&result, &badgerhold.Query{})
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find users: %v\n", err)
|
||||||
}
|
}
|
||||||
return st.discord
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDiscordKey returns the value stored in the store's key.
|
// GetDiscordKey returns the value stored in the store's key.
|
||||||
func (st *Storage) GetDiscordKey(k string) (DiscordUser, bool) {
|
func (st *Storage) GetDiscordKey(k string) (DiscordUser, bool) {
|
||||||
v, ok := st.discord[k]
|
result := DiscordUser{}
|
||||||
return v, ok
|
err := st.db.Get(k, &result)
|
||||||
|
ok := true
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find user: %v\n", err)
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
return result, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDiscordKey stores value v in key k.
|
// SetDiscordKey stores value v in key k.
|
||||||
func (st *Storage) SetDiscordKey(k string, v DiscordUser) {
|
func (st *Storage) SetDiscordKey(k string, v DiscordUser) {
|
||||||
st.discordLock.Lock()
|
v.JellyfinID = k
|
||||||
if st.discord == nil {
|
err := st.db.Upsert(k, v)
|
||||||
st.discord = discordStore{}
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to set user: %v\n", err)
|
||||||
}
|
}
|
||||||
st.discord[k] = v
|
|
||||||
st.storeDiscordUsers()
|
|
||||||
st.discordLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteDiscordKey deletes value at key k.
|
// DeleteDiscordKey deletes value at key k.
|
||||||
func (st *Storage) DeleteDiscordKey(k string) {
|
func (st *Storage) DeleteDiscordKey(k string) {
|
||||||
st.discordLock.Lock()
|
st.db.Delete(k, DiscordUser{})
|
||||||
delete(st.discord, k)
|
|
||||||
st.storeDiscordUsers()
|
|
||||||
st.discordLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTelegram returns a copy of the store.
|
// GetTelegram returns a copy of the store.
|
||||||
func (st *Storage) GetTelegram() telegramStore {
|
func (st *Storage) GetTelegram() []TelegramUser {
|
||||||
if st.telegram == nil {
|
result := []TelegramUser{}
|
||||||
st.telegram = telegramStore{}
|
err := st.db.Find(&result, &badgerhold.Query{})
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find users: %v\n", err)
|
||||||
}
|
}
|
||||||
return st.telegram
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTelegramKey returns the value stored in the store's key.
|
// GetTelegramKey returns the value stored in the store's key.
|
||||||
func (st *Storage) GetTelegramKey(k string) (TelegramUser, bool) {
|
func (st *Storage) GetTelegramKey(k string) (TelegramUser, bool) {
|
||||||
v, ok := st.telegram[k]
|
result := TelegramUser{}
|
||||||
return v, ok
|
err := st.db.Get(k, &result)
|
||||||
|
ok := true
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find user: %v\n", err)
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
return result, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTelegramKey stores value v in key k.
|
// SetTelegramKey stores value v in key k.
|
||||||
func (st *Storage) SetTelegramKey(k string, v TelegramUser) {
|
func (st *Storage) SetTelegramKey(k string, v TelegramUser) {
|
||||||
st.telegramLock.Lock()
|
v.JellyfinID = k
|
||||||
if st.telegram == nil {
|
err := st.db.Upsert(k, v)
|
||||||
st.telegram = telegramStore{}
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to set user: %v\n", err)
|
||||||
}
|
}
|
||||||
st.telegram[k] = v
|
|
||||||
st.storeTelegramUsers()
|
|
||||||
st.telegramLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTelegramKey deletes value at key k.
|
// DeleteTelegramKey deletes value at key k.
|
||||||
func (st *Storage) DeleteTelegramKey(k string) {
|
func (st *Storage) DeleteTelegramKey(k string) {
|
||||||
st.telegramLock.Lock()
|
st.db.Delete(k, TelegramUser{})
|
||||||
delete(st.telegram, k)
|
|
||||||
st.storeTelegramUsers()
|
|
||||||
st.telegramLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMatrix returns a copy of the store.
|
// GetMatrix returns a copy of the store.
|
||||||
func (st *Storage) GetMatrix() matrixStore {
|
func (st *Storage) GetMatrix() []MatrixUser {
|
||||||
if st.matrix == nil {
|
result := []MatrixUser{}
|
||||||
st.matrix = matrixStore{}
|
err := st.db.Find(&result, &badgerhold.Query{})
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find users: %v\n", err)
|
||||||
}
|
}
|
||||||
return st.matrix
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMatrixKey returns the value stored in the store's key.
|
// GetMatrixKey returns the value stored in the store's key.
|
||||||
func (st *Storage) GetMatrixKey(k string) (MatrixUser, bool) {
|
func (st *Storage) GetMatrixKey(k string) (MatrixUser, bool) {
|
||||||
v, ok := st.matrix[k]
|
result := MatrixUser{}
|
||||||
return v, ok
|
err := st.db.Get(k, &result)
|
||||||
|
ok := true
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find user: %v\n", err)
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
return result, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMatrixKey stores value v in key k.
|
// SetMatrixKey stores value v in key k.
|
||||||
func (st *Storage) SetMatrixKey(k string, v MatrixUser) {
|
func (st *Storage) SetMatrixKey(k string, v MatrixUser) {
|
||||||
st.matrixLock.Lock()
|
v.JellyfinID = k
|
||||||
if st.matrix == nil {
|
err := st.db.Upsert(k, v)
|
||||||
st.matrix = matrixStore{}
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to set user: %v\n", err)
|
||||||
}
|
}
|
||||||
st.matrix[k] = v
|
|
||||||
st.storeMatrixUsers()
|
|
||||||
st.matrixLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteMatrixKey deletes value at key k.
|
// DeleteMatrixKey deletes value at key k.
|
||||||
func (st *Storage) DeleteMatrixKey(k string) {
|
func (st *Storage) DeleteMatrixKey(k string) {
|
||||||
st.matrixLock.Lock()
|
st.db.Delete(k, MatrixUser{})
|
||||||
delete(st.matrix, k)
|
|
||||||
st.storeMatrixUsers()
|
|
||||||
st.matrixLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInvites returns a copy of the store.
|
// GetInvites returns a copy of the store.
|
||||||
func (st *Storage) GetInvites() Invites {
|
func (st *Storage) GetInvites() []Invite {
|
||||||
if st.invites == nil {
|
result := []Invite{}
|
||||||
st.invites = Invites{}
|
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.
|
// GetInvitesKey returns the value stored in the store's key.
|
||||||
func (st *Storage) GetInvitesKey(k string) (Invite, bool) {
|
func (st *Storage) GetInvitesKey(k string) (Invite, bool) {
|
||||||
v, ok := st.invites[k]
|
result := Invite{}
|
||||||
return v, ok
|
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.
|
// SetInvitesKey stores value v in key k.
|
||||||
func (st *Storage) SetInvitesKey(k string, v Invite) {
|
func (st *Storage) SetInvitesKey(k string, v Invite) {
|
||||||
st.invitesLock.Lock()
|
v.Code = k
|
||||||
if st.invites == nil {
|
err := st.db.Upsert(k, v)
|
||||||
st.invites = Invites{}
|
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.
|
// DeleteInvitesKey deletes value at key k.
|
||||||
func (st *Storage) DeleteInvitesKey(k string) {
|
func (st *Storage) DeleteInvitesKey(k string) {
|
||||||
st.invitesLock.Lock()
|
st.db.Delete(k, Invite{})
|
||||||
delete(st.invites, k)
|
}
|
||||||
st.storeInvites()
|
|
||||||
st.invitesLock.Unlock()
|
// GetAnnouncements returns a copy of the store.
|
||||||
|
func (st *Storage) GetAnnouncements() []announcementTemplate {
|
||||||
|
result := []announcementTemplate{}
|
||||||
|
err := st.db.Find(&result, &badgerhold.Query{})
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find announcements: %v\n", err)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAnnouncementsKey returns the value stored in the store's key.
|
||||||
|
func (st *Storage) GetAnnouncementsKey(k string) (announcementTemplate, bool) {
|
||||||
|
result := announcementTemplate{}
|
||||||
|
err := st.db.Get(k, &result)
|
||||||
|
ok := true
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find announcement: %v\n", err)
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
return result, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAnnouncementsKey stores value v in key k.
|
||||||
|
func (st *Storage) SetAnnouncementsKey(k string, v announcementTemplate) {
|
||||||
|
err := st.db.Upsert(k, v)
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to set announcement: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAnnouncementsKey deletes value at key k.
|
||||||
|
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{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProfiles returns a copy of the store.
|
||||||
|
func (st *Storage) GetProfiles() []Profile {
|
||||||
|
result := []Profile{}
|
||||||
|
err := st.db.Find(&result, &badgerhold.Query{})
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find profiles: %v\n", err)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProfileKey returns the value stored in the store's key.
|
||||||
|
func (st *Storage) GetProfileKey(k string) (Profile, bool) {
|
||||||
|
result := Profile{}
|
||||||
|
err := st.db.Get(k, &result)
|
||||||
|
ok := true
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find profile: %v\n", err)
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
return result, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProfileKey stores value v in key k.
|
||||||
|
func (st *Storage) SetProfileKey(k string, v Profile) {
|
||||||
|
v.Name = k
|
||||||
|
v.Admin = v.Policy.IsAdministrator
|
||||||
|
if v.Policy.EnabledFolders != nil {
|
||||||
|
if len(v.Policy.EnabledFolders) == 0 {
|
||||||
|
v.LibraryAccess = "All"
|
||||||
|
} else {
|
||||||
|
v.LibraryAccess = strconv.Itoa(len(v.Policy.EnabledFolders))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v.FromUser == "" {
|
||||||
|
v.FromUser = "Unknown"
|
||||||
|
}
|
||||||
|
err := st.db.Upsert(k, v)
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to set profile: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteProfileKey deletes value at key k.
|
||||||
|
func (st *Storage) DeleteProfileKey(k string) {
|
||||||
|
st.db.Delete(k, Profile{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultProfile returns the first profile set as default, or anything available if there isn't one.
|
||||||
|
func (st *Storage) GetDefaultProfile() Profile {
|
||||||
|
defaultProfile := Profile{}
|
||||||
|
err := st.db.FindOne(&defaultProfile, badgerhold.Where("Default").Eq(true))
|
||||||
|
if err != nil {
|
||||||
|
st.db.FindOne(&defaultProfile, &badgerhold.Query{})
|
||||||
|
}
|
||||||
|
return defaultProfile
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCustomContent returns a copy of the store.
|
||||||
|
func (st *Storage) GetCustomContent() []CustomContent {
|
||||||
|
result := []CustomContent{}
|
||||||
|
err := st.db.Find(&result, &badgerhold.Query{})
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find custom content: %v\n", err)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCustomContentKey returns the value stored in the store's key.
|
||||||
|
func (st *Storage) GetCustomContentKey(k string) (CustomContent, bool) {
|
||||||
|
result := CustomContent{}
|
||||||
|
err := st.db.Get(k, &result)
|
||||||
|
ok := true
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to find custom content: %v\n", err)
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
return result, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustGetCustomContentKey returns the value stored in the store's key, or an empty value.
|
||||||
|
func (st *Storage) MustGetCustomContentKey(k string) CustomContent {
|
||||||
|
result := CustomContent{}
|
||||||
|
st.db.Get(k, &result)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCustomContentKey stores value v in key k.
|
||||||
|
func (st *Storage) SetCustomContentKey(k string, v CustomContent) {
|
||||||
|
v.Name = k
|
||||||
|
err := st.db.Upsert(k, v)
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Printf("Failed to set custom content: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCustomContentKey deletes value at key k.
|
||||||
|
func (st *Storage) DeleteCustomContentKey(k string) {
|
||||||
|
st.db.Delete(k, CustomContent{})
|
||||||
}
|
}
|
||||||
|
|
||||||
type TelegramUser struct {
|
type TelegramUser struct {
|
||||||
ChatID int64
|
JellyfinID string `badgerhold:"key"`
|
||||||
Username string
|
ChatID int64 `badgerhold:"index"`
|
||||||
Lang string
|
Username string `badgerhold:"index"`
|
||||||
Contact bool // Whether to contact through telegram or not
|
Lang string
|
||||||
|
Contact bool // Whether to contact through telegram or not
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiscordUser struct {
|
type DiscordUser struct {
|
||||||
ChannelID string
|
ChannelID string
|
||||||
ID string
|
ID string `badgerhold:"index"`
|
||||||
Username string
|
Username string `badgerhold:"index"`
|
||||||
Discriminator string
|
Discriminator string
|
||||||
Lang string
|
Lang string
|
||||||
Contact bool
|
Contact bool
|
||||||
JellyfinID string `json:"-"` // Used internally in discord.go
|
JellyfinID string `json:"-" badgerhold:"key"` // Used internally in discord.go
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmailAddress struct {
|
type EmailAddress struct {
|
||||||
Addr string
|
Addr string `badgerhold:"index"`
|
||||||
Label string // User Label.
|
Label string // User Label.
|
||||||
Contact bool
|
Contact bool
|
||||||
Admin bool // Whether or not user is jfa-go admin.
|
Admin bool // Whether or not user is jfa-go admin.
|
||||||
|
JellyfinID string `badgerhold:"key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type customEmails struct {
|
type customEmails struct {
|
||||||
UserCreated customContent `json:"userCreated"`
|
UserCreated CustomContent `json:"userCreated"`
|
||||||
InviteExpiry customContent `json:"inviteExpiry"`
|
InviteExpiry CustomContent `json:"inviteExpiry"`
|
||||||
PasswordReset customContent `json:"passwordReset"`
|
PasswordReset CustomContent `json:"passwordReset"`
|
||||||
UserDeleted customContent `json:"userDeleted"`
|
UserDeleted CustomContent `json:"userDeleted"`
|
||||||
UserDisabled customContent `json:"userDisabled"`
|
UserDisabled CustomContent `json:"userDisabled"`
|
||||||
UserEnabled customContent `json:"userEnabled"`
|
UserEnabled CustomContent `json:"userEnabled"`
|
||||||
InviteEmail customContent `json:"inviteEmail"`
|
InviteEmail CustomContent `json:"inviteEmail"`
|
||||||
WelcomeEmail customContent `json:"welcomeEmail"`
|
WelcomeEmail CustomContent `json:"welcomeEmail"`
|
||||||
EmailConfirmation customContent `json:"emailConfirmation"`
|
EmailConfirmation CustomContent `json:"emailConfirmation"`
|
||||||
UserExpired customContent `json:"userExpired"`
|
UserExpired CustomContent `json:"userExpired"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type customContent struct {
|
// CustomContent stores customized versions of jfa-go content, including emails and user messages.
|
||||||
|
type CustomContent struct {
|
||||||
|
Name string `json:"name" badgerhold:"key"`
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Variables []string `json:"variables,omitempty"`
|
Variables []string `json:"variables,omitempty"`
|
||||||
@ -245,14 +460,15 @@ type customContent struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type userPageContent struct {
|
type userPageContent struct {
|
||||||
Login customContent `json:"login"`
|
Login CustomContent `json:"login"`
|
||||||
Page customContent `json:"page"`
|
Page CustomContent `json:"page"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// timePattern: %Y-%m-%dT%H:%M:%S.%f
|
// timePattern: %Y-%m-%dT%H:%M:%S.%f
|
||||||
|
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
Admin bool `json:"admin,omitempty"`
|
Name string `badgerhold:"key"`
|
||||||
|
Admin bool `json:"admin,omitempty" badgerhold:"index"`
|
||||||
LibraryAccess string `json:"libraries,omitempty"`
|
LibraryAccess string `json:"libraries,omitempty"`
|
||||||
FromUser string `json:"fromUser,omitempty"`
|
FromUser string `json:"fromUser,omitempty"`
|
||||||
Policy mediabrowser.Policy `json:"policy,omitempty"`
|
Policy mediabrowser.Policy `json:"policy,omitempty"`
|
||||||
@ -263,6 +479,7 @@ type Profile struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Invite struct {
|
type Invite struct {
|
||||||
|
Code string `badgerhold:"key"`
|
||||||
Created time.Time `json:"created"`
|
Created time.Time `json:"created"`
|
||||||
NoLimit bool `json:"no-limit"`
|
NoLimit bool `json:"no-limit"`
|
||||||
RemainingUses int `json:"remaining-uses"`
|
RemainingUses int `json:"remaining-uses"`
|
||||||
@ -964,18 +1181,16 @@ func (st *Storage) loadLangTelegram(filesystems ...fs.FS) error {
|
|||||||
type Invites map[string]Invite
|
type Invites map[string]Invite
|
||||||
|
|
||||||
func (st *Storage) loadInvites() error {
|
func (st *Storage) loadInvites() error {
|
||||||
return loadJSON(st.invite_path, &st.invites)
|
return loadJSON(st.invite_path, &st.deprecatedInvites)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeInvites() error {
|
func (st *Storage) storeInvites() error {
|
||||||
return storeJSON(st.invite_path, st.invites)
|
return storeJSON(st.invite_path, st.deprecatedInvites)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadUsers() error {
|
func (st *Storage) loadUserExpiries() error {
|
||||||
st.usersLock.Lock()
|
if st.deprecatedUserExpiries == nil {
|
||||||
defer st.usersLock.Unlock()
|
st.deprecatedUserExpiries = map[string]time.Time{}
|
||||||
if st.users == nil {
|
|
||||||
st.users = map[string]time.Time{}
|
|
||||||
}
|
}
|
||||||
temp := map[string]time.Time{}
|
temp := map[string]time.Time{}
|
||||||
err := loadJSON(st.users_path, &temp)
|
err := loadJSON(st.users_path, &temp)
|
||||||
@ -983,111 +1198,111 @@ func (st *Storage) loadUsers() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for id, t1 := range temp {
|
for id, t1 := range temp {
|
||||||
if _, ok := st.users[id]; !ok {
|
if _, ok := st.deprecatedUserExpiries[id]; !ok {
|
||||||
st.users[id] = t1
|
st.deprecatedUserExpiries[id] = t1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeUsers() error {
|
func (st *Storage) storeUserExpiries() error {
|
||||||
return storeJSON(st.users_path, st.users)
|
return storeJSON(st.users_path, st.deprecatedUserExpiries)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadEmails() error {
|
func (st *Storage) loadEmails() error {
|
||||||
return loadJSON(st.emails_path, &st.emails)
|
return loadJSON(st.emails_path, &st.deprecatedEmails)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeEmails() error {
|
func (st *Storage) storeEmails() error {
|
||||||
return storeJSON(st.emails_path, st.emails)
|
return storeJSON(st.emails_path, st.deprecatedEmails)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadTelegramUsers() error {
|
func (st *Storage) loadTelegramUsers() error {
|
||||||
return loadJSON(st.telegram_path, &st.telegram)
|
return loadJSON(st.telegram_path, &st.deprecatedTelegram)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeTelegramUsers() error {
|
func (st *Storage) storeTelegramUsers() error {
|
||||||
return storeJSON(st.telegram_path, st.telegram)
|
return storeJSON(st.telegram_path, st.deprecatedTelegram)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadDiscordUsers() error {
|
func (st *Storage) loadDiscordUsers() error {
|
||||||
return loadJSON(st.discord_path, &st.discord)
|
return loadJSON(st.discord_path, &st.deprecatedDiscord)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeDiscordUsers() error {
|
func (st *Storage) storeDiscordUsers() error {
|
||||||
return storeJSON(st.discord_path, st.discord)
|
return storeJSON(st.discord_path, st.deprecatedDiscord)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadMatrixUsers() error {
|
func (st *Storage) loadMatrixUsers() error {
|
||||||
return loadJSON(st.matrix_path, &st.matrix)
|
return loadJSON(st.matrix_path, &st.deprecatedMatrix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeMatrixUsers() error {
|
func (st *Storage) storeMatrixUsers() error {
|
||||||
return storeJSON(st.matrix_path, st.matrix)
|
return storeJSON(st.matrix_path, st.deprecatedMatrix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadCustomEmails() error {
|
func (st *Storage) loadCustomEmails() error {
|
||||||
return loadJSON(st.customEmails_path, &st.customEmails)
|
return loadJSON(st.customEmails_path, &st.deprecatedCustomEmails)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeCustomEmails() error {
|
func (st *Storage) storeCustomEmails() error {
|
||||||
return storeJSON(st.customEmails_path, st.customEmails)
|
return storeJSON(st.customEmails_path, st.deprecatedCustomEmails)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadUserPageContent() error {
|
func (st *Storage) loadUserPageContent() error {
|
||||||
return loadJSON(st.userPage_path, &st.userPage)
|
return loadJSON(st.userPage_path, &st.deprecatedUserPageContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeUserPageContent() error {
|
func (st *Storage) storeUserPageContent() error {
|
||||||
return storeJSON(st.userPage_path, st.userPage)
|
return storeJSON(st.userPage_path, st.deprecatedUserPageContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadPolicy() error {
|
func (st *Storage) loadPolicy() error {
|
||||||
return loadJSON(st.policy_path, &st.policy)
|
return loadJSON(st.policy_path, &st.deprecatedPolicy)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storePolicy() error {
|
func (st *Storage) storePolicy() error {
|
||||||
return storeJSON(st.policy_path, st.policy)
|
return storeJSON(st.policy_path, st.deprecatedPolicy)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadConfiguration() error {
|
func (st *Storage) loadConfiguration() error {
|
||||||
return loadJSON(st.configuration_path, &st.configuration)
|
return loadJSON(st.configuration_path, &st.deprecatedConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeConfiguration() error {
|
func (st *Storage) storeConfiguration() error {
|
||||||
return storeJSON(st.configuration_path, st.configuration)
|
return storeJSON(st.configuration_path, st.deprecatedConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadDisplayprefs() error {
|
func (st *Storage) loadDisplayprefs() error {
|
||||||
return loadJSON(st.displayprefs_path, &st.displayprefs)
|
return loadJSON(st.displayprefs_path, &st.deprecatedDisplayprefs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeDisplayprefs() error {
|
func (st *Storage) storeDisplayprefs() error {
|
||||||
return storeJSON(st.displayprefs_path, st.displayprefs)
|
return storeJSON(st.displayprefs_path, st.deprecatedDisplayprefs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadOmbiTemplate() error {
|
func (st *Storage) loadOmbiTemplate() error {
|
||||||
return loadJSON(st.ombi_path, &st.ombi_template)
|
return loadJSON(st.ombi_path, &st.deprecatedOmbiTemplate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeOmbiTemplate() error {
|
func (st *Storage) storeOmbiTemplate() error {
|
||||||
return storeJSON(st.ombi_path, st.ombi_template)
|
return storeJSON(st.ombi_path, st.deprecatedOmbiTemplate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadAnnouncements() 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 {
|
func (st *Storage) storeAnnouncements() error {
|
||||||
return storeJSON(st.announcements_path, st.announcements)
|
return storeJSON(st.announcements_path, st.deprecatedAnnouncements)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) loadProfiles() error {
|
func (st *Storage) loadProfiles() error {
|
||||||
err := loadJSON(st.profiles_path, &st.profiles)
|
err := loadJSON(st.profiles_path, &st.deprecatedProfiles)
|
||||||
for name, profile := range st.profiles {
|
for name, profile := range st.deprecatedProfiles {
|
||||||
if profile.Default {
|
// if profile.Default {
|
||||||
st.defaultProfile = name
|
// st.defaultProfile = name
|
||||||
}
|
// }
|
||||||
change := false
|
change := false
|
||||||
if profile.Policy.IsAdministrator != profile.Admin {
|
if profile.Policy.IsAdministrator != profile.Admin {
|
||||||
change = true
|
change = true
|
||||||
@ -1107,19 +1322,19 @@ func (st *Storage) loadProfiles() error {
|
|||||||
change = true
|
change = true
|
||||||
}
|
}
|
||||||
if change {
|
if change {
|
||||||
st.profiles[name] = profile
|
st.deprecatedProfiles[name] = profile
|
||||||
}
|
|
||||||
}
|
|
||||||
if st.defaultProfile == "" {
|
|
||||||
for n := range st.profiles {
|
|
||||||
st.defaultProfile = n
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if st.defaultProfile == "" {
|
||||||
|
// for n := range st.deprecatedProfiles {
|
||||||
|
// st.defaultProfile = n
|
||||||
|
// }
|
||||||
|
// }
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) storeProfiles() error {
|
func (st *Storage) storeProfiles() error {
|
||||||
return storeJSON(st.profiles_path, st.profiles)
|
return storeJSON(st.profiles_path, st.deprecatedProfiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Storage) migrateToProfile() error {
|
func (st *Storage) migrateToProfile() error {
|
||||||
@ -1127,10 +1342,10 @@ func (st *Storage) migrateToProfile() error {
|
|||||||
st.loadConfiguration()
|
st.loadConfiguration()
|
||||||
st.loadDisplayprefs()
|
st.loadDisplayprefs()
|
||||||
st.loadProfiles()
|
st.loadProfiles()
|
||||||
st.profiles["Default"] = Profile{
|
st.deprecatedProfiles["Default"] = Profile{
|
||||||
Policy: st.policy,
|
Policy: st.deprecatedPolicy,
|
||||||
Configuration: st.configuration,
|
Configuration: st.deprecatedConfiguration,
|
||||||
Displayprefs: st.displayprefs,
|
Displayprefs: st.deprecatedDisplayprefs,
|
||||||
}
|
}
|
||||||
return st.storeProfiles()
|
return st.storeProfiles()
|
||||||
}
|
}
|
||||||
|
20
telegram.go
20
telegram.go
@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
tg "github.com/go-telegram-bot-api/telegram-bot-api"
|
tg "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||||
|
"github.com/timshannon/badgerhold/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -216,13 +217,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.GetTelegram() {
|
for _, 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.SetTelegramKey(jfID, user)
|
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
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,15 +268,9 @@ func (t *TelegramDaemon) AssignedTokenVerified(pin string, jfID string) (token T
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UserExists returns whether or not a user with the given username exists.
|
// UserExists returns whether or not a user with the given username exists.
|
||||||
func (t *TelegramDaemon) UserExists(username string) (ok bool) {
|
func (t *TelegramDaemon) UserExists(username string) bool {
|
||||||
ok = false
|
c, err := t.app.storage.db.Count(&TelegramUser{}, badgerhold.Where("Username").Eq(username))
|
||||||
for _, u := range t.app.storage.GetTelegram() {
|
return err != nil || c > 0
|
||||||
if u.Username == username {
|
|
||||||
ok = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteVerifiedToken removes the token with the given PIN.
|
// DeleteVerifiedToken removes the token with the given PIN.
|
||||||
|
@ -50,13 +50,7 @@ func (rt *userDaemon) shutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *appContext) checkUsers() {
|
func (app *appContext) checkUsers() {
|
||||||
if err := app.storage.loadUsers(); err != nil {
|
if len(app.storage.GetUserExpiries()) == 0 {
|
||||||
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 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
app.info.Println("Daemon: Checking for user expiry")
|
app.info.Println("Daemon: Checking for user expiry")
|
||||||
@ -80,11 +74,12 @@ func (app *appContext) checkUsers() {
|
|||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
userExists[user.ID] = true
|
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 {
|
if _, ok := userExists[id]; !ok {
|
||||||
app.info.Printf("Deleting expiry for non-existent user \"%s\"", id)
|
app.info.Printf("Deleting expiry for non-existent user \"%s\"", id)
|
||||||
delete(app.storage.users, id)
|
app.storage.DeleteUserExpiryKey(expiry.JellyfinID)
|
||||||
} else if time.Now().After(expiry) {
|
} else if time.Now().After(expiry.Expiry) {
|
||||||
found := false
|
found := false
|
||||||
var user mediabrowser.User
|
var user mediabrowser.User
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
@ -96,7 +91,7 @@ func (app *appContext) checkUsers() {
|
|||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
app.info.Printf("Expired user already deleted, ignoring.")
|
app.info.Printf("Expired user already deleted, ignoring.")
|
||||||
delete(app.storage.users, id)
|
app.storage.DeleteUserExpiryKey(expiry.JellyfinID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
app.info.Printf("%s expired user \"%s\"", termPlural, user.Name)
|
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)
|
app.err.Printf("Failed to %s \"%s\" (%d): %s", mode, user.Name, status, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
delete(app.storage.users, id)
|
app.storage.DeleteUserExpiryKey(expiry.JellyfinID)
|
||||||
app.jf.CacheExpiry = time.Now()
|
app.jf.CacheExpiry = time.Now()
|
||||||
if contact {
|
if contact {
|
||||||
if !ok {
|
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
10
views.go
10
views.go
@ -224,13 +224,13 @@ func (app *appContext) MyUserPage(gc *gin.Context) {
|
|||||||
data["discordInviteLink"] = app.discord.inviteChannelName != ""
|
data["discordInviteLink"] = app.discord.inviteChannelName != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
pageMessages := map[string]*customContent{
|
pageMessagesExist := map[string]bool{}
|
||||||
"Login": app.getCustomMessage("UserLogin"),
|
pageMessages := map[string]CustomContent{}
|
||||||
"Page": app.getCustomMessage("UserPage"),
|
pageMessages["Login"], pageMessagesExist["Login"] = app.storage.GetCustomContentKey("UserLogin")
|
||||||
}
|
pageMessages["Page"], pageMessagesExist["Page"] = app.storage.GetCustomContentKey("UserPage")
|
||||||
|
|
||||||
for name, msg := range pageMessages {
|
for name, msg := range pageMessages {
|
||||||
if msg == nil {
|
if !pageMessagesExist[name] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
data[name+"MessageEnabled"] = msg.Enabled
|
data[name+"MessageEnabled"] = msg.Enabled
|
||||||
|
Loading…
Reference in New Issue
Block a user