mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-26 19:10:10 +00:00
Compare commits
3 Commits
35f8337a36
...
2a6937228c
Author | SHA1 | Date | |
---|---|---|---|
2a6937228c | |||
785395dd20 | |||
385953b0cb |
@ -5,6 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/hrfee/jfa-go/jellyseerr"
|
||||||
"github.com/lithammer/shortuuid/v3"
|
"github.com/lithammer/shortuuid/v3"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
)
|
)
|
||||||
@ -322,6 +323,14 @@ func (app *appContext) TelegramAddUser(gc *gin.Context) {
|
|||||||
tgUser.Lang = lang
|
tgUser.Lang = lang
|
||||||
}
|
}
|
||||||
app.storage.SetTelegramKey(req.ID, tgUser)
|
app.storage.SetTelegramKey(req.ID, tgUser)
|
||||||
|
|
||||||
|
if err := app.js.ModifyNotifications(gc.GetString("jfId"), map[jellyseerr.NotificationsField]any{
|
||||||
|
jellyseerr.FieldTelegram: tgUser.ChatID,
|
||||||
|
jellyseerr.FieldTelegramEnabled: tgUser.Contact,
|
||||||
|
}); err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact methods with Jellyseerr: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
linkExistingOmbiDiscordTelegram(app)
|
linkExistingOmbiDiscordTelegram(app)
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
@ -346,6 +355,7 @@ func (app *appContext) SetContactMethods(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Context) {
|
func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Context) {
|
||||||
|
jsPrefs := map[jellyseerr.NotificationsField]any{}
|
||||||
if tgUser, ok := app.storage.GetTelegramKey(req.ID); ok {
|
if tgUser, ok := app.storage.GetTelegramKey(req.ID); ok {
|
||||||
change := tgUser.Contact != req.Telegram
|
change := tgUser.Contact != req.Telegram
|
||||||
tgUser.Contact = req.Telegram
|
tgUser.Contact = req.Telegram
|
||||||
@ -356,6 +366,7 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
|
|||||||
msg = " not"
|
msg = " not"
|
||||||
}
|
}
|
||||||
app.debug.Printf("Telegram: User \"%s\" will%s be notified through Telegram.", tgUser.Username, msg)
|
app.debug.Printf("Telegram: User \"%s\" will%s be notified through Telegram.", tgUser.Username, msg)
|
||||||
|
jsPrefs[jellyseerr.FieldTelegramEnabled] = req.Telegram
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dcUser, ok := app.storage.GetDiscordKey(req.ID); ok {
|
if dcUser, ok := app.storage.GetDiscordKey(req.ID); ok {
|
||||||
@ -368,6 +379,7 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
|
|||||||
msg = " not"
|
msg = " not"
|
||||||
}
|
}
|
||||||
app.debug.Printf("Discord: User \"%s\" will%s be notified through Discord.", dcUser.Username, msg)
|
app.debug.Printf("Discord: User \"%s\" will%s be notified through Discord.", dcUser.Username, msg)
|
||||||
|
jsPrefs[jellyseerr.FieldDiscordEnabled] = req.Discord
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mxUser, ok := app.storage.GetMatrixKey(req.ID); ok {
|
if mxUser, ok := app.storage.GetMatrixKey(req.ID); ok {
|
||||||
@ -392,6 +404,13 @@ func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Conte
|
|||||||
msg = " not"
|
msg = " not"
|
||||||
}
|
}
|
||||||
app.debug.Printf("\"%s\" will%s be notified via Email.", email.Addr, msg)
|
app.debug.Printf("\"%s\" will%s be notified via Email.", email.Addr, msg)
|
||||||
|
jsPrefs[jellyseerr.FieldEmailEnabled] = req.Email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if app.config.Section("jellyseerr").Key("enabled").MustBool(false) {
|
||||||
|
err := app.js.ModifyNotifications(req.ID, jsPrefs)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact prefs with Jellyseerr: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
@ -678,6 +697,13 @@ func (app *appContext) DiscordConnect(gc *gin.Context) {
|
|||||||
|
|
||||||
app.storage.SetDiscordKey(req.JellyfinID, user)
|
app.storage.SetDiscordKey(req.JellyfinID, user)
|
||||||
|
|
||||||
|
if err := app.js.ModifyNotifications(req.JellyfinID, map[jellyseerr.NotificationsField]any{
|
||||||
|
jellyseerr.FieldDiscord: req.DiscordID,
|
||||||
|
jellyseerr.FieldDiscordEnabled: true,
|
||||||
|
}); err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact methods with Jellyseerr: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
||||||
Type: ActivityContactLinked,
|
Type: ActivityContactLinked,
|
||||||
UserID: req.JellyfinID,
|
UserID: req.JellyfinID,
|
||||||
@ -708,6 +734,14 @@ func (app *appContext) UnlinkDiscord(gc *gin.Context) {
|
|||||||
} */
|
} */
|
||||||
app.storage.DeleteDiscordKey(req.ID)
|
app.storage.DeleteDiscordKey(req.ID)
|
||||||
|
|
||||||
|
// May not actually remove Discord ID, but should disable interaction.
|
||||||
|
if err := app.js.ModifyNotifications(gc.GetString("jfId"), map[jellyseerr.NotificationsField]any{
|
||||||
|
jellyseerr.FieldDiscord: jellyseerr.BogusIdentifier,
|
||||||
|
jellyseerr.FieldDiscordEnabled: false,
|
||||||
|
}); err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact methods with Jellyseerr: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
||||||
Type: ActivityContactUnlinked,
|
Type: ActivityContactUnlinked,
|
||||||
UserID: req.ID,
|
UserID: req.ID,
|
||||||
@ -737,6 +771,13 @@ func (app *appContext) UnlinkTelegram(gc *gin.Context) {
|
|||||||
} */
|
} */
|
||||||
app.storage.DeleteTelegramKey(req.ID)
|
app.storage.DeleteTelegramKey(req.ID)
|
||||||
|
|
||||||
|
if err := app.js.ModifyNotifications(gc.GetString("jfId"), map[jellyseerr.NotificationsField]any{
|
||||||
|
jellyseerr.FieldTelegram: jellyseerr.BogusIdentifier,
|
||||||
|
jellyseerr.FieldTelegramEnabled: false,
|
||||||
|
}); err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact methods with Jellyseerr: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
||||||
Type: ActivityContactUnlinked,
|
Type: ActivityContactUnlinked,
|
||||||
UserID: req.ID,
|
UserID: req.ID,
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/golang-jwt/jwt"
|
"github.com/golang-jwt/jwt"
|
||||||
|
"github.com/hrfee/jfa-go/jellyseerr"
|
||||||
"github.com/lithammer/shortuuid/v3"
|
"github.com/lithammer/shortuuid/v3"
|
||||||
"github.com/timshannon/badgerhold/v4"
|
"github.com/timshannon/badgerhold/v4"
|
||||||
)
|
)
|
||||||
@ -200,14 +201,7 @@ func (app *appContext) confirmMyAction(gc *gin.Context, key string) {
|
|||||||
gc.Redirect(http.StatusSeeOther, "/my/account")
|
gc.Redirect(http.StatusSeeOther, "/my/account")
|
||||||
return
|
return
|
||||||
} else if target == UserEmailChange {
|
} else if target == UserEmailChange {
|
||||||
emailStore, ok := app.storage.GetEmailsKey(id)
|
app.modifyEmail(id, claims["email"].(string))
|
||||||
if !ok {
|
|
||||||
emailStore = EmailAddress{
|
|
||||||
Contact: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
emailStore.Addr = claims["email"].(string)
|
|
||||||
app.storage.SetEmailsKey(id, emailStore)
|
|
||||||
|
|
||||||
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
||||||
Type: ActivityContactLinked,
|
Type: ActivityContactLinked,
|
||||||
@ -218,17 +212,6 @@ func (app *appContext) confirmMyAction(gc *gin.Context, key string) {
|
|||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
}, gc, true)
|
}, gc, true)
|
||||||
|
|
||||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
|
||||||
ombiUser, code, err := app.getOmbiUser(id)
|
|
||||||
if code == 200 && err == nil {
|
|
||||||
ombiUser["emailAddress"] = claims["email"].(string)
|
|
||||||
code, err = app.ombi.ModifyUser(ombiUser)
|
|
||||||
if code != 200 || err != nil {
|
|
||||||
app.err.Printf("%s: Failed to change ombi email address (%d): %v", ombiUser["userName"].(string), code, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
@ -371,6 +354,13 @@ func (app *appContext) MyDiscordVerifiedInvite(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
app.storage.SetDiscordKey(gc.GetString("jfId"), dcUser)
|
app.storage.SetDiscordKey(gc.GetString("jfId"), dcUser)
|
||||||
|
|
||||||
|
if err := app.js.ModifyNotifications(gc.GetString("jfId"), map[jellyseerr.NotificationsField]any{
|
||||||
|
jellyseerr.FieldDiscord: dcUser.ID,
|
||||||
|
jellyseerr.FieldDiscordEnabled: dcUser.Contact,
|
||||||
|
}); err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact methods with Jellyseerr: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
||||||
Type: ActivityContactLinked,
|
Type: ActivityContactLinked,
|
||||||
UserID: gc.GetString("jfId"),
|
UserID: gc.GetString("jfId"),
|
||||||
@ -419,6 +409,13 @@ func (app *appContext) MyTelegramVerifiedInvite(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
app.storage.SetTelegramKey(gc.GetString("jfId"), tgUser)
|
app.storage.SetTelegramKey(gc.GetString("jfId"), tgUser)
|
||||||
|
|
||||||
|
if err := app.js.ModifyNotifications(gc.GetString("jfId"), map[jellyseerr.NotificationsField]any{
|
||||||
|
jellyseerr.FieldTelegram: tgUser.ChatID,
|
||||||
|
jellyseerr.FieldTelegramEnabled: tgUser.Contact,
|
||||||
|
}); err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact methods with Jellyseerr: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
||||||
Type: ActivityContactLinked,
|
Type: ActivityContactLinked,
|
||||||
UserID: gc.GetString("jfId"),
|
UserID: gc.GetString("jfId"),
|
||||||
@ -522,6 +519,13 @@ func (app *appContext) MatrixCheckMyPIN(gc *gin.Context) {
|
|||||||
func (app *appContext) UnlinkMyDiscord(gc *gin.Context) {
|
func (app *appContext) UnlinkMyDiscord(gc *gin.Context) {
|
||||||
app.storage.DeleteDiscordKey(gc.GetString("jfId"))
|
app.storage.DeleteDiscordKey(gc.GetString("jfId"))
|
||||||
|
|
||||||
|
if err := app.js.ModifyNotifications(gc.GetString("jfId"), map[jellyseerr.NotificationsField]any{
|
||||||
|
jellyseerr.FieldDiscord: jellyseerr.BogusIdentifier,
|
||||||
|
jellyseerr.FieldDiscordEnabled: false,
|
||||||
|
}); err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact methods with Jellyseerr: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
||||||
Type: ActivityContactUnlinked,
|
Type: ActivityContactUnlinked,
|
||||||
UserID: gc.GetString("jfId"),
|
UserID: gc.GetString("jfId"),
|
||||||
@ -543,6 +547,13 @@ func (app *appContext) UnlinkMyDiscord(gc *gin.Context) {
|
|||||||
func (app *appContext) UnlinkMyTelegram(gc *gin.Context) {
|
func (app *appContext) UnlinkMyTelegram(gc *gin.Context) {
|
||||||
app.storage.DeleteTelegramKey(gc.GetString("jfId"))
|
app.storage.DeleteTelegramKey(gc.GetString("jfId"))
|
||||||
|
|
||||||
|
if err := app.js.ModifyNotifications(gc.GetString("jfId"), map[jellyseerr.NotificationsField]any{
|
||||||
|
jellyseerr.FieldTelegram: jellyseerr.BogusIdentifier,
|
||||||
|
jellyseerr.FieldTelegramEnabled: false,
|
||||||
|
}); err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact methods with Jellyseerr: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
app.storage.SetActivityKey(shortuuid.New(), Activity{
|
||||||
Type: ActivityContactUnlinked,
|
Type: ActivityContactUnlinked,
|
||||||
UserID: gc.GetString("jfId"),
|
UserID: gc.GetString("jfId"),
|
||||||
|
69
api-users.go
69
api-users.go
@ -516,7 +516,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool, gc *gin.Context)
|
|||||||
}
|
}
|
||||||
contactMethods := map[jellyseerr.NotificationsField]any{}
|
contactMethods := map[jellyseerr.NotificationsField]any{}
|
||||||
if emailEnabled {
|
if emailEnabled {
|
||||||
err = app.js.ModifyUser(id, map[jellyseerr.UserField]any{jellyseerr.FieldEmail: req.Email})
|
err = app.js.ModifyMainUserSettings(id, jellyseerr.MainUserSettings{Email: req.Email})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.err.Printf("Failed to set Jellyseerr email address: %v\n", err)
|
app.err.Printf("Failed to set Jellyseerr email address: %v\n", err)
|
||||||
} else {
|
} else {
|
||||||
@ -1258,6 +1258,44 @@ func (app *appContext) ModifyLabels(gc *gin.Context) {
|
|||||||
respondBool(204, true, gc)
|
respondBool(204, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *appContext) modifyEmail(jfID string, addr string) {
|
||||||
|
contactPrefChanged := false
|
||||||
|
emailStore, ok := app.storage.GetEmailsKey(jfID)
|
||||||
|
// Auto enable contact by email for newly added addresses
|
||||||
|
if !ok || emailStore.Addr == "" {
|
||||||
|
emailStore = EmailAddress{
|
||||||
|
Contact: true,
|
||||||
|
}
|
||||||
|
contactPrefChanged = true
|
||||||
|
}
|
||||||
|
emailStore.Addr = addr
|
||||||
|
app.storage.SetEmailsKey(jfID, emailStore)
|
||||||
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
|
ombiUser, code, err := app.getOmbiUser(jfID)
|
||||||
|
if code == 200 && err == nil {
|
||||||
|
ombiUser["emailAddress"] = addr
|
||||||
|
code, err = app.ombi.ModifyUser(ombiUser)
|
||||||
|
if code != 200 || err != nil {
|
||||||
|
app.err.Printf("%s: Failed to change ombi email address (%d): %v", ombiUser["userName"].(string), code, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if app.config.Section("jellyseerr").Key("enabled").MustBool(false) {
|
||||||
|
err := app.js.ModifyMainUserSettings(jfID, jellyseerr.MainUserSettings{Email: addr})
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to set Jellyseerr email address: %v\n", err)
|
||||||
|
} else if contactPrefChanged {
|
||||||
|
contactMethods := map[jellyseerr.NotificationsField]any{
|
||||||
|
jellyseerr.FieldEmailEnabled: true,
|
||||||
|
}
|
||||||
|
err := app.js.ModifyNotifications(jfID, contactMethods)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact methods with Jellyseerr: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @Summary Modify user's email addresses.
|
// @Summary Modify user's email addresses.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param modifyEmailsDTO body modifyEmailsDTO true "Map of userIDs to email addresses"
|
// @Param modifyEmailsDTO body modifyEmailsDTO true "Map of userIDs to email addresses"
|
||||||
@ -1276,22 +1314,10 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
|
|||||||
respond(500, "Couldn't get users", gc)
|
respond(500, "Couldn't get users", gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
|
|
||||||
for _, jfUser := range users {
|
for _, jfUser := range users {
|
||||||
id := jfUser.ID
|
id := jfUser.ID
|
||||||
if address, ok := req[id]; ok {
|
if address, ok := req[id]; ok {
|
||||||
var emailStore = EmailAddress{}
|
app.modifyEmail(id, address)
|
||||||
oldEmail, ok := app.storage.GetEmailsKey(id)
|
|
||||||
if ok {
|
|
||||||
emailStore = oldEmail
|
|
||||||
}
|
|
||||||
// Auto enable contact by email for newly added addresses
|
|
||||||
if !ok || oldEmail.Addr == "" {
|
|
||||||
emailStore.Contact = true
|
|
||||||
}
|
|
||||||
|
|
||||||
emailStore.Addr = address
|
|
||||||
app.storage.SetEmailsKey(id, emailStore)
|
|
||||||
|
|
||||||
activityType := ActivityContactLinked
|
activityType := ActivityContactLinked
|
||||||
if address == "" {
|
if address == "" {
|
||||||
@ -1305,17 +1331,6 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
|
|||||||
Value: "email",
|
Value: "email",
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
}, gc, false)
|
}, gc, false)
|
||||||
|
|
||||||
if ombiEnabled {
|
|
||||||
ombiUser, code, err := app.getOmbiUser(id)
|
|
||||||
if code == 200 && err == nil {
|
|
||||||
ombiUser["emailAddress"] = address
|
|
||||||
code, err = app.ombi.ModifyUser(ombiUser)
|
|
||||||
if code != 200 || err != nil {
|
|
||||||
app.err.Printf("%s: Failed to change ombi email address (%d): %v", ombiUser["userName"].(string), code, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.info.Println("Email list modified")
|
app.info.Println("Email list modified")
|
||||||
@ -1359,12 +1374,12 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
displayprefs = profile.Displayprefs
|
displayprefs = profile.Displayprefs
|
||||||
}
|
}
|
||||||
policy = profile.Policy
|
policy = profile.Policy
|
||||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
if req.Ombi && app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
if profile.Ombi != nil && len(profile.Ombi) != 0 {
|
if profile.Ombi != nil && len(profile.Ombi) != 0 {
|
||||||
ombi = profile.Ombi
|
ombi = profile.Ombi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if app.config.Section("jellyseerr").Key("enabled").MustBool(false) {
|
if req.Jellyseerr && app.config.Section("jellyseerr").Key("enabled").MustBool(false) {
|
||||||
if profile.Jellyseerr.Enabled {
|
if profile.Jellyseerr.Enabled {
|
||||||
jellyseerr = profile.Jellyseerr
|
jellyseerr = profile.Jellyseerr
|
||||||
}
|
}
|
||||||
|
@ -1595,6 +1595,14 @@
|
|||||||
"value": false,
|
"value": false,
|
||||||
"description": "Enable the Jellyseerr integration."
|
"description": "Enable the Jellyseerr integration."
|
||||||
},
|
},
|
||||||
|
"usertype_note": {
|
||||||
|
"name": "Password Changes:",
|
||||||
|
"type": "note",
|
||||||
|
"value": "",
|
||||||
|
"depends_true": "enabled",
|
||||||
|
"required": "false",
|
||||||
|
"description": "Ensure existing users on Jellyseerr are \"Jellyfin User\"s not \"Local User\"s, as password changes are not synced with Jellyseerr."
|
||||||
|
},
|
||||||
"server": {
|
"server": {
|
||||||
"name": "URL",
|
"name": "URL",
|
||||||
"required": false,
|
"required": false,
|
||||||
|
@ -84,30 +84,40 @@
|
|||||||
<form class="card relative mx-auto my-[10%] w-11/12 sm:w-4/5 lg:w-1/3" id="form-modify-user" href="">
|
<form class="card relative mx-auto my-[10%] w-11/12 sm:w-4/5 lg:w-1/3" id="form-modify-user" href="">
|
||||||
<span class="heading"><span id="header-modify-user"></span> <span class="modal-close">×</span></span>
|
<span class="heading"><span id="header-modify-user"></span> <span class="modal-close">×</span></span>
|
||||||
<p class="content my-4">{{ .strings.modifySettingsDescription }}</p>
|
<p class="content my-4">{{ .strings.modifySettingsDescription }}</p>
|
||||||
<div class="flex flex-row mb-4">
|
<div class="flex flex-col gap-4 my-2">
|
||||||
<label class="grow mr-2">
|
<div class="flex flex-row gap-2">
|
||||||
<input type="radio" name="modify-user-source" class="unfocused" id="radio-use-profile" checked>
|
<label class="grow">
|
||||||
<span class="button ~neutral @high supra full-width center">{{ .strings.profile }}</span>
|
<input type="radio" name="modify-user-source" class="unfocused" id="radio-use-profile" checked>
|
||||||
|
<span class="button ~neutral @high supra full-width center">{{ .strings.profile }}</span>
|
||||||
|
</label>
|
||||||
|
<label class="grow">
|
||||||
|
<input type="radio" name="modify-user-source" class="unfocused" id="radio-use-user">
|
||||||
|
<span class="button ~neutral @low supra full-width center">{{ .strings.user }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="select ~neutral @low">
|
||||||
|
<select id="modify-user-profiles"></select>
|
||||||
|
</div>
|
||||||
|
<div class="select ~neutral @low unfocused">
|
||||||
|
<select id="modify-user-users"></select>
|
||||||
|
</div>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" id="modify-user-homescreen" checked>
|
||||||
|
<span>{{ .strings.applyHomescreenLayout }}</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="grow ml-2">
|
<label class="switch">
|
||||||
<input type="radio" name="modify-user-source" class="unfocused" id="radio-use-user">
|
<input type="checkbox" id="modify-user-ombi" checked>
|
||||||
<span class="button ~neutral @low supra full-width center">{{ .strings.user }}</span>
|
<span>{{ .strings.applyOmbi }}</span>
|
||||||
|
</label>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" id="modify-user-jellyseerr" checked>
|
||||||
|
<span>{{ .strings.applyJellyseerr }}</span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="submit" class="unfocused">
|
||||||
|
<span class="button ~urge @low full-width center supra submit">{{ .strings.apply }}</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="select ~neutral @low mb-4">
|
|
||||||
<select id="modify-user-profiles"></select>
|
|
||||||
</div>
|
|
||||||
<div class="select ~neutral @low mb-4 unfocused">
|
|
||||||
<select id="modify-user-users"></select>
|
|
||||||
</div>
|
|
||||||
<label class="switch mb-4">
|
|
||||||
<input type="checkbox" id="modify-user-homescreen" checked>
|
|
||||||
<span>{{ .strings.applyHomescreenLayout }}</span>
|
|
||||||
</label>
|
|
||||||
<label>
|
|
||||||
<input type="submit" class="unfocused">
|
|
||||||
<span class="button ~urge @low full-width center supra submit">{{ .strings.apply }}</span>
|
|
||||||
</label>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{{ if .referralsEnabled }}
|
{{ if .referralsEnabled }}
|
||||||
|
@ -16,7 +16,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
API_SUFFIX = "/api/v1"
|
API_SUFFIX = "/api/v1"
|
||||||
|
BogusIdentifier = "123412341234123456"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Jellyseerr represents a running Jellyseerr instance.
|
// Jellyseerr represents a running Jellyseerr instance.
|
||||||
@ -300,6 +301,9 @@ func (js *Jellyseerr) ApplyTemplateToUser(jfID string, tmpl UserTemplate) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (js *Jellyseerr) ModifyUser(jfID string, conf map[UserField]any) error {
|
func (js *Jellyseerr) ModifyUser(jfID string, conf map[UserField]any) error {
|
||||||
|
if _, ok := conf[FieldEmail]; ok {
|
||||||
|
return fmt.Errorf("email is read only, set with ModifyMainUserSettings instead")
|
||||||
|
}
|
||||||
u, err := js.MustGetUser(jfID)
|
u, err := js.MustGetUser(jfID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -408,3 +412,21 @@ func (js *Jellyseerr) UserByID(jellyseerrID int64) (User, error) {
|
|||||||
err = json.Unmarshal([]byte(resp), &data)
|
err = json.Unmarshal([]byte(resp), &data)
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (js *Jellyseerr) ModifyMainUserSettings(jfID string, conf MainUserSettings) error {
|
||||||
|
u, err := js.MustGetUser(jfID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, status, err := js.put(fmt.Sprintf(js.server+"/user/%d/settings/main", u.ID), conf, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if status != 200 && status != 201 {
|
||||||
|
return fmt.Errorf("failed (error %d)", status)
|
||||||
|
}
|
||||||
|
// Lazily just invalidate the cache.
|
||||||
|
js.cacheExpiry = time.Now()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -115,3 +115,18 @@ type NotificationsTemplate struct {
|
|||||||
WebPushEnabled bool `json:"webPushEnabled,omitempty"`
|
WebPushEnabled bool `json:"webPushEnabled,omitempty"`
|
||||||
NotifTypes NotificationTypes `json:"notificationTypes"`
|
NotifTypes NotificationTypes `json:"notificationTypes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MainUserSettings struct {
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
Email string `json:"email,omitempty"`
|
||||||
|
DiscordID string `json:"discordId,omitempty"`
|
||||||
|
Locale string `json:"locale,omitempty"`
|
||||||
|
Region string `json:"region,omitempty"`
|
||||||
|
OriginalLanguage any `json:"originalLanguage,omitempty"`
|
||||||
|
MovieQuotaLimit any `json:"movieQuotaLimit,omitempty"`
|
||||||
|
MovieQuotaDays any `json:"movieQuotaDays,omitempty"`
|
||||||
|
TvQuotaLimit any `json:"tvQuotaLimit,omitempty"`
|
||||||
|
TvQuotaDays any `json:"tvQuotaDays,omitempty"`
|
||||||
|
WatchlistSyncMovies any `json:"watchlistSyncMovies,omitempty"`
|
||||||
|
WatchlistSyncTv any `json:"watchlistSyncTv,omitempty"`
|
||||||
|
}
|
||||||
|
@ -81,6 +81,8 @@
|
|||||||
"useInviteExpiry": "Set expiry from profile/invite",
|
"useInviteExpiry": "Set expiry from profile/invite",
|
||||||
"useInviteExpiryNote": "By default, invites expire after 90 days but can be renewed by the user. Enable for the referral to be disabled after the time set.",
|
"useInviteExpiryNote": "By default, invites expire after 90 days but can be renewed by the user. Enable for the referral to be disabled after the time set.",
|
||||||
"applyHomescreenLayout": "Apply homescreen layout",
|
"applyHomescreenLayout": "Apply homescreen layout",
|
||||||
|
"applyOmbi": "Apply Ombi profile (if available)",
|
||||||
|
"applyJellyseerr": "Apply Jellyseerr profile (if available)",
|
||||||
"sendDeleteNotificationEmail": "Send notification message",
|
"sendDeleteNotificationEmail": "Send notification message",
|
||||||
"sendDeleteNotifiationExample": "Your account has been deleted.",
|
"sendDeleteNotifiationExample": "Your account has been deleted.",
|
||||||
"settingsRestart": "Restart",
|
"settingsRestart": "Restart",
|
||||||
|
2
main.go
2
main.go
@ -369,7 +369,7 @@ func start(asDaemon, firstCall bool) {
|
|||||||
app.config.Section("jellyseerr").Key("api_key").String(),
|
app.config.Section("jellyseerr").Key("api_key").String(),
|
||||||
common.NewTimeoutHandler("Jellyseerr", jellyseerrServer, true),
|
common.NewTimeoutHandler("Jellyseerr", jellyseerrServer, true),
|
||||||
)
|
)
|
||||||
app.js.LogRequestBodies = true
|
// app.js.LogRequestBodies = true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +179,8 @@ type userSettingsDTO struct {
|
|||||||
ApplyTo []string `json:"apply_to"` // Users to apply settings to
|
ApplyTo []string `json:"apply_to"` // Users to apply settings to
|
||||||
ID string `json:"id"` // ID of user (if from = "user")
|
ID string `json:"id"` // ID of user (if from = "user")
|
||||||
Homescreen bool `json:"homescreen"` // Whether to apply homescreen layout or not
|
Homescreen bool `json:"homescreen"` // Whether to apply homescreen layout or not
|
||||||
|
Ombi bool `json:"ombi"` // Whether to apply ombi profile or not
|
||||||
|
Jellyseerr bool `json:"jellyseerr"` // Whether to apply jellyseerr profile or not
|
||||||
}
|
}
|
||||||
|
|
||||||
type announcementDTO struct {
|
type announcementDTO struct {
|
||||||
|
@ -187,6 +187,7 @@ login.onLogin = () => {
|
|||||||
console.log("Logged in.");
|
console.log("Logged in.");
|
||||||
window.updater = new Updater();
|
window.updater = new Updater();
|
||||||
// FIXME: Decide whether to autoload activity or not
|
// FIXME: Decide whether to autoload activity or not
|
||||||
|
window.invites.reload()
|
||||||
setInterval(() => { window.invites.reload(); accounts.reload(); }, 30*1000);
|
setInterval(() => { window.invites.reload(); accounts.reload(); }, 30*1000);
|
||||||
const currentTab = window.tabs.current;
|
const currentTab = window.tabs.current;
|
||||||
switch (currentTab) {
|
switch (currentTab) {
|
||||||
|
@ -795,6 +795,10 @@ export class accountsList {
|
|||||||
private _searchBox = document.getElementById("accounts-search") as HTMLInputElement;
|
private _searchBox = document.getElementById("accounts-search") as HTMLInputElement;
|
||||||
private _search: Search;
|
private _search: Search;
|
||||||
|
|
||||||
|
private _applyHomesreen = document.getElementById("modify-user-homescreen") as HTMLInputElement;
|
||||||
|
private _applyOmbi = document.getElementById("modify-user-ombi") as HTMLInputElement;
|
||||||
|
private _applyJellyseerr = document.getElementById("modify-user-jellyseerr") as HTMLInputElement;
|
||||||
|
|
||||||
private _selectAll = document.getElementById("accounts-select-all") as HTMLInputElement;
|
private _selectAll = document.getElementById("accounts-select-all") as HTMLInputElement;
|
||||||
private _users: { [id: string]: user };
|
private _users: { [id: string]: user };
|
||||||
private _ordering: string[] = [];
|
private _ordering: string[] = [];
|
||||||
@ -1459,6 +1463,7 @@ export class accountsList {
|
|||||||
const modalHeader = document.getElementById("header-modify-user");
|
const modalHeader = document.getElementById("header-modify-user");
|
||||||
modalHeader.textContent = window.lang.quantity("modifySettingsFor", this._collectUsers().length)
|
modalHeader.textContent = window.lang.quantity("modifySettingsFor", this._collectUsers().length)
|
||||||
let list = this._collectUsers();
|
let list = this._collectUsers();
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
let innerHTML = "";
|
let innerHTML = "";
|
||||||
for (const profile of window.availableProfiles) {
|
for (const profile of window.availableProfiles) {
|
||||||
@ -1477,6 +1482,7 @@ export class accountsList {
|
|||||||
|
|
||||||
const form = document.getElementById("form-modify-user") as HTMLFormElement;
|
const form = document.getElementById("form-modify-user") as HTMLFormElement;
|
||||||
const button = form.querySelector("span.submit") as HTMLSpanElement;
|
const button = form.querySelector("span.submit") as HTMLSpanElement;
|
||||||
|
|
||||||
this._modifySettingsProfile.checked = true;
|
this._modifySettingsProfile.checked = true;
|
||||||
this._modifySettingsUser.checked = false;
|
this._modifySettingsUser.checked = false;
|
||||||
form.onsubmit = (event: Event) => {
|
form.onsubmit = (event: Event) => {
|
||||||
@ -1484,7 +1490,9 @@ export class accountsList {
|
|||||||
toggleLoader(button);
|
toggleLoader(button);
|
||||||
let send = {
|
let send = {
|
||||||
"apply_to": list,
|
"apply_to": list,
|
||||||
"homescreen": (document.getElementById("modify-user-homescreen") as HTMLInputElement).checked
|
"homescreen": this._applyHomesreen.checked,
|
||||||
|
"ombi": this._applyOmbi.checked,
|
||||||
|
"jellyseerr": this._applyJellyseerr.checked
|
||||||
};
|
};
|
||||||
if (this._modifySettingsProfile.checked && !this._modifySettingsUser.checked) {
|
if (this._modifySettingsProfile.checked && !this._modifySettingsUser.checked) {
|
||||||
send["from"] = "profile";
|
send["from"] = "profile";
|
||||||
@ -1821,6 +1829,16 @@ export class accountsList {
|
|||||||
};
|
};
|
||||||
this._modifySettings.onclick = this.modifyUsers;
|
this._modifySettings.onclick = this.modifyUsers;
|
||||||
this._modifySettings.classList.add("unfocused");
|
this._modifySettings.classList.add("unfocused");
|
||||||
|
|
||||||
|
if (window.ombiEnabled)
|
||||||
|
this._applyOmbi.parentElement.classList.remove("unfocused");
|
||||||
|
else
|
||||||
|
this._applyOmbi.parentElement.classList.add("unfocused");
|
||||||
|
if (window.jellyseerrEnabled)
|
||||||
|
this._applyJellyseerr.parentElement.classList.remove("unfocused");
|
||||||
|
else
|
||||||
|
this._applyJellyseerr.parentElement.classList.add("unfocused");
|
||||||
|
|
||||||
const checkSource = () => {
|
const checkSource = () => {
|
||||||
const profileSpan = this._modifySettingsProfile.nextElementSibling as HTMLSpanElement;
|
const profileSpan = this._modifySettingsProfile.nextElementSibling as HTMLSpanElement;
|
||||||
const userSpan = this._modifySettingsUser.nextElementSibling as HTMLSpanElement;
|
const userSpan = this._modifySettingsUser.nextElementSibling as HTMLSpanElement;
|
||||||
@ -1831,6 +1849,8 @@ export class accountsList {
|
|||||||
profileSpan.classList.remove("@low");
|
profileSpan.classList.remove("@low");
|
||||||
userSpan.classList.remove("@high");
|
userSpan.classList.remove("@high");
|
||||||
userSpan.classList.add("@low");
|
userSpan.classList.add("@low");
|
||||||
|
this._applyOmbi.parentElement.classList.remove("unfocused");
|
||||||
|
this._applyJellyseerr.parentElement.classList.remove("unfocused");
|
||||||
} else {
|
} else {
|
||||||
this._userSelect.parentElement.classList.remove("unfocused");
|
this._userSelect.parentElement.classList.remove("unfocused");
|
||||||
this._profileSelect.parentElement.classList.add("unfocused");
|
this._profileSelect.parentElement.classList.add("unfocused");
|
||||||
@ -1838,6 +1858,8 @@ export class accountsList {
|
|||||||
userSpan.classList.remove("@low");
|
userSpan.classList.remove("@low");
|
||||||
profileSpan.classList.remove("@high");
|
profileSpan.classList.remove("@high");
|
||||||
profileSpan.classList.add("@low");
|
profileSpan.classList.add("@low");
|
||||||
|
this._applyOmbi.parentElement.classList.add("unfocused");
|
||||||
|
this._applyJellyseerr.parentElement.classList.add("unfocused");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this._modifySettingsProfile.onchange = checkSource;
|
this._modifySettingsProfile.onchange = checkSource;
|
||||||
|
Loading…
Reference in New Issue
Block a user