mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-29 12:30:11 +00:00
Compare commits
35 Commits
6b88d6f75a
...
1b1dba2baa
Author | SHA1 | Date | |
---|---|---|---|
|
1b1dba2baa | ||
3143d32b45 | |||
742f5c095a | |||
7b2a6cdf74 | |||
2f3d5e4e3a | |||
2fb2f3ee74 | |||
7813c8c68b | |||
e528f7c348 | |||
77f6b1042e | |||
7db94dcebf | |||
|
70afc21217 | ||
|
525c13ff6a | ||
|
0366e5116d | ||
62923d5e45 | |||
10a32ad1ae | |||
e52e21a54b | |||
7c861e5763 | |||
9c771e193e | |||
|
f37451021f | ||
|
4aa095d466 | ||
|
638be18ea8 | ||
|
42264f0547 | ||
|
07d738006f | ||
|
4bc51570c2 | ||
cf94fdb2f0 | |||
4864c6c53c | |||
|
dd93758b0e | ||
|
b595d3ea03 | ||
|
49dfac514d | ||
|
729548334d | ||
|
27f85f866e | ||
|
c43d5cf1b0 | ||
|
3538935d3b | ||
|
edf6c13f03 | ||
|
b30d6c3ee1 |
@ -17,6 +17,18 @@ const (
|
|||||||
CAPTCHA_VALIDITY = 20 * 60 // Seconds
|
CAPTCHA_VALIDITY = 20 * 60 // Seconds
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GenerateInviteCode generates an invite code in the correct format.
|
||||||
|
func GenerateInviteCode() string {
|
||||||
|
// make sure code doesn't begin with number
|
||||||
|
inviteCode := shortuuid.New()
|
||||||
|
_, err := strconv.Atoi(string(inviteCode[0]))
|
||||||
|
for err == nil {
|
||||||
|
inviteCode = shortuuid.New()
|
||||||
|
_, err = strconv.Atoi(string(inviteCode[0]))
|
||||||
|
}
|
||||||
|
return inviteCode
|
||||||
|
}
|
||||||
|
|
||||||
func (app *appContext) checkInvites() {
|
func (app *appContext) checkInvites() {
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
for _, data := range app.storage.GetInvites() {
|
for _, data := range app.storage.GetInvites() {
|
||||||
@ -150,14 +162,8 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
|
|||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
validTill := currentTime.AddDate(0, req.Months, req.Days)
|
validTill := currentTime.AddDate(0, req.Months, req.Days)
|
||||||
validTill = validTill.Add(time.Hour*time.Duration(req.Hours) + time.Minute*time.Duration(req.Minutes))
|
validTill = validTill.Add(time.Hour*time.Duration(req.Hours) + time.Minute*time.Duration(req.Minutes))
|
||||||
// make sure code doesn't begin with number
|
|
||||||
inviteCode := shortuuid.New()
|
|
||||||
_, err := strconv.Atoi(string(inviteCode[0]))
|
|
||||||
for err == nil {
|
|
||||||
inviteCode = shortuuid.New()
|
|
||||||
_, err = strconv.Atoi(string(inviteCode[0]))
|
|
||||||
}
|
|
||||||
var invite Invite
|
var invite Invite
|
||||||
|
invite.Code = GenerateInviteCode()
|
||||||
if req.Label != "" {
|
if req.Label != "" {
|
||||||
invite.Label = req.Label
|
invite.Label = req.Label
|
||||||
}
|
}
|
||||||
@ -185,7 +191,7 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
|
|||||||
if req.SendTo != "" && app.config.Section("invite_emails").Key("enabled").MustBool(false) {
|
if req.SendTo != "" && app.config.Section("invite_emails").Key("enabled").MustBool(false) {
|
||||||
addressValid := false
|
addressValid := false
|
||||||
discord := ""
|
discord := ""
|
||||||
app.debug.Printf("%s: Sending invite message", inviteCode)
|
app.debug.Printf("%s: Sending invite message", invite.Code)
|
||||||
if discordEnabled && !strings.Contains(req.SendTo, "@") {
|
if discordEnabled && !strings.Contains(req.SendTo, "@") {
|
||||||
users := app.discord.GetUsers(req.SendTo)
|
users := app.discord.GetUsers(req.SendTo)
|
||||||
if len(users) == 0 {
|
if len(users) == 0 {
|
||||||
@ -202,10 +208,10 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
|
|||||||
invite.SendTo = req.SendTo
|
invite.SendTo = req.SendTo
|
||||||
}
|
}
|
||||||
if addressValid {
|
if addressValid {
|
||||||
msg, err := app.email.constructInvite(inviteCode, invite, app, false)
|
msg, err := app.email.constructInvite(invite.Code, invite, app, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
invite.SendTo = fmt.Sprintf("Failed to send to %s", req.SendTo)
|
invite.SendTo = fmt.Sprintf("Failed to send to %s", req.SendTo)
|
||||||
app.err.Printf("%s: Failed to construct invite message: %v", inviteCode, err)
|
app.err.Printf("%s: Failed to construct invite message: %v", invite.Code, err)
|
||||||
} else {
|
} else {
|
||||||
var err error
|
var err error
|
||||||
if discord != "" {
|
if discord != "" {
|
||||||
@ -215,9 +221,9 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
invite.SendTo = fmt.Sprintf("Failed to send to %s", req.SendTo)
|
invite.SendTo = fmt.Sprintf("Failed to send to %s", req.SendTo)
|
||||||
app.err.Printf("%s: %s: %v", inviteCode, invite.SendTo, err)
|
app.err.Printf("%s: %s: %v", invite.Code, invite.SendTo, err)
|
||||||
} else {
|
} else {
|
||||||
app.info.Printf("%s: Sent invite email to \"%s\"", inviteCode, req.SendTo)
|
app.info.Printf("%s: Sent invite email to \"%s\"", invite.Code, req.SendTo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,7 +235,7 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
|
|||||||
invite.Profile = "Default"
|
invite.Profile = "Default"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.storage.SetInvitesKey(inviteCode, invite)
|
app.storage.SetInvitesKey(invite.Code, invite)
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
api-ombi.go
42
api-ombi.go
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/hrfee/mediabrowser"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, int, error) {
|
func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, int, error) {
|
||||||
@ -29,7 +30,31 @@ func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, int, er
|
|||||||
return ombiUser, code, err
|
return ombiUser, code, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, 400, fmt.Errorf("Couldn't find user")
|
return nil, 400, fmt.Errorf("couldn't find user")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a user with the given name who has been imported from Jellyfin/Emby by Ombi
|
||||||
|
func (app *appContext) getOmbiImportedUser(name string) (map[string]interface{}, int, error) {
|
||||||
|
// Ombi User Types: 3/4 = Emby, 5 = Jellyfin
|
||||||
|
ombiUsers, code, err := app.ombi.GetUsers()
|
||||||
|
if err != nil || code != 200 {
|
||||||
|
return nil, code, err
|
||||||
|
}
|
||||||
|
for _, ombiUser := range ombiUsers {
|
||||||
|
if ombiUser["userName"].(string) == name {
|
||||||
|
uType, ok := ombiUser["userType"].(int)
|
||||||
|
if !ok { // Don't know if Ombi somehow allows duplicate usernames
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if serverType == mediabrowser.JellyfinServer && uType != 5 { // Jellyfin
|
||||||
|
continue
|
||||||
|
} else if uType != 3 && uType != 4 { // Emby
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return ombiUser, code, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, 400, fmt.Errorf("couldn't find user")
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Get a list of Ombi users.
|
// @Summary Get a list of Ombi users.
|
||||||
@ -107,3 +132,18 @@ func (app *appContext) DeleteOmbiProfile(gc *gin.Context) {
|
|||||||
app.storage.SetProfileKey(profileName, profile)
|
app.storage.SetProfileKey(profileName, profile)
|
||||||
respondBool(204, true, gc)
|
respondBool(204, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *appContext) applyOmbiProfile(user map[string]interface{}, profile map[string]interface{}) (status int, err error) {
|
||||||
|
for k, v := range profile {
|
||||||
|
switch v.(type) {
|
||||||
|
case map[string]interface{}, []interface{}:
|
||||||
|
user[k] = v
|
||||||
|
default:
|
||||||
|
if v != user[k] {
|
||||||
|
user[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status, err = app.ombi.ModifyUser(user)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/lithammer/shortuuid/v3"
|
|
||||||
"github.com/timshannon/badgerhold/v4"
|
"github.com/timshannon/badgerhold/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -106,6 +104,10 @@ func (app *appContext) CreateProfile(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.storage.SetProfileKey(req.Name, profile)
|
app.storage.SetProfileKey(req.Name, profile)
|
||||||
|
// Refresh discord bots, profile list
|
||||||
|
if discordEnabled {
|
||||||
|
app.discord.UpdateCommands()
|
||||||
|
}
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,13 +153,7 @@ func (app *appContext) EnableReferralForProfile(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate new code for referral template
|
// Generate new code for referral template
|
||||||
inv.Code = shortuuid.New()
|
inv.Code = GenerateInviteCode()
|
||||||
// make sure code doesn't begin with number
|
|
||||||
_, err := strconv.Atoi(string(inv.Code[0]))
|
|
||||||
for err == nil {
|
|
||||||
inv.Code = shortuuid.New()
|
|
||||||
_, err = strconv.Atoi(string(inv.Code[0]))
|
|
||||||
}
|
|
||||||
inv.Created = time.Now()
|
inv.Created = time.Now()
|
||||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||||
inv.IsReferral = true
|
inv.IsReferral = true
|
||||||
|
@ -3,13 +3,11 @@ package main
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/golang-jwt/jwt"
|
"github.com/golang-jwt/jwt"
|
||||||
"github.com/lithammer/shortuuid/v3"
|
|
||||||
"github.com/timshannon/badgerhold/v4"
|
"github.com/timshannon/badgerhold/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -673,13 +671,7 @@ func (app *appContext) GetMyReferral(gc *gin.Context) {
|
|||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
inv.Code = shortuuid.New()
|
inv.Code = GenerateInviteCode()
|
||||||
// make sure code doesn't begin with number
|
|
||||||
_, err := strconv.Atoi(string(inv.Code[0]))
|
|
||||||
for err == nil {
|
|
||||||
inv.Code = shortuuid.New()
|
|
||||||
_, err = strconv.Atoi(string(inv.Code[0]))
|
|
||||||
}
|
|
||||||
inv.Created = time.Now()
|
inv.Created = time.Now()
|
||||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||||
inv.IsReferral = true
|
inv.IsReferral = true
|
||||||
@ -689,13 +681,7 @@ func (app *appContext) GetMyReferral(gc *gin.Context) {
|
|||||||
// 3. We found an invite for us, but it's expired.
|
// 3. We found an invite for us, but it's expired.
|
||||||
// We delete it from storage, and put it back with a fresh code and expiry.
|
// We delete it from storage, and put it back with a fresh code and expiry.
|
||||||
app.storage.DeleteInvitesKey(inv.Code)
|
app.storage.DeleteInvitesKey(inv.Code)
|
||||||
inv.Code = shortuuid.New()
|
inv.Code = GenerateInviteCode()
|
||||||
// make sure code doesn't begin with number
|
|
||||||
_, err := strconv.Atoi(string(inv.Code[0]))
|
|
||||||
for err == nil {
|
|
||||||
inv.Code = shortuuid.New()
|
|
||||||
_, err = strconv.Atoi(string(inv.Code[0]))
|
|
||||||
}
|
|
||||||
inv.Created = time.Now()
|
inv.Created = time.Now()
|
||||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||||
app.storage.SetInvitesKey(inv.Code, inv)
|
app.storage.SetInvitesKey(inv.Code, inv)
|
||||||
|
47
api-users.go
47
api-users.go
@ -3,14 +3,12 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/golang-jwt/jwt"
|
"github.com/golang-jwt/jwt"
|
||||||
"github.com/hrfee/mediabrowser"
|
"github.com/hrfee/mediabrowser"
|
||||||
"github.com/lithammer/shortuuid/v3"
|
|
||||||
"github.com/timshannon/badgerhold/v4"
|
"github.com/timshannon/badgerhold/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -377,16 +375,34 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
if profile.Ombi != nil && len(profile.Ombi) != 0 {
|
if profile.Ombi != nil && len(profile.Ombi) != 0 {
|
||||||
template := profile.Ombi
|
template := profile.Ombi
|
||||||
errors, code, err := app.ombi.NewUser(req.Username, req.Password, req.Email, template)
|
errors, code, err := app.ombi.NewUser(req.Username, req.Password, req.Email, template)
|
||||||
|
accountExists := false
|
||||||
|
var ombiUser map[string]interface{}
|
||||||
if err != nil || code != 200 {
|
if err != nil || code != 200 {
|
||||||
|
// Check if on the off chance, Ombi's user importer has already added the account.
|
||||||
|
ombiUser, status, err = app.getOmbiImportedUser(req.Username)
|
||||||
|
if status == 200 && err == nil {
|
||||||
|
app.info.Println("Found existing Ombi user, applying changes")
|
||||||
|
accountExists = true
|
||||||
|
template["password"] = req.Password
|
||||||
|
status, err = app.applyOmbiProfile(ombiUser, template)
|
||||||
|
if status != 200 || err != nil {
|
||||||
|
app.err.Printf("Failed to modify existing Ombi user (%d): %v\n", status, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
app.info.Printf("Failed to create Ombi user (%d): %s", code, err)
|
app.info.Printf("Failed to create Ombi user (%d): %s", code, err)
|
||||||
app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", "))
|
app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", "))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
app.info.Println("Created Ombi user")
|
ombiUser, status, err = app.getOmbiUser(id)
|
||||||
if discordVerified || telegramVerified {
|
|
||||||
ombiUser, status, err := app.getOmbiUser(id)
|
|
||||||
if status != 200 || err != nil {
|
if status != 200 || err != nil {
|
||||||
app.err.Printf("Failed to get Ombi user (%d): %v", status, err)
|
app.err.Printf("Failed to get Ombi user (%d): %v", status, err)
|
||||||
} else {
|
} else {
|
||||||
|
app.info.Println("Created Ombi user")
|
||||||
|
accountExists = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if accountExists {
|
||||||
|
if discordVerified || telegramVerified {
|
||||||
dID := ""
|
dID := ""
|
||||||
tUser := ""
|
tUser := ""
|
||||||
if discordVerified {
|
if discordVerified {
|
||||||
@ -403,7 +419,6 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
app.debug.Printf("Skipping Ombi: Profile \"%s\" was empty", invite.Profile)
|
app.debug.Printf("Skipping Ombi: Profile \"%s\" was empty", invite.Profile)
|
||||||
}
|
}
|
||||||
@ -690,13 +705,7 @@ func (app *appContext) EnableReferralForUsers(gc *gin.Context) {
|
|||||||
|
|
||||||
// 2. Generate referral invite.
|
// 2. Generate referral invite.
|
||||||
inv := baseInv
|
inv := baseInv
|
||||||
inv.Code = shortuuid.New()
|
inv.Code = GenerateInviteCode()
|
||||||
// make sure code doesn't begin with number
|
|
||||||
_, err := strconv.Atoi(string(inv.Code[0]))
|
|
||||||
for err == nil {
|
|
||||||
inv.Code = shortuuid.New()
|
|
||||||
_, err = strconv.Atoi(string(inv.Code[0]))
|
|
||||||
}
|
|
||||||
inv.Created = time.Now()
|
inv.Created = time.Now()
|
||||||
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
inv.ValidTill = inv.Created.Add(REFERRAL_EXPIRY_DAYS * 24 * time.Hour)
|
||||||
inv.IsReferral = true
|
inv.IsReferral = true
|
||||||
@ -1214,17 +1223,7 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
// newUser["userName"] = user["userName"]
|
// newUser["userName"] = user["userName"]
|
||||||
// newUser["alias"] = user["alias"]
|
// newUser["alias"] = user["alias"]
|
||||||
// newUser["emailAddress"] = user["emailAddress"]
|
// newUser["emailAddress"] = user["emailAddress"]
|
||||||
for k, v := range ombi {
|
status, err = app.applyOmbiProfile(user, ombi)
|
||||||
switch v.(type) {
|
|
||||||
case map[string]interface{}, []interface{}:
|
|
||||||
user[k] = v
|
|
||||||
default:
|
|
||||||
if v != user[k] {
|
|
||||||
user[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
status, err = app.ombi.ModifyUser(user)
|
|
||||||
if status != 200 || err != nil {
|
if status != 200 || err != nil {
|
||||||
errorString += fmt.Sprintf("Apply %d: %v ", status, err)
|
errorString += fmt.Sprintf("Apply %d: %v ", status, err)
|
||||||
}
|
}
|
||||||
|
2
api.go
2
api.go
@ -182,7 +182,7 @@ func (app *appContext) ResetSetPassword(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
// Silently fail for changing ombi passwords
|
// Silently fail for changing ombi passwords
|
||||||
if status != 200 || err != nil {
|
if (status != 200 && status != 204) || err != nil {
|
||||||
app.err.Printf("Failed to get user \"%s\" from jellyfin/emby (%d): %v", username, status, err)
|
app.err.Printf("Failed to get user \"%s\" from jellyfin/emby (%d): %v", username, status, err)
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
return
|
return
|
||||||
|
@ -395,6 +395,123 @@
|
|||||||
"type": "password",
|
"type": "password",
|
||||||
"value": "",
|
"value": "",
|
||||||
"description": "Leave blank for no Authentication."
|
"description": "Leave blank for no Authentication."
|
||||||
|
},
|
||||||
|
"debug_log_emails": {
|
||||||
|
"name": "Debug Storage Logging: Emails",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "select",
|
||||||
|
"options": [
|
||||||
|
["none", "None"],
|
||||||
|
["all", "All Writes"],
|
||||||
|
["deletion", "Deletion Only*"]
|
||||||
|
],
|
||||||
|
"value": "none",
|
||||||
|
"description": "Extra debug logging for writes to the database. *: Deletion also includes blanking out major fields, e.g. an email address."
|
||||||
|
},
|
||||||
|
"debug_log_discord": {
|
||||||
|
"name": "Debug Storage Logging: Discord",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "select",
|
||||||
|
"options": [
|
||||||
|
["none", "None"],
|
||||||
|
["all", "All Writes"],
|
||||||
|
["deletion", "Deletion Only*"]
|
||||||
|
],
|
||||||
|
"value": "none",
|
||||||
|
"description": "Extra debug logging for writes to the database. *: Deletion also includes blanking out major fields, e.g. an email address."
|
||||||
|
},
|
||||||
|
"debug_log_telegram": {
|
||||||
|
"name": "Debug Storage Logging: Telegram",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "select",
|
||||||
|
"options": [
|
||||||
|
["none", "None"],
|
||||||
|
["all", "All Writes"],
|
||||||
|
["deletion", "Deletion Only*"]
|
||||||
|
],
|
||||||
|
"value": "none",
|
||||||
|
"description": "Extra debug logging for writes to the database. *: Deletion also includes blanking out major fields, e.g. an email address."
|
||||||
|
},
|
||||||
|
"debug_log_matrix": {
|
||||||
|
"name": "Debug Storage Logging: Matrix",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "select",
|
||||||
|
"options": [
|
||||||
|
["none", "None"],
|
||||||
|
["all", "All Writes"],
|
||||||
|
["deletion", "Deletion Only*"]
|
||||||
|
],
|
||||||
|
"value": "none",
|
||||||
|
"description": "Extra debug logging for writes to the database. *: Deletion also includes blanking out major fields, e.g. an email address."
|
||||||
|
},
|
||||||
|
"debug_log_invites": {
|
||||||
|
"name": "Debug Storage Logging: Invites",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "select",
|
||||||
|
"options": [
|
||||||
|
["none", "None"],
|
||||||
|
["all", "All Writes"],
|
||||||
|
["deletion", "Deletion Only*"]
|
||||||
|
],
|
||||||
|
"value": "none",
|
||||||
|
"description": "Extra debug logging for writes to the database. *: Deletion also includes blanking out major fields, e.g. an email address."
|
||||||
|
},
|
||||||
|
"debug_log_announcements": {
|
||||||
|
"name": "Debug Storage Logging: Announcements",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "select",
|
||||||
|
"options": [
|
||||||
|
["none", "None"],
|
||||||
|
["all", "All Writes"],
|
||||||
|
["deletion", "Deletion Only*"]
|
||||||
|
],
|
||||||
|
"value": "none",
|
||||||
|
"description": "Extra debug logging for writes to the database. *: Deletion also includes blanking out major fields, e.g. an email address."
|
||||||
|
},
|
||||||
|
"debug_log_expiries": {
|
||||||
|
"name": "Debug Storage Logging: User Expiries",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "select",
|
||||||
|
"options": [
|
||||||
|
["none", "None"],
|
||||||
|
["all", "All Writes"],
|
||||||
|
["deletion", "Deletion Only*"]
|
||||||
|
],
|
||||||
|
"value": "none",
|
||||||
|
"description": "Extra debug logging for writes to the database. *: Deletion also includes blanking out major fields, e.g. an email address."
|
||||||
|
},
|
||||||
|
"debug_log_profiles": {
|
||||||
|
"name": "Debug Storage Logging: Profiles",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "select",
|
||||||
|
"options": [
|
||||||
|
["none", "None"],
|
||||||
|
["all", "All Writes"],
|
||||||
|
["deletion", "Deletion Only*"]
|
||||||
|
],
|
||||||
|
"value": "none",
|
||||||
|
"description": "Extra debug logging for writes to the database. *: Deletion also includes blanking out major fields, e.g. an email address."
|
||||||
|
},
|
||||||
|
"debug_log_custom_content": {
|
||||||
|
"name": "Debug Storage Logging: Custom Message Content",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "select",
|
||||||
|
"options": [
|
||||||
|
["none", "None"],
|
||||||
|
["all", "All Writes"],
|
||||||
|
["deletion", "Deletion Only*"]
|
||||||
|
],
|
||||||
|
"value": "none",
|
||||||
|
"description": "Extra debug logging for writes to the database. *: Deletion also includes blanking out major fields, e.g. an email address."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
205
discord.go
205
discord.go
@ -24,6 +24,7 @@ type DiscordDaemon struct {
|
|||||||
app *appContext
|
app *appContext
|
||||||
commandHandlers map[string]func(s *dg.Session, i *dg.InteractionCreate, lang string)
|
commandHandlers map[string]func(s *dg.Session, i *dg.InteractionCreate, lang string)
|
||||||
commandIDs []string
|
commandIDs []string
|
||||||
|
commandDescriptions []*dg.ApplicationCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) {
|
func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) {
|
||||||
@ -50,6 +51,7 @@ func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) {
|
|||||||
dd.commandHandlers[app.config.Section("discord").Key("start_command").MustString("start")] = dd.cmdStart
|
dd.commandHandlers[app.config.Section("discord").Key("start_command").MustString("start")] = dd.cmdStart
|
||||||
dd.commandHandlers["lang"] = dd.cmdLang
|
dd.commandHandlers["lang"] = dd.cmdLang
|
||||||
dd.commandHandlers["pin"] = dd.cmdPIN
|
dd.commandHandlers["pin"] = dd.cmdPIN
|
||||||
|
dd.commandHandlers["inv"] = dd.cmdInvite
|
||||||
for _, user := range app.storage.GetDiscord() {
|
for _, user := range app.storage.GetDiscord() {
|
||||||
dd.users[user.ID] = user
|
dd.users[user.ID] = user
|
||||||
}
|
}
|
||||||
@ -127,6 +129,7 @@ func (d *DiscordDaemon) run() {
|
|||||||
d.inviteChannelName = invChannel
|
d.inviteChannelName = invChannel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
err = d.bot.UpdateGameStatus(0, "/"+d.app.config.Section("discord").Key("start_command").MustString("start"))
|
||||||
defer d.deregisterCommands()
|
defer d.deregisterCommands()
|
||||||
defer d.bot.Close()
|
defer d.bot.Close()
|
||||||
|
|
||||||
@ -220,7 +223,6 @@ func (d *DiscordDaemon) NewTempInvite(ageSeconds, maxUses int) (inviteURL, iconU
|
|||||||
d.app.err.Printf("Discord: Failed to get guild: %v", err)
|
d.app.err.Printf("Discord: Failed to get guild: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// FIXME: Fix CSS, and handle no icon
|
|
||||||
iconURL = guild.IconURL("256")
|
iconURL = guild.IconURL("256")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -308,7 +310,7 @@ func (d *DiscordDaemon) Shutdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DiscordDaemon) registerCommands() {
|
func (d *DiscordDaemon) registerCommands() {
|
||||||
commands := []*dg.ApplicationCommand{
|
d.commandDescriptions = []*dg.ApplicationCommand{
|
||||||
{
|
{
|
||||||
Name: d.app.config.Section("discord").Key("start_command").MustString("start"),
|
Name: d.app.config.Section("discord").Key("start_command").MustString("start"),
|
||||||
Description: "Start the Discord linking process. The bot will send further instructions.",
|
Description: "Start the Discord linking process. The bot will send further instructions.",
|
||||||
@ -338,26 +340,73 @@ func (d *DiscordDaemon) registerCommands() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "inv",
|
||||||
|
Description: "Send an invite to a discord user (admin only).",
|
||||||
|
Options: []*dg.ApplicationCommandOption{
|
||||||
|
{
|
||||||
|
Type: dg.ApplicationCommandOptionUser,
|
||||||
|
Name: "user",
|
||||||
|
Description: "User to Invite.",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: dg.ApplicationCommandOptionInteger,
|
||||||
|
Name: "expiry",
|
||||||
|
Description: "Time in minutes before expiration.",
|
||||||
|
Required: false,
|
||||||
|
},
|
||||||
|
/* Label should be automatically set to something like "Discord invite for @username"
|
||||||
|
{
|
||||||
|
Type: dg.ApplicationCommandOptionString,
|
||||||
|
Name: "label",
|
||||||
|
Description: "Label given to this invite (shown on the Admin page)",
|
||||||
|
Required: false,
|
||||||
|
}, */
|
||||||
|
{
|
||||||
|
Type: dg.ApplicationCommandOptionString,
|
||||||
|
Name: "user_label",
|
||||||
|
Description: "Label given to users created with this invite.",
|
||||||
|
Required: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: dg.ApplicationCommandOptionString,
|
||||||
|
Name: "profile",
|
||||||
|
Description: "Profile to apply to the created user.",
|
||||||
|
Required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
commands[1].Options[0].Choices = make([]*dg.ApplicationCommandOptionChoice, len(d.app.storage.lang.Telegram))
|
d.commandDescriptions[1].Options[0].Choices = make([]*dg.ApplicationCommandOptionChoice, len(d.app.storage.lang.Telegram))
|
||||||
i := 0
|
i := 0
|
||||||
for code := range d.app.storage.lang.Telegram {
|
for code := range d.app.storage.lang.Telegram {
|
||||||
d.app.debug.Printf("Registering choice \"%s\":\"%s\"\n", d.app.storage.lang.Telegram[code].Meta.Name, code)
|
d.app.debug.Printf("Discord: registering lang choice \"%s\":\"%s\"\n", d.app.storage.lang.Telegram[code].Meta.Name, code)
|
||||||
commands[1].Options[0].Choices[i] = &dg.ApplicationCommandOptionChoice{
|
d.commandDescriptions[1].Options[0].Choices[i] = &dg.ApplicationCommandOptionChoice{
|
||||||
Name: d.app.storage.lang.Telegram[code].Meta.Name,
|
Name: d.app.storage.lang.Telegram[code].Meta.Name,
|
||||||
Value: code,
|
Value: code,
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
profiles := d.app.storage.GetProfiles()
|
||||||
|
d.commandDescriptions[3].Options[3].Choices = make([]*dg.ApplicationCommandOptionChoice, len(profiles))
|
||||||
|
for i, profile := range profiles {
|
||||||
|
d.app.debug.Printf("Discord: registering profile choice \"%s\"", profile.Name)
|
||||||
|
d.commandDescriptions[3].Options[3].Choices[i] = &dg.ApplicationCommandOptionChoice{
|
||||||
|
Name: profile.Name,
|
||||||
|
Value: profile.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// d.deregisterCommands()
|
// d.deregisterCommands()
|
||||||
|
|
||||||
d.commandIDs = make([]string, len(commands))
|
d.commandIDs = make([]string, len(d.commandDescriptions))
|
||||||
// cCommands, err := d.bot.ApplicationCommandBulkOverwrite(d.bot.State.User.ID, d.guildID, commands)
|
// cCommands, err := d.bot.ApplicationCommandBulkOverwrite(d.bot.State.User.ID, d.guildID, commands)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// d.app.err.Printf("Discord: Cannot create commands: %v", err)
|
// d.app.err.Printf("Discord: Cannot create commands: %v", err)
|
||||||
// }
|
// }
|
||||||
for i, cmd := range commands {
|
for i, cmd := range d.commandDescriptions {
|
||||||
command, err := d.bot.ApplicationCommandCreate(d.bot.State.User.ID, d.guildID, cmd)
|
command, err := d.bot.ApplicationCommandCreate(d.bot.State.User.ID, d.guildID, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.app.err.Printf("Discord: Cannot create command \"%s\": %v", cmd.Name, err)
|
d.app.err.Printf("Discord: Cannot create command \"%s\": %v", cmd.Name, err)
|
||||||
@ -375,12 +424,32 @@ func (d *DiscordDaemon) deregisterCommands() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, cmd := range existingCommands {
|
for _, cmd := range existingCommands {
|
||||||
if err := d.bot.ApplicationCommandDelete(d.bot.State.User.ID, "", cmd.ID); err != nil {
|
if err := d.bot.ApplicationCommandDelete(d.bot.State.User.ID, d.guildID, cmd.ID); err != nil {
|
||||||
d.app.err.Printf("Failed to deregister command: %v", err)
|
d.app.err.Printf("Discord: Failed to deregister command: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateCommands updates commands which have defined lists of options, to be used when changes occur.
|
||||||
|
func (d *DiscordDaemon) UpdateCommands() {
|
||||||
|
// Reload Profile List
|
||||||
|
profiles := d.app.storage.GetProfiles()
|
||||||
|
d.commandDescriptions[3].Options[3].Choices = make([]*dg.ApplicationCommandOptionChoice, len(profiles))
|
||||||
|
for i, profile := range profiles {
|
||||||
|
d.app.debug.Printf("Discord: registering profile choice \"%s\"", profile.Name)
|
||||||
|
d.commandDescriptions[3].Options[3].Choices[i] = &dg.ApplicationCommandOptionChoice{
|
||||||
|
Name: profile.Name,
|
||||||
|
Value: profile.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd, err := d.bot.ApplicationCommandEdit(d.bot.State.User.ID, d.guildID, d.commandIDs[3], d.commandDescriptions[3])
|
||||||
|
if err != nil {
|
||||||
|
d.app.err.Printf("Discord: Failed to update profile list: %v\n", err)
|
||||||
|
} else {
|
||||||
|
d.commandIDs[3] = cmd.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DiscordDaemon) commandHandler(s *dg.Session, i *dg.InteractionCreate) {
|
func (d *DiscordDaemon) commandHandler(s *dg.Session, i *dg.InteractionCreate) {
|
||||||
if h, ok := d.commandHandlers[i.ApplicationCommandData().Name]; ok {
|
if h, ok := d.commandHandlers[i.ApplicationCommandData().Name]; ok {
|
||||||
if i.GuildID != "" && d.channelName != "" {
|
if i.GuildID != "" && d.channelName != "" {
|
||||||
@ -503,6 +572,124 @@ func (d *DiscordDaemon) cmdLang(s *dg.Session, i *dg.InteractionCreate, lang str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DiscordDaemon) cmdInvite(s *dg.Session, i *dg.InteractionCreate, lang string) {
|
||||||
|
channel, err := s.UserChannelCreate(i.Interaction.Member.User.ID)
|
||||||
|
if err != nil {
|
||||||
|
d.app.err.Printf("Discord: Failed to create private channel with \"%s\": %v", i.Interaction.Member.User.Username, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
requester := d.MustGetUser(channel.ID, i.Interaction.Member.User.ID, i.Interaction.Member.User.Discriminator, i.Interaction.Member.User.Username)
|
||||||
|
d.users[i.Interaction.Member.User.ID] = requester
|
||||||
|
recipient := i.ApplicationCommandData().Options[0].UserValue(s)
|
||||||
|
// d.app.debug.Println(invuser)
|
||||||
|
//label := i.ApplicationCommandData().Options[2].StringValue()
|
||||||
|
//profile := i.ApplicationCommandData().Options[3].StringValue()
|
||||||
|
//mins, err := strconv.Atoi(i.ApplicationCommandData().Options[1].StringValue())
|
||||||
|
//if mins > 0 {
|
||||||
|
// expmin = mins
|
||||||
|
//}
|
||||||
|
// Check whether requestor is linked to the admin account
|
||||||
|
requesterEmail, ok := d.app.storage.GetEmailsKey(requester.JellyfinID)
|
||||||
|
if !ok {
|
||||||
|
d.app.err.Printf("Failed to verify admin")
|
||||||
|
}
|
||||||
|
if !requesterEmail.Admin {
|
||||||
|
d.app.err.Printf("User is not admin")
|
||||||
|
//add response message
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var expiryMinutes int64 = 30
|
||||||
|
userLabel := ""
|
||||||
|
profileName := ""
|
||||||
|
|
||||||
|
for i, opt := range i.ApplicationCommandData().Options {
|
||||||
|
if i == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch opt.Name {
|
||||||
|
case "expiry":
|
||||||
|
expiryMinutes = opt.IntValue()
|
||||||
|
case "user_label":
|
||||||
|
userLabel = opt.StringValue()
|
||||||
|
case "profile":
|
||||||
|
profileName = opt.StringValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTime := time.Now()
|
||||||
|
|
||||||
|
validTill := currentTime.Add(time.Minute * time.Duration(expiryMinutes))
|
||||||
|
|
||||||
|
invite := Invite{
|
||||||
|
Code: GenerateInviteCode(),
|
||||||
|
Created: currentTime,
|
||||||
|
RemainingUses: 1,
|
||||||
|
UserExpiry: false,
|
||||||
|
ValidTill: validTill,
|
||||||
|
UserLabel: userLabel,
|
||||||
|
Profile: "Default",
|
||||||
|
Label: fmt.Sprintf("Discord: %s", RenderDiscordUsername(recipient)),
|
||||||
|
}
|
||||||
|
if profileName != "" {
|
||||||
|
if _, ok := d.app.storage.GetProfileKey(profileName); ok {
|
||||||
|
invite.Profile = profileName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if recipient != nil && d.app.config.Section("invite_emails").Key("enabled").MustBool(false) {
|
||||||
|
d.app.debug.Printf("%s: Sending invite message", invite.Code)
|
||||||
|
invname, err := d.bot.GuildMember(d.guildID, recipient.ID)
|
||||||
|
invite.SendTo = invname.User.Username
|
||||||
|
msg, err := d.app.email.constructInvite(invite.Code, invite, d.app, false)
|
||||||
|
if err != nil {
|
||||||
|
invite.SendTo = fmt.Sprintf("Failed to send to %s", RenderDiscordUsername(recipient))
|
||||||
|
d.app.err.Printf("%s: Failed to construct invite message: %v", invite.Code, err)
|
||||||
|
err := s.InteractionRespond(i.Interaction, &dg.InteractionResponse{
|
||||||
|
Type: dg.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &dg.InteractionResponseData{
|
||||||
|
Content: d.app.storage.lang.Telegram[lang].Strings.get("sentInviteFailure"),
|
||||||
|
Flags: 64, // Ephemeral
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", RenderDiscordUsername(requester), err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
err = d.app.discord.SendDM(msg, recipient.ID)
|
||||||
|
if err != nil {
|
||||||
|
invite.SendTo = fmt.Sprintf("Failed to send to %s", RenderDiscordUsername(recipient))
|
||||||
|
d.app.err.Printf("%s: %s: %v", invite.Code, invite.SendTo, err)
|
||||||
|
err := s.InteractionRespond(i.Interaction, &dg.InteractionResponse{
|
||||||
|
Type: dg.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &dg.InteractionResponseData{
|
||||||
|
Content: d.app.storage.lang.Telegram[lang].Strings.get("sentInviteFailure"),
|
||||||
|
Flags: 64, // Ephemeral
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", RenderDiscordUsername(requester), err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d.app.info.Printf("%s: Sent invite email to \"%s\"", invite.Code, RenderDiscordUsername(recipient))
|
||||||
|
err := s.InteractionRespond(i.Interaction, &dg.InteractionResponse{
|
||||||
|
Type: dg.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &dg.InteractionResponseData{
|
||||||
|
Content: d.app.storage.lang.Telegram[lang].Strings.get("sentInvite"),
|
||||||
|
Flags: 64, // Ephemeral
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", RenderDiscordUsername(requester), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if profile != "" {
|
||||||
|
d.app.storage.SetInvitesKey(invite.Code, invite)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DiscordDaemon) messageHandler(s *dg.Session, m *dg.MessageCreate) {
|
func (d *DiscordDaemon) messageHandler(s *dg.Session, m *dg.MessageCreate) {
|
||||||
if m.GuildID != "" && d.channelName != "" {
|
if m.GuildID != "" && d.channelName != "" {
|
||||||
if d.channelID == "" {
|
if d.channelID == "" {
|
||||||
|
@ -118,7 +118,14 @@
|
|||||||
"userPagePage": "Page utilisateur : Page",
|
"userPagePage": "Page utilisateur : Page",
|
||||||
"after": "Après",
|
"after": "Après",
|
||||||
"before": "Avant",
|
"before": "Avant",
|
||||||
"unlink": "Délier le compte"
|
"unlink": "Délier le compte",
|
||||||
|
"enableReferrals": "Activer Parrainage",
|
||||||
|
"enableReferralsDescription": "Offrez aux utilisateurs un lien de parrainage personnel semblable à une invitation, à envoyer à vos amis/famille. Peut provenir modèle de profil ou d’une invitation existante.",
|
||||||
|
"invite": "Inviter",
|
||||||
|
"userLabel": "Étiquette",
|
||||||
|
"userLabelDescription": "Étiquette à appliquer aux utilisateurs créés avec cette invitation.",
|
||||||
|
"disableReferrals": "Désactiver Parrainage",
|
||||||
|
"enableReferralsProfileDescription": "Donnez aux utilisateurs créés avec ce profil un lien de parrainage personnel semblable à une invitation, à envoyer à vos amis/famille. Créez une invitation avec les paramètres souhaités, puis sélectionnez-la ici. Chaque référence sera alors basée sur cette invitation. Vous pouvez supprimer l'invitation une fois terminée."
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"changedEmailAddress": "Adresse e-mail modifiée de {n}.",
|
"changedEmailAddress": "Adresse e-mail modifiée de {n}.",
|
||||||
@ -156,7 +163,9 @@
|
|||||||
"accountConnected": "Compte connecté.",
|
"accountConnected": "Compte connecté.",
|
||||||
"savedAnnouncement": "Annonce enregistrée.",
|
"savedAnnouncement": "Annonce enregistrée.",
|
||||||
"setOmbiProfile": "Profil ombi enregistré.",
|
"setOmbiProfile": "Profil ombi enregistré.",
|
||||||
"errorSetOmbiProfile": "Echec de la sauvegarde du profil ombi."
|
"errorSetOmbiProfile": "Echec de la sauvegarde du profil ombi.",
|
||||||
|
"errorNoReferralTemplate": "Le profil ne contient pas de modèle de référence, ajoutez-en un dans les paramètres.",
|
||||||
|
"referralsEnabled": "Parrainage activer."
|
||||||
},
|
},
|
||||||
"quantityStrings": {
|
"quantityStrings": {
|
||||||
"modifySettingsFor": {
|
"modifySettingsFor": {
|
||||||
@ -214,6 +223,10 @@
|
|||||||
"setExpiry": {
|
"setExpiry": {
|
||||||
"singular": "Définir l'expiration pour {n} utilisateur",
|
"singular": "Définir l'expiration pour {n} utilisateur",
|
||||||
"plural": "Définir l'expiration pour {n} utilisateurs"
|
"plural": "Définir l'expiration pour {n} utilisateurs"
|
||||||
|
},
|
||||||
|
"enableReferralsFor": {
|
||||||
|
"singular": "Activer les parrainages pour {n} utilisateur",
|
||||||
|
"plural": "Activer les parrainages pour {n} utilisateur"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"name": "Angol (US)"
|
"name": "Magyar (HU)"
|
||||||
},
|
},
|
||||||
"strings": {
|
"strings": {
|
||||||
"invites": "Meghívások",
|
"invites": "Meghívások",
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"strings": {
|
"strings": {
|
||||||
"username": "Nom d'utilisateur",
|
"username": "Nom d'utilisateur",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
"emailAddress": "Adresse courriel",
|
"emailAddress": "Adresse Email",
|
||||||
"name": "Nom",
|
"name": "Nom",
|
||||||
"submit": "Soumettre",
|
"submit": "Soumettre",
|
||||||
"send": "Envoyer",
|
"send": "Envoyer",
|
||||||
@ -29,7 +29,7 @@
|
|||||||
"logout": "Se déconnecter",
|
"logout": "Se déconnecter",
|
||||||
"admin": "Administrateur",
|
"admin": "Administrateur",
|
||||||
"enabled": "Activé",
|
"enabled": "Activé",
|
||||||
"disabled": "Désactivé",
|
"disabled": "Désactiver",
|
||||||
"reEnable": "Ré-activé",
|
"reEnable": "Ré-activé",
|
||||||
"disable": "Désactivé",
|
"disable": "Désactivé",
|
||||||
"expiry": "Expiration",
|
"expiry": "Expiration",
|
||||||
@ -40,7 +40,8 @@
|
|||||||
"accountStatus": "Statut du compte",
|
"accountStatus": "Statut du compte",
|
||||||
"notSet": "Non défini",
|
"notSet": "Non défini",
|
||||||
"myAccount": "Mon compte",
|
"myAccount": "Mon compte",
|
||||||
"contactMethods": "Moyens de contact"
|
"contactMethods": "Moyens de contact",
|
||||||
|
"referrals": "Programme de parrainage"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Le nom d'utilisateur et/ou le mot de passe sont vides.",
|
"errorLoginBlank": "Le nom d'utilisateur et/ou le mot de passe sont vides.",
|
||||||
@ -51,16 +52,16 @@
|
|||||||
},
|
},
|
||||||
"quantityStrings": {
|
"quantityStrings": {
|
||||||
"year": {
|
"year": {
|
||||||
"plural": "{n] années",
|
"plural": "{n} années",
|
||||||
"singular": "{n] année"
|
"singular": "{n} année"
|
||||||
},
|
},
|
||||||
"day": {
|
"day": {
|
||||||
"singular": "{n] jour",
|
"singular": "{n} jour",
|
||||||
"plural": "{n] jours"
|
"plural": "{n} jours"
|
||||||
},
|
},
|
||||||
"month": {
|
"month": {
|
||||||
"singular": "{n] mois",
|
"singular": "{n} mois",
|
||||||
"plural": "{n] mois"
|
"plural": "{n} mois"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"name": "Angol (US)"
|
"name": "Magyar (HU)"
|
||||||
},
|
},
|
||||||
"strings": {
|
"strings": {
|
||||||
"login": "Belépés",
|
"login": "Belépés",
|
||||||
|
@ -23,7 +23,22 @@
|
|||||||
"expiry": "Löper ut",
|
"expiry": "Löper ut",
|
||||||
"edit": "Redigera",
|
"edit": "Redigera",
|
||||||
"delete": "Radera",
|
"delete": "Radera",
|
||||||
"inviteRemainingUses": "Återstående användningar"
|
"inviteRemainingUses": "Återstående användningar",
|
||||||
|
"send": "Skicka",
|
||||||
|
"linkDiscord": "Länka Discord",
|
||||||
|
"copied": "Kopierat",
|
||||||
|
"linkTelegram": "Länka Telegram",
|
||||||
|
"contactEmail": "Kontakta via e-post",
|
||||||
|
"contactTelegram": "Kontakta via Telegram",
|
||||||
|
"refresh": "Uppdatera",
|
||||||
|
"required": "Obligatoriskt",
|
||||||
|
"contactDiscord": "Kontakt via Discord",
|
||||||
|
"linkMatrix": "Länka Matrix",
|
||||||
|
"reEnable": "Återaktivera",
|
||||||
|
"disable": "Inaktivera",
|
||||||
|
"contactMethods": "Kontaktmetoder",
|
||||||
|
"accountStatus": "Kontostatus",
|
||||||
|
"notSet": "Inte inställt"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Användarnamnet och/eller lösenordet lämnades tomt.",
|
"errorLoginBlank": "Användarnamnet och/eller lösenordet lämnades tomt.",
|
||||||
@ -31,6 +46,5 @@
|
|||||||
"errorUnknown": "Okänt fel.",
|
"errorUnknown": "Okänt fel.",
|
||||||
"error401Unauthorized": "Obehörig. Prova att uppdatera sidan.",
|
"error401Unauthorized": "Obehörig. Prova att uppdatera sidan.",
|
||||||
"errorSaveSettings": "Det gick inte att spara inställningarna."
|
"errorSaveSettings": "Det gick inte att spara inställningarna."
|
||||||
},
|
}
|
||||||
"quantityStrings": {}
|
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"name": "Angol (US)"
|
"name": "Magyar (HU)"
|
||||||
},
|
},
|
||||||
"strings": {
|
"strings": {
|
||||||
"ifItWasNotYou": "",
|
"ifItWasNotYou": "",
|
@ -7,11 +7,11 @@
|
|||||||
"pageTitle": "Créer un compte Jellyfin",
|
"pageTitle": "Créer un compte Jellyfin",
|
||||||
"createAccountHeader": "Création du compte",
|
"createAccountHeader": "Création du compte",
|
||||||
"accountDetails": "Détails",
|
"accountDetails": "Détails",
|
||||||
"emailAddress": "Courriel",
|
"emailAddress": "Email",
|
||||||
"username": "Nom d'utilisateur",
|
"username": "Nom d'utilisateur",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
"reEnterPassword": "Confirmez mot de passe",
|
"reEnterPassword": "Confirmez mot de passe",
|
||||||
"reEnterPasswordInvalid": "Les mots de passe ne correspondent pas.",
|
"reEnterPasswordInvalid": "Les mots de passe ne sont pas pareils.",
|
||||||
"createAccountButton": "Créer le compte",
|
"createAccountButton": "Créer le compte",
|
||||||
"passwordRequirementsHeader": "Mot de passe requis",
|
"passwordRequirementsHeader": "Mot de passe requis",
|
||||||
"successHeader": "Succès !",
|
"successHeader": "Succès !",
|
||||||
@ -35,7 +35,10 @@
|
|||||||
"editContactMethod": "Modifier le moyen de contact",
|
"editContactMethod": "Modifier le moyen de contact",
|
||||||
"joinTheServer": "Rejoindre le serveur :",
|
"joinTheServer": "Rejoindre le serveur :",
|
||||||
"customMessagePlaceholderHeader": "Personnaliser cette carte",
|
"customMessagePlaceholderHeader": "Personnaliser cette carte",
|
||||||
"resetPassword": "Réinitialisation de mot de passe"
|
"resetPassword": "Réinitialisation mot de passe",
|
||||||
|
"referralsDescription": "Invitez vos amis et votre famille à Jellyfin avec ce lien. Revenez ici pour en obtenir un nouveau s'il expire.",
|
||||||
|
"copyReferral": "Copier le lien",
|
||||||
|
"invitedBy": "Vous avez été invité par l'utilisateur {user}."
|
||||||
},
|
},
|
||||||
"validationStrings": {
|
"validationStrings": {
|
||||||
"length": {
|
"length": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"name": "Angol (US)"
|
"name": "Magyar (HU)"
|
||||||
},
|
},
|
||||||
"strings": {
|
"strings": {
|
||||||
"pageTitle": "Jellyfin fiók létrehozása",
|
"pageTitle": "Jellyfin fiók létrehozása",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"name": "Angol (US)"
|
"name": "Magyar (HU)"
|
||||||
},
|
},
|
||||||
"strings": {
|
"strings": {
|
||||||
"passwordReset": "Jelszó visszaállítás",
|
"passwordReset": "Jelszó visszaállítás",
|
@ -8,7 +8,7 @@
|
|||||||
"back": "Retour",
|
"back": "Retour",
|
||||||
"optional": "Optionnel",
|
"optional": "Optionnel",
|
||||||
"serverType": "Type de serveur",
|
"serverType": "Type de serveur",
|
||||||
"disabled": "Désactivé",
|
"disabled": "Désactiver",
|
||||||
"enabled": "Activé",
|
"enabled": "Activé",
|
||||||
"port": "Port",
|
"port": "Port",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"name": "Angol (US)"
|
"name": "Magyar (HU)"
|
||||||
},
|
},
|
||||||
"strings": {
|
"strings": {
|
||||||
"pageTitle": "Telepítés - jfa-go",
|
"pageTitle": "Telepítés - jfa-go",
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
"languageMessage": "Note: See available languages with {command}, and set language with {command} <language code>.",
|
"languageMessage": "Note: See available languages with {command}, and set language with {command} <language code>.",
|
||||||
"languageMessageDiscord": "Note: set your language with /lang <language name>.",
|
"languageMessageDiscord": "Note: set your language with /lang <language name>.",
|
||||||
"languageSet": "Language set to {language}.",
|
"languageSet": "Language set to {language}.",
|
||||||
"discordDMs": "Please check your DMs for a response."
|
"discordDMs": "Please check your DMs for a response.",
|
||||||
|
"sentInvite": "Sent invite.",
|
||||||
|
"sentInviteFailure": "Failed to send invite, check logs."
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"meta": {
|
"meta": {
|
||||||
"name": "Angol (US)"
|
"name": "Magyar (HU)"
|
||||||
},
|
},
|
||||||
"strings": {
|
"strings": {
|
||||||
"startMessage": "Helló!\nAdd meg a Jellyfin PIN kódodat itt, hogy megerősítsd a fiókodat.",
|
"startMessage": "Helló!\nAdd meg a Jellyfin PIN kódodat itt, hogy megerősítsd a fiókodat.",
|
@ -28,9 +28,10 @@ type Logger struct {
|
|||||||
fatalFunc func(err interface{})
|
fatalFunc func(err interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Lshortfile() string {
|
// Lshortfile is a re-implemented log.Lshortfile with a modifiable call level.
|
||||||
|
func Lshortfile(level int) string {
|
||||||
// 0 = This function, 1 = Print/Printf/Println, 2 = Caller of Print/Printf/Println
|
// 0 = This function, 1 = Print/Printf/Println, 2 = Caller of Print/Printf/Println
|
||||||
_, file, line, ok := runtime.Caller(2)
|
_, file, line, ok := runtime.Caller(level)
|
||||||
lineString := strconv.Itoa(line)
|
lineString := strconv.Itoa(line)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ""
|
return ""
|
||||||
@ -47,6 +48,10 @@ func Lshortfile() string {
|
|||||||
return file + ":" + lineString + ":"
|
return file + ":" + lineString + ":"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lshortfile() string {
|
||||||
|
return Lshortfile(2)
|
||||||
|
}
|
||||||
|
|
||||||
func NewLogger(out io.Writer, prefix string, flag int, color c.Attribute) (l *Logger) {
|
func NewLogger(out io.Writer, prefix string, flag int, color c.Attribute) (l *Logger) {
|
||||||
l = &Logger{}
|
l = &Logger{}
|
||||||
// Use reimplemented Lshortfile since wrapping the log functions messes them up
|
// Use reimplemented Lshortfile since wrapping the log functions messes them up
|
||||||
@ -73,7 +78,7 @@ func (l *Logger) Printf(format string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
var out string
|
var out string
|
||||||
if l.shortfile {
|
if l.shortfile {
|
||||||
out = Lshortfile()
|
out = lshortfile()
|
||||||
}
|
}
|
||||||
out += " " + l.printer.Sprintf(format, v...)
|
out += " " + l.printer.Sprintf(format, v...)
|
||||||
l.logger.Print(out)
|
l.logger.Print(out)
|
||||||
@ -85,7 +90,7 @@ func (l *Logger) Print(v ...interface{}) {
|
|||||||
}
|
}
|
||||||
var out string
|
var out string
|
||||||
if l.shortfile {
|
if l.shortfile {
|
||||||
out = Lshortfile()
|
out = lshortfile()
|
||||||
}
|
}
|
||||||
out += " " + l.printer.Sprint(v...)
|
out += " " + l.printer.Sprint(v...)
|
||||||
l.logger.Print(out)
|
l.logger.Print(out)
|
||||||
@ -97,7 +102,7 @@ func (l *Logger) Println(v ...interface{}) {
|
|||||||
}
|
}
|
||||||
var out string
|
var out string
|
||||||
if l.shortfile {
|
if l.shortfile {
|
||||||
out = Lshortfile()
|
out = lshortfile()
|
||||||
}
|
}
|
||||||
out += " " + l.printer.Sprintln(v...)
|
out += " " + l.printer.Sprintln(v...)
|
||||||
l.logger.Print(out)
|
l.logger.Print(out)
|
||||||
@ -109,7 +114,7 @@ func (l *Logger) Fatal(v ...interface{}) {
|
|||||||
}
|
}
|
||||||
var out string
|
var out string
|
||||||
if l.shortfile {
|
if l.shortfile {
|
||||||
out = Lshortfile()
|
out = lshortfile()
|
||||||
}
|
}
|
||||||
out += " " + l.printer.Sprint(v...)
|
out += " " + l.printer.Sprint(v...)
|
||||||
l.logger.Fatal(out)
|
l.logger.Fatal(out)
|
||||||
@ -121,7 +126,7 @@ func (l *Logger) Fatalf(format string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
var out string
|
var out string
|
||||||
if l.shortfile {
|
if l.shortfile {
|
||||||
out = Lshortfile()
|
out = lshortfile()
|
||||||
}
|
}
|
||||||
out += " " + l.printer.Sprintf(format, v...)
|
out += " " + l.printer.Sprintf(format, v...)
|
||||||
if l.fatalFunc != nil {
|
if l.fatalFunc != nil {
|
||||||
|
4
main.go
4
main.go
@ -246,8 +246,12 @@ func start(asDaemon, firstCall bool) {
|
|||||||
}
|
}
|
||||||
if debugMode {
|
if debugMode {
|
||||||
app.debug = logger.NewLogger(os.Stdout, "[DEBUG] ", log.Ltime|log.Lshortfile, color.FgYellow)
|
app.debug = logger.NewLogger(os.Stdout, "[DEBUG] ", log.Ltime|log.Lshortfile, color.FgYellow)
|
||||||
|
// Bind debug log
|
||||||
|
app.storage.debug = app.debug
|
||||||
|
app.storage.logActions = generateLogActions(app.config)
|
||||||
} else {
|
} else {
|
||||||
app.debug = logger.NewEmptyLogger()
|
app.debug = logger.NewEmptyLogger()
|
||||||
|
app.storage.debug = nil
|
||||||
}
|
}
|
||||||
if *PPROF {
|
if *PPROF {
|
||||||
app.info.Print(warning("\n\nWARNING: Don't use pprof in production.\n\n"))
|
app.info.Print(warning("\n\nWARNING: Don't use pprof in production.\n\n"))
|
||||||
|
101
storage.go
101
storage.go
@ -10,8 +10,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hrfee/jfa-go/logger"
|
||||||
"github.com/hrfee/mediabrowser"
|
"github.com/hrfee/mediabrowser"
|
||||||
"github.com/timshannon/badgerhold/v4"
|
"github.com/timshannon/badgerhold/v4"
|
||||||
|
"gopkg.in/ini.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type discordStore map[string]DiscordUser
|
type discordStore map[string]DiscordUser
|
||||||
@ -24,7 +26,18 @@ type UserExpiry struct {
|
|||||||
Expiry time.Time
|
Expiry time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DebugLogAction int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NoLog DebugLogAction = iota
|
||||||
|
LogAll
|
||||||
|
LogDeletion // Logs deletion, and wiping of main field in new data, e.g. setting email.addr to "".
|
||||||
|
)
|
||||||
|
|
||||||
type Storage struct {
|
type Storage struct {
|
||||||
|
debug *logger.Logger
|
||||||
|
logActions map[string]DebugLogAction
|
||||||
|
|
||||||
timePattern string
|
timePattern string
|
||||||
|
|
||||||
db_path string
|
db_path string
|
||||||
@ -47,6 +60,76 @@ type Storage struct {
|
|||||||
lang Lang
|
lang Lang
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StoreType int
|
||||||
|
|
||||||
|
// Used for debug logging of storage.
|
||||||
|
const (
|
||||||
|
StoredEmails StoreType = iota
|
||||||
|
StoredDiscord
|
||||||
|
StoredTelegram
|
||||||
|
StoredMatrix
|
||||||
|
StoredInvites
|
||||||
|
StoredAnnouncements
|
||||||
|
StoredExpiries
|
||||||
|
StoredProfiles
|
||||||
|
StoredCustomContent
|
||||||
|
)
|
||||||
|
|
||||||
|
// DebugWatch logs database writes according on the advanced debugging settings in the Advanced section
|
||||||
|
func (st *Storage) DebugWatch(storeType StoreType, key, mainData string) {
|
||||||
|
if st.debug == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
actionKey := ""
|
||||||
|
switch storeType {
|
||||||
|
case StoredEmails:
|
||||||
|
actionKey = "emails"
|
||||||
|
case StoredDiscord:
|
||||||
|
actionKey = "discord"
|
||||||
|
case StoredTelegram:
|
||||||
|
actionKey = "telegram"
|
||||||
|
case StoredMatrix:
|
||||||
|
actionKey = "matrix"
|
||||||
|
case StoredInvites:
|
||||||
|
actionKey = "invites"
|
||||||
|
case StoredAnnouncements:
|
||||||
|
actionKey = "announcements"
|
||||||
|
case StoredExpiries:
|
||||||
|
actionKey = "expiries"
|
||||||
|
case StoredProfiles:
|
||||||
|
actionKey = "profiles"
|
||||||
|
case StoredCustomContent:
|
||||||
|
actionKey = "custom_content"
|
||||||
|
}
|
||||||
|
|
||||||
|
logAction := st.logActions[actionKey]
|
||||||
|
if logAction == NoLog {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
actionString := "WRITE"
|
||||||
|
if mainData == "" {
|
||||||
|
actionString = "DELETE"
|
||||||
|
}
|
||||||
|
if logAction == LogAll || mainData == "" {
|
||||||
|
st.debug.Printf("%s @ %s %s[%s] = \"%s\"\n", actionString, logger.Lshortfile(3), actionKey, key, mainData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateLogActions(c *ini.File) map[string]DebugLogAction {
|
||||||
|
m := map[string]DebugLogAction{}
|
||||||
|
for _, v := range []string{"emails", "discord", "telegram", "matrix", "invites", "announcements", "expirires", "profiles", "custom_content"} {
|
||||||
|
switch c.Section("advanced").Key("debug_log_" + v).MustString("none") {
|
||||||
|
case "none":
|
||||||
|
m[v] = NoLog
|
||||||
|
case "all":
|
||||||
|
m[v] = LogAll
|
||||||
|
case "deletion":
|
||||||
|
m[v] = LogDeletion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
func (app *appContext) ConnectDB() {
|
func (app *appContext) ConnectDB() {
|
||||||
opts := badgerhold.DefaultOptions
|
opts := badgerhold.DefaultOptions
|
||||||
opts.Dir = app.storage.db_path
|
opts.Dir = app.storage.db_path
|
||||||
@ -83,6 +166,7 @@ func (st *Storage) GetEmailsKey(k string) (EmailAddress, bool) {
|
|||||||
|
|
||||||
// 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.DebugWatch(StoredEmails, k, v.Addr)
|
||||||
v.JellyfinID = k
|
v.JellyfinID = k
|
||||||
err := st.db.Upsert(k, v)
|
err := st.db.Upsert(k, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -92,6 +176,7 @@ func (st *Storage) SetEmailsKey(k string, v EmailAddress) {
|
|||||||
|
|
||||||
// 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.DebugWatch(StoredEmails, k, "")
|
||||||
st.db.Delete(k, EmailAddress{})
|
st.db.Delete(k, EmailAddress{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +204,7 @@ func (st *Storage) GetDiscordKey(k string) (DiscordUser, bool) {
|
|||||||
|
|
||||||
// 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.DebugWatch(StoredDiscord, k, v.Username)
|
||||||
v.JellyfinID = k
|
v.JellyfinID = k
|
||||||
err := st.db.Upsert(k, v)
|
err := st.db.Upsert(k, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -128,6 +214,7 @@ func (st *Storage) SetDiscordKey(k string, v DiscordUser) {
|
|||||||
|
|
||||||
// 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.DebugWatch(StoredDiscord, k, "")
|
||||||
st.db.Delete(k, DiscordUser{})
|
st.db.Delete(k, DiscordUser{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +242,7 @@ func (st *Storage) GetTelegramKey(k string) (TelegramUser, bool) {
|
|||||||
|
|
||||||
// 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.DebugWatch(StoredTelegram, k, v.Username)
|
||||||
v.JellyfinID = k
|
v.JellyfinID = k
|
||||||
err := st.db.Upsert(k, v)
|
err := st.db.Upsert(k, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -164,6 +252,7 @@ func (st *Storage) SetTelegramKey(k string, v TelegramUser) {
|
|||||||
|
|
||||||
// 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.DebugWatch(StoredTelegram, k, "")
|
||||||
st.db.Delete(k, TelegramUser{})
|
st.db.Delete(k, TelegramUser{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,6 +280,7 @@ func (st *Storage) GetMatrixKey(k string) (MatrixUser, bool) {
|
|||||||
|
|
||||||
// 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.DebugWatch(StoredMatrix, k, v.UserID)
|
||||||
v.JellyfinID = k
|
v.JellyfinID = k
|
||||||
err := st.db.Upsert(k, v)
|
err := st.db.Upsert(k, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -200,6 +290,7 @@ func (st *Storage) SetMatrixKey(k string, v MatrixUser) {
|
|||||||
|
|
||||||
// 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.DebugWatch(StoredMatrix, k, "")
|
||||||
st.db.Delete(k, MatrixUser{})
|
st.db.Delete(k, MatrixUser{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,6 +318,7 @@ func (st *Storage) GetInvitesKey(k string) (Invite, bool) {
|
|||||||
|
|
||||||
// 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.DebugWatch(StoredInvites, k, "changed") // Not sure what the main data from this would be
|
||||||
v.Code = k
|
v.Code = k
|
||||||
err := st.db.Upsert(k, v)
|
err := st.db.Upsert(k, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -236,6 +328,7 @@ func (st *Storage) SetInvitesKey(k string, v Invite) {
|
|||||||
|
|
||||||
// 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.DebugWatch(StoredInvites, k, "")
|
||||||
st.db.Delete(k, Invite{})
|
st.db.Delete(k, Invite{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,6 +356,7 @@ func (st *Storage) GetAnnouncementsKey(k string) (announcementTemplate, bool) {
|
|||||||
|
|
||||||
// SetAnnouncementsKey stores value v in key k.
|
// SetAnnouncementsKey stores value v in key k.
|
||||||
func (st *Storage) SetAnnouncementsKey(k string, v announcementTemplate) {
|
func (st *Storage) SetAnnouncementsKey(k string, v announcementTemplate) {
|
||||||
|
st.DebugWatch(StoredAnnouncements, k, v.Subject)
|
||||||
err := st.db.Upsert(k, v)
|
err := st.db.Upsert(k, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// fmt.Printf("Failed to set announcement: %v\n", err)
|
// fmt.Printf("Failed to set announcement: %v\n", err)
|
||||||
@ -271,6 +365,7 @@ func (st *Storage) SetAnnouncementsKey(k string, v announcementTemplate) {
|
|||||||
|
|
||||||
// DeleteAnnouncementsKey deletes value at key k.
|
// DeleteAnnouncementsKey deletes value at key k.
|
||||||
func (st *Storage) DeleteAnnouncementsKey(k string) {
|
func (st *Storage) DeleteAnnouncementsKey(k string) {
|
||||||
|
st.DebugWatch(StoredAnnouncements, k, "")
|
||||||
st.db.Delete(k, announcementTemplate{})
|
st.db.Delete(k, announcementTemplate{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,6 +393,7 @@ func (st *Storage) GetUserExpiryKey(k string) (UserExpiry, bool) {
|
|||||||
|
|
||||||
// SetUserExpiryKey stores value v in key k.
|
// SetUserExpiryKey stores value v in key k.
|
||||||
func (st *Storage) SetUserExpiryKey(k string, v UserExpiry) {
|
func (st *Storage) SetUserExpiryKey(k string, v UserExpiry) {
|
||||||
|
st.DebugWatch(StoredExpiries, k, v.Expiry.String())
|
||||||
v.JellyfinID = k
|
v.JellyfinID = k
|
||||||
err := st.db.Upsert(k, v)
|
err := st.db.Upsert(k, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -307,6 +403,7 @@ func (st *Storage) SetUserExpiryKey(k string, v UserExpiry) {
|
|||||||
|
|
||||||
// DeleteUserExpiryKey deletes value at key k.
|
// DeleteUserExpiryKey deletes value at key k.
|
||||||
func (st *Storage) DeleteUserExpiryKey(k string) {
|
func (st *Storage) DeleteUserExpiryKey(k string) {
|
||||||
|
st.DebugWatch(StoredExpiries, k, "")
|
||||||
st.db.Delete(k, UserExpiry{})
|
st.db.Delete(k, UserExpiry{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,6 +434,7 @@ func (st *Storage) GetProfileKey(k string) (Profile, bool) {
|
|||||||
|
|
||||||
// SetProfileKey stores value v in key k.
|
// SetProfileKey stores value v in key k.
|
||||||
func (st *Storage) SetProfileKey(k string, v Profile) {
|
func (st *Storage) SetProfileKey(k string, v Profile) {
|
||||||
|
st.DebugWatch(StoredProfiles, k, "changed")
|
||||||
v.Name = k
|
v.Name = k
|
||||||
v.Admin = v.Policy.IsAdministrator
|
v.Admin = v.Policy.IsAdministrator
|
||||||
if v.Policy.EnabledFolders != nil {
|
if v.Policy.EnabledFolders != nil {
|
||||||
@ -357,6 +455,7 @@ func (st *Storage) SetProfileKey(k string, v Profile) {
|
|||||||
|
|
||||||
// DeleteProfileKey deletes value at key k.
|
// DeleteProfileKey deletes value at key k.
|
||||||
func (st *Storage) DeleteProfileKey(k string) {
|
func (st *Storage) DeleteProfileKey(k string) {
|
||||||
|
st.DebugWatch(StoredProfiles, k, "")
|
||||||
st.db.Delete(k, Profile{})
|
st.db.Delete(k, Profile{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,6 +500,7 @@ func (st *Storage) MustGetCustomContentKey(k string) CustomContent {
|
|||||||
|
|
||||||
// SetCustomContentKey stores value v in key k.
|
// SetCustomContentKey stores value v in key k.
|
||||||
func (st *Storage) SetCustomContentKey(k string, v CustomContent) {
|
func (st *Storage) SetCustomContentKey(k string, v CustomContent) {
|
||||||
|
st.DebugWatch(StoredCustomContent, k, "changed")
|
||||||
v.Name = k
|
v.Name = k
|
||||||
err := st.db.Upsert(k, v)
|
err := st.db.Upsert(k, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -410,6 +510,7 @@ func (st *Storage) SetCustomContentKey(k string, v CustomContent) {
|
|||||||
|
|
||||||
// DeleteCustomContentKey deletes value at key k.
|
// DeleteCustomContentKey deletes value at key k.
|
||||||
func (st *Storage) DeleteCustomContentKey(k string) {
|
func (st *Storage) DeleteCustomContentKey(k string) {
|
||||||
|
st.DebugWatch(StoredCustomContent, k, "")
|
||||||
st.db.Delete(k, CustomContent{})
|
st.db.Delete(k, CustomContent{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user