mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 17:10:10 +00:00
jellyseerr: use in profiles, apply on user creation and modification
added in the same way as ombi profiles. Most code is copy-pasted and adjusted from ombi (especially on web), so maybe this can be merged in the future. Also, profile names are url-escaped like announcement template names were not too long ago. API client has "LogRequestBodies" option which just dumps the request body when enabled (useful for recreating reqs in the jellyseerr swagger UI). User.Name() helper returns a name from all three possible values in the struct.
This commit is contained in:
parent
7b9cdf385a
commit
a97bccc88f
100
api-jellyseerr.go
Normal file
100
api-jellyseerr.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Summary Get a list of Jellyseerr users.
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} ombiUsersDTO
|
||||||
|
// @Failure 500 {object} stringResponse
|
||||||
|
// @Router /jellyseerr/users [get]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags Jellyseerr
|
||||||
|
func (app *appContext) JellyseerrUsers(gc *gin.Context) {
|
||||||
|
app.debug.Println("Jellyseerr users requested")
|
||||||
|
users, err := app.js.GetUsers()
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to get users from Jellyseerr: %v", err)
|
||||||
|
respond(500, "Couldn't get users", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.debug.Printf("Jellyseerr users retrieved: %d", len(users))
|
||||||
|
userlist := make([]ombiUser, len(users))
|
||||||
|
i := 0
|
||||||
|
for _, u := range users {
|
||||||
|
userlist[i] = ombiUser{
|
||||||
|
Name: u.Name(),
|
||||||
|
ID: strconv.FormatInt(u.ID, 10),
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
gc.JSON(200, ombiUsersDTO{Users: userlist})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Store Jellyseerr user template in an existing profile.
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path string true "Jellyseerr ID of user to source from"
|
||||||
|
// @Param profile path string true "Name of profile to store in"
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 400 {object} boolResponse
|
||||||
|
// @Failure 500 {object} stringResponse
|
||||||
|
// @Router /profiles/jellyseerr/{profile}/{id} [post]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags Jellyseerr
|
||||||
|
func (app *appContext) SetJellyseerrProfile(gc *gin.Context) {
|
||||||
|
jellyseerrID, err := strconv.ParseInt(gc.Param("id"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
respondBool(400, false, gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
escapedProfileName := gc.Param("profile")
|
||||||
|
profileName, _ := url.QueryUnescape(escapedProfileName)
|
||||||
|
profile, ok := app.storage.GetProfileKey(profileName)
|
||||||
|
if !ok {
|
||||||
|
respondBool(400, false, gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u, err := app.js.UserByID(jellyseerrID)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Couldn't get user from Jellyseerr: %v", err)
|
||||||
|
respond(500, "Couldn't get user", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
profile.Jellyseerr.User = u.UserTemplate
|
||||||
|
n, err := app.js.GetNotificationPreferencesByID(jellyseerrID)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Couldn't get user's notification prefs from Jellyseerr: %v", err)
|
||||||
|
respond(500, "Couldn't get user notification prefs", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
profile.Jellyseerr.Notifications = n.NotificationsTemplate
|
||||||
|
profile.Jellyseerr.Enabled = true
|
||||||
|
app.storage.SetProfileKey(profileName, profile)
|
||||||
|
respondBool(204, true, gc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Remove jellyseerr user template from a profile.
|
||||||
|
// @Produce json
|
||||||
|
// @Param profile path string true "Name of profile to store in"
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 400 {object} boolResponse
|
||||||
|
// @Failure 500 {object} stringResponse
|
||||||
|
// @Router /profiles/jellyseerr/{profile} [delete]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags Jellyseerr
|
||||||
|
func (app *appContext) DeleteJellyseerrProfile(gc *gin.Context) {
|
||||||
|
escapedProfileName := gc.Param("profile")
|
||||||
|
profileName, _ := url.QueryUnescape(escapedProfileName)
|
||||||
|
profile, ok := app.storage.GetProfileKey(profileName)
|
||||||
|
if !ok {
|
||||||
|
respondBool(400, false, gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
profile.Jellyseerr.Enabled = false
|
||||||
|
app.storage.SetProfileKey(profileName, profile)
|
||||||
|
respondBool(204, true, gc)
|
||||||
|
}
|
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/hrfee/mediabrowser"
|
"github.com/hrfee/mediabrowser"
|
||||||
@ -95,7 +96,8 @@ func (app *appContext) OmbiUsers(gc *gin.Context) {
|
|||||||
func (app *appContext) SetOmbiProfile(gc *gin.Context) {
|
func (app *appContext) SetOmbiProfile(gc *gin.Context) {
|
||||||
var req ombiUser
|
var req ombiUser
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
profileName := gc.Param("profile")
|
escapedProfileName := gc.Param("profile")
|
||||||
|
profileName, _ := url.QueryUnescape(escapedProfileName)
|
||||||
profile, ok := app.storage.GetProfileKey(profileName)
|
profile, ok := app.storage.GetProfileKey(profileName)
|
||||||
if !ok {
|
if !ok {
|
||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
@ -122,7 +124,8 @@ func (app *appContext) SetOmbiProfile(gc *gin.Context) {
|
|||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
// @tags Ombi
|
// @tags Ombi
|
||||||
func (app *appContext) DeleteOmbiProfile(gc *gin.Context) {
|
func (app *appContext) DeleteOmbiProfile(gc *gin.Context) {
|
||||||
profileName := gc.Param("profile")
|
escapedProfileName := gc.Param("profile")
|
||||||
|
profileName, _ := url.QueryUnescape(escapedProfileName)
|
||||||
profile, ok := app.storage.GetProfileKey(profileName)
|
profile, ok := app.storage.GetProfileKey(profileName)
|
||||||
if !ok {
|
if !ok {
|
||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
|
@ -27,6 +27,7 @@ func (app *appContext) GetProfiles(gc *gin.Context) {
|
|||||||
LibraryAccess: p.LibraryAccess,
|
LibraryAccess: p.LibraryAccess,
|
||||||
FromUser: p.FromUser,
|
FromUser: p.FromUser,
|
||||||
Ombi: p.Ombi != nil,
|
Ombi: p.Ombi != nil,
|
||||||
|
Jellyseerr: p.Jellyseerr.Enabled,
|
||||||
ReferralsEnabled: false,
|
ReferralsEnabled: false,
|
||||||
}
|
}
|
||||||
if referralsEnabled {
|
if referralsEnabled {
|
||||||
|
102
api-users.go
102
api-users.go
@ -4,11 +4,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"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/jfa-go/jellyseerr"
|
||||||
"github.com/hrfee/mediabrowser"
|
"github.com/hrfee/mediabrowser"
|
||||||
"github.com/lithammer/shortuuid/v3"
|
"github.com/lithammer/shortuuid/v3"
|
||||||
"github.com/timshannon/badgerhold/v4"
|
"github.com/timshannon/badgerhold/v4"
|
||||||
@ -94,6 +96,29 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
|
|||||||
app.info.Println("Created Ombi user")
|
app.info.Println("Created Ombi user")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if app.config.Section("jellyseerr").Key("enabled").MustBool(false) {
|
||||||
|
// Gets existing user (not possible) or imports the given user.
|
||||||
|
_, err := app.js.MustGetUser(id)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to create Jellyseerr user: %v", err)
|
||||||
|
} else {
|
||||||
|
app.info.Println("Created Jellyseerr user")
|
||||||
|
}
|
||||||
|
err = app.js.ApplyTemplateToUser(id, profile.Jellyseerr.User)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to apply Jellyseerr user template: %v\n", err)
|
||||||
|
}
|
||||||
|
err = app.js.ApplyNotificationsTemplateToUser(id, profile.Jellyseerr.Notifications)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to apply Jellyseerr notifications template: %v\n", err)
|
||||||
|
}
|
||||||
|
if emailEnabled {
|
||||||
|
err = app.js.ModifyUser(id, map[jellyseerr.UserField]any{jellyseerr.FieldEmail: req.Email})
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to set Jellyseerr email address: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "" {
|
if emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "" {
|
||||||
app.debug.Printf("%s: Sending welcome email to %s", req.Username, req.Email)
|
app.debug.Printf("%s: Sending welcome email to %s", req.Username, req.Email)
|
||||||
msg, err := app.email.constructWelcome(req.Username, time.Time{}, app, false)
|
msg, err := app.email.constructWelcome(req.Username, time.Time{}, app, false)
|
||||||
@ -338,6 +363,10 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool, gc *gin.Context)
|
|||||||
Addr: req.Email,
|
Addr: req.Email,
|
||||||
Contact: (req.Email != ""),
|
Contact: (req.Email != ""),
|
||||||
}
|
}
|
||||||
|
// Only allow disabling of email contact if some other method is available.
|
||||||
|
if req.DiscordContact || req.TelegramContact || req.MatrixContact {
|
||||||
|
emailStore.Contact = req.EmailContact
|
||||||
|
}
|
||||||
|
|
||||||
if invite.UserLabel != "" {
|
if invite.UserLabel != "" {
|
||||||
emailStore.Label = invite.UserLabel
|
emailStore.Label = invite.UserLabel
|
||||||
@ -468,6 +497,51 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool, gc *gin.Context)
|
|||||||
app.debug.Printf("Skipping Ombi: Profile \"%s\" was empty", invite.Profile)
|
app.debug.Printf("Skipping Ombi: Profile \"%s\" was empty", invite.Profile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if invite.Profile != "" && app.config.Section("jellyseerr").Key("enabled").MustBool(false) {
|
||||||
|
if profile.Jellyseerr.Enabled {
|
||||||
|
// Gets existing user (not possible) or imports the given user.
|
||||||
|
_, err := app.js.MustGetUser(id)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to create Jellyseerr user: %v", err)
|
||||||
|
} else {
|
||||||
|
app.info.Println("Created Jellyseerr user")
|
||||||
|
}
|
||||||
|
err = app.js.ApplyTemplateToUser(id, profile.Jellyseerr.User)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to apply Jellyseerr user template: %v\n", err)
|
||||||
|
}
|
||||||
|
err = app.js.ApplyNotificationsTemplateToUser(id, profile.Jellyseerr.Notifications)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to apply Jellyseerr notifications template: %v\n", err)
|
||||||
|
}
|
||||||
|
contactMethods := map[jellyseerr.NotificationsField]any{}
|
||||||
|
if emailEnabled {
|
||||||
|
err = app.js.ModifyUser(id, map[jellyseerr.UserField]any{jellyseerr.FieldEmail: req.Email})
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to set Jellyseerr email address: %v\n", err)
|
||||||
|
} else {
|
||||||
|
contactMethods[jellyseerr.FieldEmailEnabled] = req.EmailContact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if discordVerified {
|
||||||
|
contactMethods[jellyseerr.FieldDiscord] = discordUser.ID
|
||||||
|
contactMethods[jellyseerr.FieldDiscordEnabled] = req.DiscordContact
|
||||||
|
}
|
||||||
|
if telegramVerified {
|
||||||
|
u, _ := app.storage.GetTelegramKey(user.ID)
|
||||||
|
contactMethods[jellyseerr.FieldTelegram] = strconv.FormatInt(u.ChatID, 10)
|
||||||
|
contactMethods[jellyseerr.FieldTelegramEnabled] = req.TelegramContact
|
||||||
|
}
|
||||||
|
if emailEnabled || discordVerified || telegramVerified {
|
||||||
|
err := app.js.ModifyNotifications(id, contactMethods)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to sync contact methods with Jellyseerr: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
app.debug.Printf("Skipping Jellyseerr: Profile \"%s\" was empty", invite.Profile)
|
||||||
|
}
|
||||||
|
}
|
||||||
if matrixVerified {
|
if matrixVerified {
|
||||||
matrixUser.Contact = req.MatrixContact
|
matrixUser.Contact = req.MatrixContact
|
||||||
delete(app.matrix.tokens, req.MatrixPIN)
|
delete(app.matrix.tokens, req.MatrixPIN)
|
||||||
@ -1265,6 +1339,8 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
var configuration mediabrowser.Configuration
|
var configuration mediabrowser.Configuration
|
||||||
var displayprefs map[string]interface{}
|
var displayprefs map[string]interface{}
|
||||||
var ombi map[string]interface{}
|
var ombi map[string]interface{}
|
||||||
|
var jellyseerr JellyseerrTemplate
|
||||||
|
jellyseerr.Enabled = false
|
||||||
if req.From == "profile" {
|
if req.From == "profile" {
|
||||||
// Check profile exists & isn't empty
|
// Check profile exists & isn't empty
|
||||||
profile, ok := app.storage.GetProfileKey(req.Profile)
|
profile, ok := app.storage.GetProfileKey(req.Profile)
|
||||||
@ -1288,6 +1364,11 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
ombi = profile.Ombi
|
ombi = profile.Ombi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if app.config.Section("jellyseerr").Key("enabled").MustBool(false) {
|
||||||
|
if profile.Jellyseerr.Enabled {
|
||||||
|
jellyseerr = profile.Jellyseerr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if req.From == "user" {
|
} else if req.From == "user" {
|
||||||
applyingFrom = "user"
|
applyingFrom = "user"
|
||||||
@ -1315,6 +1396,7 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
"policy": map[string]string{},
|
"policy": map[string]string{},
|
||||||
"homescreen": map[string]string{},
|
"homescreen": map[string]string{},
|
||||||
"ombi": map[string]string{},
|
"ombi": map[string]string{},
|
||||||
|
"jellyseerr": map[string]string{},
|
||||||
}
|
}
|
||||||
/* Jellyfin doesn't seem to like too many of these requests sent in succession
|
/* Jellyfin doesn't seem to like too many of these requests sent in succession
|
||||||
and can crash and mess up its database. Issue #160 says this occurs when more
|
and can crash and mess up its database. Issue #160 says this occurs when more
|
||||||
@ -1367,6 +1449,26 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
errors["ombi"][id] = errorString
|
errors["ombi"][id] = errorString
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if jellyseerr.Enabled {
|
||||||
|
errorString := ""
|
||||||
|
// newUser := ombi
|
||||||
|
// newUser["id"] = user["id"]
|
||||||
|
// newUser["userName"] = user["userName"]
|
||||||
|
// newUser["alias"] = user["alias"]
|
||||||
|
// newUser["emailAddress"] = user["emailAddress"]
|
||||||
|
err := app.js.ApplyTemplateToUser(id, jellyseerr.User)
|
||||||
|
if err != nil {
|
||||||
|
errorString += fmt.Sprintf("ApplyUser: %v ", err)
|
||||||
|
}
|
||||||
|
err = app.js.ApplyNotificationsTemplateToUser(id, jellyseerr.Notifications)
|
||||||
|
if err != nil {
|
||||||
|
errorString += fmt.Sprintf("ApplyNotifications: %v ", err)
|
||||||
|
}
|
||||||
|
if errorString != "" {
|
||||||
|
errors["jellyseerr"][id] = errorString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if shouldDelay {
|
if shouldDelay {
|
||||||
time.Sleep(250 * time.Millisecond)
|
time.Sleep(250 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
@ -1580,6 +1580,41 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jellyseerr": {
|
||||||
|
"order": [],
|
||||||
|
"meta": {
|
||||||
|
"name": "Jellyseerr Integration",
|
||||||
|
"description": "Connect to Jellyseerr to automatically trigger the import of users on account creation, and to automatically link contact methods (email, discord and telegram). A template must be added to a User Profile for accounts to be created."
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"enabled": {
|
||||||
|
"name": "Enabled",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "bool",
|
||||||
|
"value": false,
|
||||||
|
"description": "Enable the Jellyseerr integration."
|
||||||
|
},
|
||||||
|
"server": {
|
||||||
|
"name": "URL",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "text",
|
||||||
|
"value": "localhost:5000",
|
||||||
|
"depends_true": "enabled",
|
||||||
|
"description": "Jellyseerr server URL."
|
||||||
|
},
|
||||||
|
"api_key": {
|
||||||
|
"name": "API Key",
|
||||||
|
"required": false,
|
||||||
|
"requires_restart": true,
|
||||||
|
"type": "text",
|
||||||
|
"value": "",
|
||||||
|
"depends_true": "enabled",
|
||||||
|
"description": "API Key. Get this from the first tab in Jellyseerr's settings."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"backups": {
|
"backups": {
|
||||||
"order": [],
|
"order": [],
|
||||||
"meta": {
|
"meta": {
|
||||||
|
5
go.mod
5
go.mod
@ -16,6 +16,8 @@ replace github.com/hrfee/jfa-go/api => ./api
|
|||||||
|
|
||||||
replace github.com/hrfee/jfa-go/easyproxy => ./easyproxy
|
replace github.com/hrfee/jfa-go/easyproxy => ./easyproxy
|
||||||
|
|
||||||
|
replace github.com/hrfee/jfa-go/jellyseerr => ./jellyseerr
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bwmarrin/discordgo v0.27.1
|
github.com/bwmarrin/discordgo v0.27.1
|
||||||
github.com/dgraph-io/badger/v3 v3.2103.5
|
github.com/dgraph-io/badger/v3 v3.2103.5
|
||||||
@ -29,7 +31,7 @@ require (
|
|||||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a
|
github.com/gomarkdown/markdown v0.0.0-20230322041520-c84983bdbf2a
|
||||||
github.com/hrfee/jfa-go/common v0.0.0-20230626224816-f72960635dc3
|
github.com/hrfee/jfa-go/common v0.0.0-20240728190513-dabef831d769
|
||||||
github.com/hrfee/jfa-go/docs v0.0.0-20230626224816-f72960635dc3
|
github.com/hrfee/jfa-go/docs v0.0.0-20230626224816-f72960635dc3
|
||||||
github.com/hrfee/jfa-go/easyproxy v0.0.0-00010101000000-000000000000
|
github.com/hrfee/jfa-go/easyproxy v0.0.0-00010101000000-000000000000
|
||||||
github.com/hrfee/jfa-go/linecache v0.0.0-20230626224816-f72960635dc3
|
github.com/hrfee/jfa-go/linecache v0.0.0-20230626224816-f72960635dc3
|
||||||
@ -88,6 +90,7 @@ require (
|
|||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/gorilla/mux v1.8.0 // indirect
|
github.com/gorilla/mux v1.8.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
|
github.com/hrfee/jfa-go/jellyseerr v0.0.0-00010101000000-000000000000 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.16.6 // indirect
|
github.com/klauspost/compress v1.16.6 // indirect
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
window.discordEnabled = {{ .discordEnabled }};
|
window.discordEnabled = {{ .discordEnabled }};
|
||||||
window.matrixEnabled = {{ .matrixEnabled }};
|
window.matrixEnabled = {{ .matrixEnabled }};
|
||||||
window.ombiEnabled = {{ .ombiEnabled }};
|
window.ombiEnabled = {{ .ombiEnabled }};
|
||||||
|
window.jellyseerrEnabled = {{ .jellyseerrEnabled }};
|
||||||
window.usernameEnabled = {{ .username }};
|
window.usernameEnabled = {{ .username }};
|
||||||
window.langFile = JSON.parse({{ .language }});
|
window.langFile = JSON.parse({{ .language }});
|
||||||
window.linkResetEnabled = {{ .linkResetEnabled }};
|
window.linkResetEnabled = {{ .linkResetEnabled }};
|
||||||
@ -396,6 +397,19 @@
|
|||||||
</label>
|
</label>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="modal-jellyseerr-profile" class="modal">
|
||||||
|
<form class="card relative mx-auto my-[10%] w-11/12 sm:w-4/5 lg:w-1/3" id="form-jellyseerr-defaults" href="">
|
||||||
|
<span class="heading">{{ .strings.jellyseerrProfile }} <span class="modal-close">×</span></span>
|
||||||
|
<p class="content my-4">{{ .strings.jellyseerrUserDefaultsDescription }}</p>
|
||||||
|
<div class="select ~neutral @low mb-4">
|
||||||
|
<select></select>
|
||||||
|
</div>
|
||||||
|
<label>
|
||||||
|
<input type="submit" class="unfocused">
|
||||||
|
<span class="button ~urge @low full-width center supra submit">{{ .strings.submit }}</span>
|
||||||
|
</label>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
<div id="modal-user-profiles" class="modal">
|
<div id="modal-user-profiles" class="modal">
|
||||||
<div class="relative mx-auto my-[10%] w-11/12 sm:w-4/5 lg:w-2/3 content card">
|
<div class="relative mx-auto my-[10%] w-11/12 sm:w-4/5 lg:w-2/3 content card">
|
||||||
<span class="heading">{{ .strings.userProfiles }} <span class="modal-close">×</span></span>
|
<span class="heading">{{ .strings.userProfiles }} <span class="modal-close">×</span></span>
|
||||||
@ -409,6 +423,9 @@
|
|||||||
{{ if .ombiEnabled }}
|
{{ if .ombiEnabled }}
|
||||||
<th>Ombi</th>
|
<th>Ombi</th>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ if .jellyseerrEnabled }}
|
||||||
|
<th>Jellyseerr</th>
|
||||||
|
{{ end }}
|
||||||
{{ if .referralsEnabled }}
|
{{ if .referralsEnabled }}
|
||||||
<th>{{ .strings.referrals }}</th>
|
<th>{{ .strings.referrals }}</th>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -28,6 +28,7 @@ type Jellyseerr struct {
|
|||||||
cacheExpiry time.Time
|
cacheExpiry time.Time
|
||||||
cacheLength time.Duration
|
cacheLength time.Duration
|
||||||
timeoutHandler common.TimeoutHandler
|
timeoutHandler common.TimeoutHandler
|
||||||
|
LogRequestBodies bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewJellyseerr returns an Ombi object.
|
// NewJellyseerr returns an Ombi object.
|
||||||
@ -48,6 +49,7 @@ func NewJellyseerr(server, key string, timeoutHandler common.TimeoutHandler) *Je
|
|||||||
cacheExpiry: time.Now(),
|
cacheExpiry: time.Now(),
|
||||||
timeoutHandler: timeoutHandler,
|
timeoutHandler: timeoutHandler,
|
||||||
userCache: map[string]User{},
|
userCache: map[string]User{},
|
||||||
|
LogRequestBodies: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +61,9 @@ func (js *Jellyseerr) getJSON(url string, params map[string]string, queryParams
|
|||||||
var req *http.Request
|
var req *http.Request
|
||||||
if params != nil {
|
if params != nil {
|
||||||
jsonParams, _ := json.Marshal(params)
|
jsonParams, _ := json.Marshal(params)
|
||||||
|
if js.LogRequestBodies {
|
||||||
|
fmt.Printf("Jellyseerr API Client: Sending Data \"%s\"\n", string(jsonParams))
|
||||||
|
}
|
||||||
req, _ = http.NewRequest("GET", url+"?"+queryParams.Encode(), bytes.NewBuffer(jsonParams))
|
req, _ = http.NewRequest("GET", url+"?"+queryParams.Encode(), bytes.NewBuffer(jsonParams))
|
||||||
} else {
|
} else {
|
||||||
req, _ = http.NewRequest("GET", url+"?"+queryParams.Encode(), nil)
|
req, _ = http.NewRequest("GET", url+"?"+queryParams.Encode(), nil)
|
||||||
@ -94,6 +99,9 @@ func (js *Jellyseerr) getJSON(url string, params map[string]string, queryParams
|
|||||||
func (js *Jellyseerr) send(mode string, url string, data any, response bool, headers map[string]string) (string, int, error) {
|
func (js *Jellyseerr) send(mode string, url string, data any, response bool, headers map[string]string) (string, int, error) {
|
||||||
responseText := ""
|
responseText := ""
|
||||||
params, _ := json.Marshal(data)
|
params, _ := json.Marshal(data)
|
||||||
|
if js.LogRequestBodies {
|
||||||
|
fmt.Printf("Jellyseerr API Client: Sending Data \"%s\"\n", string(params))
|
||||||
|
}
|
||||||
req, _ := http.NewRequest(mode, url, bytes.NewBuffer(params))
|
req, _ := http.NewRequest(mode, url, bytes.NewBuffer(params))
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
for name, value := range js.header {
|
for name, value := range js.header {
|
||||||
@ -291,7 +299,7 @@ func (js *Jellyseerr) ApplyTemplateToUser(jfID string, tmpl UserTemplate) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (js *Jellyseerr) ModifyUser(jfID string, conf map[UserField]string) error {
|
func (js *Jellyseerr) ModifyUser(jfID string, conf map[UserField]any) error {
|
||||||
u, err := js.MustGetUser(jfID)
|
u, err := js.MustGetUser(jfID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -327,13 +335,16 @@ func (js *Jellyseerr) DeleteUser(jfID string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (js *Jellyseerr) GetNotificationPreferences(jfID string) (Notifications, error) {
|
func (js *Jellyseerr) GetNotificationPreferences(jfID string) (Notifications, error) {
|
||||||
var data Notifications
|
|
||||||
u, err := js.MustGetUser(jfID)
|
u, err := js.MustGetUser(jfID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data, err
|
return Notifications{}, err
|
||||||
}
|
}
|
||||||
|
return js.GetNotificationPreferencesByID(u.ID)
|
||||||
|
}
|
||||||
|
|
||||||
resp, status, err := js.getJSON(fmt.Sprintf(js.server+"/user/%d/settings/notifications", u.ID), nil, url.Values{})
|
func (js *Jellyseerr) GetNotificationPreferencesByID(jellyseerrID int64) (Notifications, error) {
|
||||||
|
var data Notifications
|
||||||
|
resp, status, err := js.getJSON(fmt.Sprintf(js.server+"/user/%d/settings/notifications", jellyseerrID), nil, url.Values{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
@ -360,7 +371,7 @@ func (js *Jellyseerr) ApplyNotificationsTemplateToUser(jfID string, tmpl Notific
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (js *Jellyseerr) ModifyNotifications(jfID string, conf map[NotificationsField]string) error {
|
func (js *Jellyseerr) ModifyNotifications(jfID string, conf map[NotificationsField]any) error {
|
||||||
u, err := js.MustGetUser(jfID)
|
u, err := js.MustGetUser(jfID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -375,3 +386,21 @@ func (js *Jellyseerr) ModifyNotifications(jfID string, conf map[NotificationsFie
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (js *Jellyseerr) GetUsers() (map[string]User, error) {
|
||||||
|
err := js.getUsers()
|
||||||
|
return js.userCache, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (js *Jellyseerr) UserByID(jellyseerrID int64) (User, error) {
|
||||||
|
resp, status, err := js.getJSON(js.server+fmt.Sprintf("/user/%d", jellyseerrID), nil, url.Values{})
|
||||||
|
var data User
|
||||||
|
if status != 200 {
|
||||||
|
return data, fmt.Errorf("failed (error %d)", status)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal([]byte(resp), &data)
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
@ -11,61 +11,74 @@ const (
|
|||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
UserTemplate // Note: You can set this with User.UserTemplate = value.
|
UserTemplate // Note: You can set this with User.UserTemplate = value.
|
||||||
Warnings []any `json:"warnings"`
|
UserType int64 `json:"userType,omitempty"`
|
||||||
ID int `json:"id"`
|
Warnings []any `json:"warnings,omitempty"`
|
||||||
Email string `json:"email"`
|
ID int64 `json:"id,omitempty"`
|
||||||
PlexUsername string `json:"plexUsername"`
|
Email string `json:"email,omitempty"`
|
||||||
JellyfinUsername string `json:"jellyfinUsername"`
|
PlexUsername string `json:"plexUsername,omitempty"`
|
||||||
Username string `json:"username"`
|
JellyfinUsername string `json:"jellyfinUsername,omitempty"`
|
||||||
RecoveryLinkExpirationDate any `json:"recoveryLinkExpirationDate"`
|
Username string `json:"username,omitempty"`
|
||||||
PlexID string `json:"plexId"`
|
RecoveryLinkExpirationDate any `json:"recoveryLinkExpirationDate,omitempty"`
|
||||||
JellyfinUserID string `json:"jellyfinUserId"`
|
PlexID string `json:"plexId,omitempty"`
|
||||||
JellyfinDeviceID string `json:"jellyfinDeviceId"`
|
JellyfinUserID string `json:"jellyfinUserId,omitempty"`
|
||||||
JellyfinAuthToken string `json:"jellyfinAuthToken"`
|
JellyfinDeviceID string `json:"jellyfinDeviceId,omitempty"`
|
||||||
PlexToken string `json:"plexToken"`
|
JellyfinAuthToken string `json:"jellyfinAuthToken,omitempty"`
|
||||||
Avatar string `json:"avatar"`
|
PlexToken string `json:"plexToken,omitempty"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
Avatar string `json:"avatar,omitempty"`
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
CreatedAt time.Time `json:"createdAt,omitempty"`
|
||||||
RequestCount int `json:"requestCount"`
|
UpdatedAt time.Time `json:"updatedAt,omitempty"`
|
||||||
DisplayName string `json:"displayName"`
|
RequestCount int64 `json:"requestCount,omitempty"`
|
||||||
|
DisplayName string `json:"displayName,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u User) Name() string {
|
||||||
|
var n string
|
||||||
|
if u.Username != "" {
|
||||||
|
n = u.Username
|
||||||
|
} else if u.JellyfinUsername != "" {
|
||||||
|
n = u.JellyfinUsername
|
||||||
|
}
|
||||||
|
if u.DisplayName != "" {
|
||||||
|
n += " (" + u.DisplayName + ")"
|
||||||
|
}
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserTemplate struct {
|
type UserTemplate struct {
|
||||||
Permissions Permissions `json:"permissions"`
|
Permissions Permissions `json:"permissions,omitempty"`
|
||||||
UserType int `json:"userType"`
|
MovieQuotaLimit any `json:"movieQuotaLimit,omitempty"`
|
||||||
MovieQuotaLimit any `json:"movieQuotaLimit"`
|
MovieQuotaDays any `json:"movieQuotaDays,omitempty"`
|
||||||
MovieQuotaDays any `json:"movieQuotaDays"`
|
TvQuotaLimit any `json:"tvQuotaLimit,omitempty"`
|
||||||
TvQuotaLimit any `json:"tvQuotaLimit"`
|
TvQuotaDays any `json:"tvQuotaDays,omitempty"`
|
||||||
TvQuotaDays any `json:"tvQuotaDays"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PageInfo struct {
|
type PageInfo struct {
|
||||||
Pages int `json:"pages"`
|
Pages int `json:"pages,omitempty"`
|
||||||
PageSize int `json:"pageSize"`
|
PageSize int `json:"pageSize,omitempty"`
|
||||||
Results int `json:"results"`
|
Results int `json:"results,omitempty"`
|
||||||
Page int `json:"page"`
|
Page int `json:"page,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetUsersDTO struct {
|
type GetUsersDTO struct {
|
||||||
Page PageInfo `json:"pageInfo"`
|
Page PageInfo `json:"pageInfo,omitempty"`
|
||||||
Results []User `json:"results"`
|
Results []User `json:"results,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type permissionsDTO struct {
|
type permissionsDTO struct {
|
||||||
Permissions Permissions `json:"permissions"`
|
Permissions Permissions `json:"permissions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Permissions int
|
type Permissions int
|
||||||
|
|
||||||
type NotificationTypes struct {
|
type NotificationTypes struct {
|
||||||
Discord int `json:"discord"`
|
Discord int64 `json:"discord,omitempty"`
|
||||||
Email int `json:"email"`
|
Email int64 `json:"email,omitempty"`
|
||||||
Pushbullet int `json:"pushbullet"`
|
Pushbullet int64 `json:"pushbullet,omitempty"`
|
||||||
Pushover int `json:"pushover"`
|
Pushover int64 `json:"pushover,omitempty"`
|
||||||
Slack int `json:"slack"`
|
Slack int64 `json:"slack,omitempty"`
|
||||||
Telegram int `json:"telegram"`
|
Telegram int64 `json:"telegram,omitempty"`
|
||||||
Webhook int `json:"webhook"`
|
Webhook int64 `json:"webhook,omitempty"`
|
||||||
Webpush int `json:"webpush"`
|
Webpush int64 `json:"webpush,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotificationsField string
|
type NotificationsField string
|
||||||
@ -80,21 +93,21 @@ const (
|
|||||||
|
|
||||||
type Notifications struct {
|
type Notifications struct {
|
||||||
NotificationsTemplate
|
NotificationsTemplate
|
||||||
PgpKey any `json:"pgpKey"`
|
PgpKey any `json:"pgpKey,omitempty"`
|
||||||
DiscordID string `json:"discordId"`
|
DiscordID string `json:"discordId,omitempty"`
|
||||||
PushbulletAccessToken any `json:"pushbulletAccessToken"`
|
PushbulletAccessToken any `json:"pushbulletAccessToken,omitempty"`
|
||||||
PushoverApplicationToken any `json:"pushoverApplicationToken"`
|
PushoverApplicationToken any `json:"pushoverApplicationToken,omitempty"`
|
||||||
PushoverUserKey any `json:"pushoverUserKey"`
|
PushoverUserKey any `json:"pushoverUserKey,omitempty"`
|
||||||
TelegramChatID string `json:"telegramChatId"`
|
TelegramChatID string `json:"telegramChatId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotificationsTemplate struct {
|
type NotificationsTemplate struct {
|
||||||
EmailEnabled bool `json:"emailEnabled"`
|
EmailEnabled bool `json:"emailEnabled,omitempty"`
|
||||||
DiscordEnabled bool `json:"discordEnabled"`
|
DiscordEnabled bool `json:"discordEnabled,omitempty"`
|
||||||
DiscordEnabledTypes int `json:"discordEnabledTypes"`
|
DiscordEnabledTypes int64 `json:"discordEnabledTypes,omitempty"`
|
||||||
PushoverSound any `json:"pushoverSound"`
|
PushoverSound any `json:"pushoverSound,omitempty"`
|
||||||
TelegramEnabled bool `json:"telegramEnabled"`
|
TelegramEnabled bool `json:"telegramEnabled,omitempty"`
|
||||||
TelegramSendSilently any `json:"telegramSendSilently"`
|
TelegramSendSilently any `json:"telegramSendSilently,omitempty"`
|
||||||
WebPushEnabled bool `json:"webPushEnabled"`
|
WebPushEnabled bool `json:"webPushEnabled,omitempty"`
|
||||||
NotifTypes NotificationTypes `json:"notificationTypes"`
|
NotifTypes NotificationTypes `json:"notificationTypes,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,8 @@
|
|||||||
"settingsMaybeUnderAdvanced": "Tip: You might find what you're looking for by enabling Advanced Settings.",
|
"settingsMaybeUnderAdvanced": "Tip: You might find what you're looking for by enabling Advanced Settings.",
|
||||||
"ombiProfile": "Ombi user profile",
|
"ombiProfile": "Ombi user profile",
|
||||||
"ombiUserDefaultsDescription": "Create an Ombi user and configure it, then select it below. It's settings/permissions will be stored and applied to new Ombi users created by jfa-go when this profile is selected.",
|
"ombiUserDefaultsDescription": "Create an Ombi user and configure it, then select it below. It's settings/permissions will be stored and applied to new Ombi users created by jfa-go when this profile is selected.",
|
||||||
|
"jellyseerrProfile": "Jellyseerr user profile",
|
||||||
|
"jellyseerrUserDefaultsDescription": "Create a Jellyseerr user and configure it, then select it below. It's settings/permissions will be stored and applied to new Jellyseerr users created by jfa-go when this profile is selected.",
|
||||||
"userProfiles": "User Profiles",
|
"userProfiles": "User Profiles",
|
||||||
"userProfilesDescription": "Profiles are applied to users when they create an account. A profile includes library access rights and homescreen layout.",
|
"userProfilesDescription": "Profiles are applied to users when they create an account. A profile includes library access rights and homescreen layout.",
|
||||||
"userProfilesIsDefault": "Default",
|
"userProfilesIsDefault": "Default",
|
||||||
@ -208,6 +210,7 @@
|
|||||||
"sentAnnouncement": "Announcement sent.",
|
"sentAnnouncement": "Announcement sent.",
|
||||||
"savedAnnouncement": "Announcement saved.",
|
"savedAnnouncement": "Announcement saved.",
|
||||||
"setOmbiProfile": "Stored ombi profile.",
|
"setOmbiProfile": "Stored ombi profile.",
|
||||||
|
"savedProfile": "Stored profile changes.",
|
||||||
"updateApplied": "Update applied, please restart.",
|
"updateApplied": "Update applied, please restart.",
|
||||||
"updateAppliedRefresh": "Update applied, please refresh.",
|
"updateAppliedRefresh": "Update applied, please refresh.",
|
||||||
"telegramVerified": "Telegram account verified.",
|
"telegramVerified": "Telegram account verified.",
|
||||||
@ -224,6 +227,7 @@
|
|||||||
"errorDeleteProfile": "Failed to delete profile {n}",
|
"errorDeleteProfile": "Failed to delete profile {n}",
|
||||||
"errorLoadProfiles": "Failed to load profiles.",
|
"errorLoadProfiles": "Failed to load profiles.",
|
||||||
"errorCreateProfile": "Failed to create profile {n}",
|
"errorCreateProfile": "Failed to create profile {n}",
|
||||||
|
"errorSavedProfile": "Failed to save profile {n}",
|
||||||
"errorSetDefaultProfile": "Failed to set default profile.",
|
"errorSetDefaultProfile": "Failed to set default profile.",
|
||||||
"errorLoadUsers": "Failed to load users.",
|
"errorLoadUsers": "Failed to load users.",
|
||||||
"errorLoadSettings": "Failed to load settings.",
|
"errorLoadSettings": "Failed to load settings.",
|
||||||
|
13
main.go
13
main.go
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/hrfee/jfa-go/common"
|
"github.com/hrfee/jfa-go/common"
|
||||||
_ "github.com/hrfee/jfa-go/docs"
|
_ "github.com/hrfee/jfa-go/docs"
|
||||||
"github.com/hrfee/jfa-go/easyproxy"
|
"github.com/hrfee/jfa-go/easyproxy"
|
||||||
|
"github.com/hrfee/jfa-go/jellyseerr"
|
||||||
"github.com/hrfee/jfa-go/logger"
|
"github.com/hrfee/jfa-go/logger"
|
||||||
"github.com/hrfee/jfa-go/ombi"
|
"github.com/hrfee/jfa-go/ombi"
|
||||||
"github.com/hrfee/mediabrowser"
|
"github.com/hrfee/mediabrowser"
|
||||||
@ -101,6 +102,7 @@ type appContext struct {
|
|||||||
jf *mediabrowser.MediaBrowser
|
jf *mediabrowser.MediaBrowser
|
||||||
authJf *mediabrowser.MediaBrowser
|
authJf *mediabrowser.MediaBrowser
|
||||||
ombi *ombi.Ombi
|
ombi *ombi.Ombi
|
||||||
|
js *jellyseerr.Jellyseerr
|
||||||
datePattern string
|
datePattern string
|
||||||
timePattern string
|
timePattern string
|
||||||
storage Storage
|
storage Storage
|
||||||
@ -359,6 +361,17 @@ func start(asDaemon, firstCall bool) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if app.config.Section("jellyseerr").Key("enabled").MustBool(false) {
|
||||||
|
app.debug.Printf("Connecting to Jellyseerr")
|
||||||
|
jellyseerrServer := app.config.Section("jellyseerr").Key("server").String()
|
||||||
|
app.js = jellyseerr.NewJellyseerr(
|
||||||
|
jellyseerrServer,
|
||||||
|
app.config.Section("jellyseerr").Key("api_key").String(),
|
||||||
|
common.NewTimeoutHandler("Jellyseerr", jellyseerrServer, true),
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
app.storage.db_path = filepath.Join(app.dataPath, "db")
|
app.storage.db_path = filepath.Join(app.dataPath, "db")
|
||||||
app.loadPendingBackup()
|
app.loadPendingBackup()
|
||||||
app.ConnectDB()
|
app.ConnectDB()
|
||||||
|
@ -16,6 +16,7 @@ type newUserDTO struct {
|
|||||||
Username string `json:"username" example:"jeff" binding:"required"` // User's username
|
Username string `json:"username" example:"jeff" binding:"required"` // User's username
|
||||||
Password string `json:"password" example:"guest" binding:"required"` // User's password
|
Password string `json:"password" example:"guest" binding:"required"` // User's password
|
||||||
Email string `json:"email" example:"jeff@jellyf.in"` // User's email address
|
Email string `json:"email" example:"jeff@jellyf.in"` // User's email address
|
||||||
|
EmailContact bool `json:"email_contact"` // Whether or not to use email for notifications/pwrs
|
||||||
Code string `json:"code" example:"abc0933jncjkcjj"` // Invite code (required on /newUser)
|
Code string `json:"code" example:"abc0933jncjkcjj"` // Invite code (required on /newUser)
|
||||||
TelegramPIN string `json:"telegram_pin" example:"A1-B2-3C"` // Telegram verification PIN (if used)
|
TelegramPIN string `json:"telegram_pin" example:"A1-B2-3C"` // Telegram verification PIN (if used)
|
||||||
TelegramContact bool `json:"telegram_contact"` // Whether or not to use telegram for notifications/pwrs
|
TelegramContact bool `json:"telegram_contact"` // Whether or not to use telegram for notifications/pwrs
|
||||||
@ -76,6 +77,7 @@ type profileDTO struct {
|
|||||||
LibraryAccess string `json:"libraries" example:"all"` // Number of libraries profile has access to
|
LibraryAccess string `json:"libraries" example:"all"` // Number of libraries profile has access to
|
||||||
FromUser string `json:"fromUser" example:"jeff"` // The user the profile is based on
|
FromUser string `json:"fromUser" example:"jeff"` // The user the profile is based on
|
||||||
Ombi bool `json:"ombi"` // Whether or not Ombi settings are stored in this profile.
|
Ombi bool `json:"ombi"` // Whether or not Ombi settings are stored in this profile.
|
||||||
|
Jellyseerr bool `json:"jellyseerr"` // Whether or not Jellyseerr settings are stored in this profile.
|
||||||
ReferralsEnabled bool `json:"referrals_enabled" example:"true"` // Whether or not the profile has referrals enabled, and has a template invite stored.
|
ReferralsEnabled bool `json:"referrals_enabled" example:"true"` // Whether or not the profile has referrals enabled, and has a template invite stored.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,6 +238,11 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
|||||||
api.GET(p+"/users/discord/:username", app.DiscordGetUsers)
|
api.GET(p+"/users/discord/:username", app.DiscordGetUsers)
|
||||||
api.POST(p+"/users/discord", app.DiscordConnect)
|
api.POST(p+"/users/discord", app.DiscordConnect)
|
||||||
}
|
}
|
||||||
|
if app.config.Section("jellyseerr").Key("enabled").MustBool(false) {
|
||||||
|
api.GET(p+"/jellyseerr/users", app.JellyseerrUsers)
|
||||||
|
api.POST(p+"/profiles/jellyseerr/:profile/:id", app.SetJellyseerrProfile)
|
||||||
|
api.DELETE(p+"/profiles/jellyseerr/:profile", app.DeleteJellyseerrProfile)
|
||||||
|
}
|
||||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
api.GET(p+"/ombi/users", app.OmbiUsers)
|
api.GET(p+"/ombi/users", app.OmbiUsers)
|
||||||
api.POST(p+"/profiles/ombi/:profile", app.SetOmbiProfile)
|
api.POST(p+"/profiles/ombi/:profile", app.SetOmbiProfile)
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/hrfee/jfa-go/jellyseerr"
|
||||||
"github.com/hrfee/jfa-go/logger"
|
"github.com/hrfee/jfa-go/logger"
|
||||||
"github.com/hrfee/mediabrowser"
|
"github.com/hrfee/mediabrowser"
|
||||||
"github.com/timshannon/badgerhold/v4"
|
"github.com/timshannon/badgerhold/v4"
|
||||||
@ -650,9 +651,16 @@ type Profile struct {
|
|||||||
Displayprefs map[string]interface{} `json:"displayprefs,omitempty"`
|
Displayprefs map[string]interface{} `json:"displayprefs,omitempty"`
|
||||||
Default bool `json:"default,omitempty"`
|
Default bool `json:"default,omitempty"`
|
||||||
Ombi map[string]interface{} `json:"ombi,omitempty"`
|
Ombi map[string]interface{} `json:"ombi,omitempty"`
|
||||||
|
Jellyseerr JellyseerrTemplate `json:"jellyseerr,omitempty"`
|
||||||
ReferralTemplateKey string
|
ReferralTemplateKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JellyseerrTemplate struct {
|
||||||
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
|
User jellyseerr.UserTemplate `json:"user,omitempty"`
|
||||||
|
Notifications jellyseerr.NotificationsTemplate `json:"notifications,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type Invite struct {
|
type Invite struct {
|
||||||
Code string `badgerhold:"key"`
|
Code string `badgerhold:"key"`
|
||||||
Created time.Time `json:"created"`
|
Created time.Time `json:"created"`
|
||||||
|
@ -50,6 +50,9 @@ window.availableProfiles = window.availableProfiles || [];
|
|||||||
window.modals.ombiProfile = new Modal(document.getElementById('modal-ombi-profile'));
|
window.modals.ombiProfile = new Modal(document.getElementById('modal-ombi-profile'));
|
||||||
document.getElementById('form-ombi-defaults').addEventListener('submit', window.modals.ombiProfile.close);
|
document.getElementById('form-ombi-defaults').addEventListener('submit', window.modals.ombiProfile.close);
|
||||||
|
|
||||||
|
window.modals.jellyseerrProfile = new Modal(document.getElementById('modal-jellyseerr-profile'));
|
||||||
|
document.getElementById('form-jellyseerr-defaults').addEventListener('submit', window.modals.jellyseerrProfile.close);
|
||||||
|
|
||||||
window.modals.profiles = new Modal(document.getElementById("modal-user-profiles"));
|
window.modals.profiles = new Modal(document.getElementById("modal-user-profiles"));
|
||||||
|
|
||||||
window.modals.addProfile = new Modal(document.getElementById("modal-add-profile"));
|
window.modals.addProfile = new Modal(document.getElementById("modal-add-profile"));
|
||||||
|
@ -224,6 +224,7 @@ if (window.emailRequired) {
|
|||||||
interface sendDTO {
|
interface sendDTO {
|
||||||
code: string;
|
code: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
email_contact?: boolean;
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
telegram_pin?: string;
|
telegram_pin?: string;
|
||||||
@ -252,8 +253,9 @@ const create = (event: SubmitEvent) => {
|
|||||||
code: window.code,
|
code: window.code,
|
||||||
username: usernameField.value,
|
username: usernameField.value,
|
||||||
email: emailField.value,
|
email: emailField.value,
|
||||||
|
email_contact: true,
|
||||||
password: passwordField.value
|
password: passwordField.value
|
||||||
};
|
}
|
||||||
if (telegramVerified) {
|
if (telegramVerified) {
|
||||||
send.telegram_pin = window.telegramPIN;
|
send.telegram_pin = window.telegramPIN;
|
||||||
const checkbox = document.getElementById("contact-via-telegram") as HTMLInputElement;
|
const checkbox = document.getElementById("contact-via-telegram") as HTMLInputElement;
|
||||||
@ -275,6 +277,10 @@ const create = (event: SubmitEvent) => {
|
|||||||
send.matrix_contact = true;
|
send.matrix_contact = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (matrixVerified || discordVerified || telegramVerified) {
|
||||||
|
const checkbox = document.getElementById("contact-via-email") as HTMLInputElement;
|
||||||
|
send.email_contact = checkbox.checked;
|
||||||
|
}
|
||||||
if (window.captcha) {
|
if (window.captcha) {
|
||||||
if (window.reCAPTCHA) {
|
if (window.reCAPTCHA) {
|
||||||
send.captcha_text = grecaptcha.getResponse();
|
send.captcha_text = grecaptcha.getResponse();
|
||||||
|
@ -5,6 +5,7 @@ interface Profile {
|
|||||||
libraries: string;
|
libraries: string;
|
||||||
fromUser: string;
|
fromUser: string;
|
||||||
ombi: boolean;
|
ombi: boolean;
|
||||||
|
jellyseerr: boolean;
|
||||||
referrals_enabled: boolean;
|
referrals_enabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,9 +15,11 @@ class profile implements Profile {
|
|||||||
private _adminChip: HTMLSpanElement;
|
private _adminChip: HTMLSpanElement;
|
||||||
private _libraries: HTMLTableDataCellElement;
|
private _libraries: HTMLTableDataCellElement;
|
||||||
private _ombiButton: HTMLSpanElement;
|
private _ombiButton: HTMLSpanElement;
|
||||||
|
private _ombi: boolean;
|
||||||
|
private _jellyseerrButton: HTMLSpanElement;
|
||||||
|
private _jellyseerr: boolean;
|
||||||
private _fromUser: HTMLTableDataCellElement;
|
private _fromUser: HTMLTableDataCellElement;
|
||||||
private _defaultRadio: HTMLInputElement;
|
private _defaultRadio: HTMLInputElement;
|
||||||
private _ombi: boolean;
|
|
||||||
private _referralsButton: HTMLSpanElement;
|
private _referralsButton: HTMLSpanElement;
|
||||||
private _referralsEnabled: boolean;
|
private _referralsEnabled: boolean;
|
||||||
|
|
||||||
@ -52,6 +55,21 @@ class profile implements Profile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get jellyseerr(): boolean { return this._jellyseerr; }
|
||||||
|
set jellyseerr(v: boolean) {
|
||||||
|
if (!window.jellyseerrEnabled) return;
|
||||||
|
this._jellyseerr = v;
|
||||||
|
if (v) {
|
||||||
|
this._jellyseerrButton.textContent = window.lang.strings("delete");
|
||||||
|
this._jellyseerrButton.classList.add("~critical");
|
||||||
|
this._jellyseerrButton.classList.remove("~neutral");
|
||||||
|
} else {
|
||||||
|
this._jellyseerrButton.textContent = window.lang.strings("add");
|
||||||
|
this._jellyseerrButton.classList.add("~neutral");
|
||||||
|
this._jellyseerrButton.classList.remove("~critical");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get fromUser(): string { return this._fromUser.textContent; }
|
get fromUser(): string { return this._fromUser.textContent; }
|
||||||
set fromUser(v: string) { this._fromUser.textContent = v; }
|
set fromUser(v: string) { this._fromUser.textContent = v; }
|
||||||
|
|
||||||
@ -82,6 +100,9 @@ class profile implements Profile {
|
|||||||
if (window.ombiEnabled) innerHTML += `
|
if (window.ombiEnabled) innerHTML += `
|
||||||
<td><span class="button @low profile-ombi"></span></td>
|
<td><span class="button @low profile-ombi"></span></td>
|
||||||
`;
|
`;
|
||||||
|
if (window.jellyseerrEnabled) innerHTML += `
|
||||||
|
<td><span class="button @low profile-jellyseerr"></span></td>
|
||||||
|
`;
|
||||||
if (window.referralsEnabled) innerHTML += `
|
if (window.referralsEnabled) innerHTML += `
|
||||||
<td><span class="button @low profile-referrals"></span></td>
|
<td><span class="button @low profile-referrals"></span></td>
|
||||||
`;
|
`;
|
||||||
@ -96,6 +117,8 @@ class profile implements Profile {
|
|||||||
this._libraries = this._row.querySelector("td.profile-libraries") as HTMLTableDataCellElement;
|
this._libraries = this._row.querySelector("td.profile-libraries") as HTMLTableDataCellElement;
|
||||||
if (window.ombiEnabled)
|
if (window.ombiEnabled)
|
||||||
this._ombiButton = this._row.querySelector("span.profile-ombi") as HTMLSpanElement;
|
this._ombiButton = this._row.querySelector("span.profile-ombi") as HTMLSpanElement;
|
||||||
|
if (window.jellyseerrEnabled)
|
||||||
|
this._jellyseerrButton = this._row.querySelector("span.profile-jellyseerr") as HTMLSpanElement;
|
||||||
if (window.referralsEnabled)
|
if (window.referralsEnabled)
|
||||||
this._referralsButton = this._row.querySelector("span.profile-referrals") as HTMLSpanElement;
|
this._referralsButton = this._row.querySelector("span.profile-referrals") as HTMLSpanElement;
|
||||||
this._fromUser = this._row.querySelector("td.profile-from") as HTMLTableDataCellElement;
|
this._fromUser = this._row.querySelector("td.profile-from") as HTMLTableDataCellElement;
|
||||||
@ -112,10 +135,12 @@ class profile implements Profile {
|
|||||||
this.fromUser = p.fromUser;
|
this.fromUser = p.fromUser;
|
||||||
this.libraries = p.libraries;
|
this.libraries = p.libraries;
|
||||||
this.ombi = p.ombi;
|
this.ombi = p.ombi;
|
||||||
|
this.jellyseerr = p.jellyseerr;
|
||||||
this.referrals_enabled = p.referrals_enabled;
|
this.referrals_enabled = p.referrals_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
setOmbiFunc = (ombiFunc: (ombi: boolean) => void) => { this._ombiButton.onclick = () => ombiFunc(this._ombi); }
|
setOmbiFunc = (ombiFunc: (ombi: boolean) => void) => { this._ombiButton.onclick = () => ombiFunc(this._ombi); }
|
||||||
|
setJellyseerrFunc = (jellyseerrFunc: (jellyseerr: boolean) => void) => { this._jellyseerrButton.onclick = () => jellyseerrFunc(this._jellyseerr); }
|
||||||
setReferralFunc = (referralFunc: (enabled: boolean) => void) => { this._referralsButton.onclick = () => referralFunc(this._referralsEnabled); }
|
setReferralFunc = (referralFunc: (enabled: boolean) => void) => { this._referralsButton.onclick = () => referralFunc(this._referralsEnabled); }
|
||||||
|
|
||||||
remove = () => { document.dispatchEvent(new CustomEvent("profiles-delete", { detail: this._name })); this._row.remove(); }
|
remove = () => { document.dispatchEvent(new CustomEvent("profiles-delete", { detail: this._name })); this._row.remove(); }
|
||||||
@ -144,6 +169,7 @@ export class ProfileEditor {
|
|||||||
private _profiles: { [name: string]: profile } = {};
|
private _profiles: { [name: string]: profile } = {};
|
||||||
private _default: string;
|
private _default: string;
|
||||||
private _ombiProfiles: ombiProfiles;
|
private _ombiProfiles: ombiProfiles;
|
||||||
|
private _jellyseerrProfiles: jellyseerrProfiles;
|
||||||
|
|
||||||
private _createForm = document.getElementById("form-add-profile") as HTMLFormElement;
|
private _createForm = document.getElementById("form-add-profile") as HTMLFormElement;
|
||||||
private _profileName = document.getElementById("add-profile-name") as HTMLInputElement;
|
private _profileName = document.getElementById("add-profile-name") as HTMLInputElement;
|
||||||
@ -181,7 +207,7 @@ export class ProfileEditor {
|
|||||||
this._profiles[name].update(name, resp.profiles[name]);
|
this._profiles[name].update(name, resp.profiles[name]);
|
||||||
} else {
|
} else {
|
||||||
this._profiles[name] = new profile(name, resp.profiles[name]);
|
this._profiles[name] = new profile(name, resp.profiles[name]);
|
||||||
if (window.ombiEnabled)
|
if (window.ombiEnabled) {
|
||||||
this._profiles[name].setOmbiFunc((ombi: boolean) => {
|
this._profiles[name].setOmbiFunc((ombi: boolean) => {
|
||||||
if (ombi) {
|
if (ombi) {
|
||||||
this._ombiProfiles.delete(name, (req: XMLHttpRequest) => {
|
this._ombiProfiles.delete(name, (req: XMLHttpRequest) => {
|
||||||
@ -198,7 +224,26 @@ export class ProfileEditor {
|
|||||||
this._ombiProfiles.load(name);
|
this._ombiProfiles.load(name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (window.referralsEnabled)
|
}
|
||||||
|
if (window.jellyseerrEnabled) {
|
||||||
|
this._profiles[name].setJellyseerrFunc((jellyseerr: boolean) => {
|
||||||
|
if (jellyseerr) {
|
||||||
|
this._jellyseerrProfiles.delete(name, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
if (req.status != 204) {
|
||||||
|
window.notifications.customError("errorDeleteJellyseerr", window.lang.notif("errorUnknown"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._profiles[name].jellyseerr = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.modals.profiles.close();
|
||||||
|
this._jellyseerrProfiles.load(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (window.referralsEnabled) {
|
||||||
this._profiles[name].setReferralFunc((enabled: boolean) => {
|
this._profiles[name].setReferralFunc((enabled: boolean) => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
this.disableReferrals(name);
|
this.disableReferrals(name);
|
||||||
@ -206,6 +251,7 @@ export class ProfileEditor {
|
|||||||
this.enableReferrals(name);
|
this.enableReferrals(name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
this._table.appendChild(this._profiles[name].asElement());
|
this._table.appendChild(this._profiles[name].asElement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,6 +345,8 @@ export class ProfileEditor {
|
|||||||
|
|
||||||
if (window.ombiEnabled)
|
if (window.ombiEnabled)
|
||||||
this._ombiProfiles = new ombiProfiles();
|
this._ombiProfiles = new ombiProfiles();
|
||||||
|
if (window.jellyseerrEnabled)
|
||||||
|
this._jellyseerrProfiles = new jellyseerrProfiles();
|
||||||
|
|
||||||
this._createButton.onclick = () => _get("/users", null, (req: XMLHttpRequest) => {
|
this._createButton.onclick = () => _get("/users", null, (req: XMLHttpRequest) => {
|
||||||
if (req.readyState == 4) {
|
if (req.readyState == 4) {
|
||||||
@ -366,7 +414,7 @@ export class ombiProfiles {
|
|||||||
let resp = {} as ombiUser;
|
let resp = {} as ombiUser;
|
||||||
resp.id = this._select.value;
|
resp.id = this._select.value;
|
||||||
resp.name = this._users[resp.id];
|
resp.name = this._users[resp.id];
|
||||||
_post("/profiles/ombi/" + this._currentProfile, resp, (req: XMLHttpRequest) => {
|
_post("/profiles/ombi/" + encodeURIComponent(encodeURIComponent(this._currentProfile)), resp, (req: XMLHttpRequest) => {
|
||||||
if (req.readyState == 4) {
|
if (req.readyState == 4) {
|
||||||
toggleLoader(button);
|
toggleLoader(button);
|
||||||
if (req.status == 200 || req.status == 204) {
|
if (req.status == 200 || req.status == 204) {
|
||||||
@ -379,7 +427,7 @@ export class ombiProfiles {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
delete = (profile: string, post?: (req: XMLHttpRequest) => void) => _delete("/profiles/ombi/" + profile, null, post);
|
delete = (profile: string, post?: (req: XMLHttpRequest) => void) => _delete("/profiles/ombi/" + encodeURIComponent(encodeURIComponent(profile)), null, post);
|
||||||
|
|
||||||
load = (profile: string) => {
|
load = (profile: string) => {
|
||||||
this._currentProfile = profile;
|
this._currentProfile = profile;
|
||||||
@ -401,3 +449,54 @@ export class ombiProfiles {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class jellyseerrProfiles {
|
||||||
|
private _form: HTMLFormElement;
|
||||||
|
private _select: HTMLSelectElement;
|
||||||
|
private _users: { [id: string]: string } = {};
|
||||||
|
private _currentProfile: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._form = document.getElementById("form-jellyseerr-defaults") as HTMLFormElement;
|
||||||
|
this._form.onsubmit = this.send;
|
||||||
|
this._select = this._form.querySelector("select") as HTMLSelectElement;
|
||||||
|
}
|
||||||
|
send = () => {
|
||||||
|
const button = this._form.querySelector("span.submit") as HTMLSpanElement;
|
||||||
|
toggleLoader(button);
|
||||||
|
let encodedProfile = encodeURIComponent(encodeURIComponent(this._currentProfile));
|
||||||
|
_post("/profiles/jellyseerr/" + encodedProfile + "/" + this._select.value, null, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
toggleLoader(button);
|
||||||
|
if (req.status == 200 || req.status == 204) {
|
||||||
|
window.notifications.customSuccess("jellyseerrDefaults", window.lang.notif("savedProfile"));
|
||||||
|
} else {
|
||||||
|
window.notifications.customError("jellyseerrDefaults", window.lang.notif("errorSavedProfile"));
|
||||||
|
}
|
||||||
|
window.modals.jellyseerrProfile.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
delete = (profile: string, post?: (req: XMLHttpRequest) => void) => _delete("/profiles/jellyseerr/" + encodeURIComponent(encodeURIComponent(profile)), null, post);
|
||||||
|
|
||||||
|
load = (profile: string) => {
|
||||||
|
this._currentProfile = profile;
|
||||||
|
_get("/jellyseerr/users", null, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
if (req.status == 200 && "users" in req.response) {
|
||||||
|
const users = req.response["users"] as ombiUser[];
|
||||||
|
let innerHTML = "";
|
||||||
|
for (let user of users) {
|
||||||
|
this._users[user.id] = user.name;
|
||||||
|
innerHTML += `<option value="${user.id}">${user.name}</option>`;
|
||||||
|
}
|
||||||
|
this._select.innerHTML = innerHTML;
|
||||||
|
window.modals.jellyseerrProfile.show();
|
||||||
|
} else {
|
||||||
|
window.notifications.customError("jellyseerrLoadError", window.lang.notif("errorLoadUsers"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@ declare interface Window {
|
|||||||
discordEnabled: boolean;
|
discordEnabled: boolean;
|
||||||
matrixEnabled: boolean;
|
matrixEnabled: boolean;
|
||||||
ombiEnabled: boolean;
|
ombiEnabled: boolean;
|
||||||
|
jellyseerrEnabled: boolean;
|
||||||
usernameEnabled: boolean;
|
usernameEnabled: boolean;
|
||||||
linkResetEnabled: boolean;
|
linkResetEnabled: boolean;
|
||||||
token: string;
|
token: string;
|
||||||
@ -101,6 +102,7 @@ declare interface Modals {
|
|||||||
settingsRestart: Modal;
|
settingsRestart: Modal;
|
||||||
settingsRefresh: Modal;
|
settingsRefresh: Modal;
|
||||||
ombiProfile?: Modal;
|
ombiProfile?: Modal;
|
||||||
|
jellyseerrProfile?: Modal;
|
||||||
profiles: Modal;
|
profiles: Modal;
|
||||||
addProfile: Modal;
|
addProfile: Modal;
|
||||||
announce: Modal;
|
announce: Modal;
|
||||||
|
5
views.go
5
views.go
@ -133,6 +133,7 @@ func (app *appContext) AdminPage(gc *gin.Context) {
|
|||||||
emailEnabled, _ := app.config.Section("invite_emails").Key("enabled").Bool()
|
emailEnabled, _ := app.config.Section("invite_emails").Key("enabled").Bool()
|
||||||
notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
|
notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
|
||||||
ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
|
ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
|
||||||
|
jellyseerrEnabled := app.config.Section("jellyseerr").Key("enabled").MustBool(false)
|
||||||
jfAdminOnly := app.config.Section("ui").Key("admin_only").MustBool(true)
|
jfAdminOnly := app.config.Section("ui").Key("admin_only").MustBool(true)
|
||||||
jfAllowAll := app.config.Section("ui").Key("allow_all").MustBool(false)
|
jfAllowAll := app.config.Section("ui").Key("allow_all").MustBool(false)
|
||||||
var license string
|
var license string
|
||||||
@ -164,6 +165,7 @@ func (app *appContext) AdminPage(gc *gin.Context) {
|
|||||||
"discordEnabled": discordEnabled,
|
"discordEnabled": discordEnabled,
|
||||||
"matrixEnabled": matrixEnabled,
|
"matrixEnabled": matrixEnabled,
|
||||||
"ombiEnabled": ombiEnabled,
|
"ombiEnabled": ombiEnabled,
|
||||||
|
"jellyseerrEnabled": jellyseerrEnabled,
|
||||||
"linkResetEnabled": app.config.Section("password_resets").Key("link_reset").MustBool(false),
|
"linkResetEnabled": app.config.Section("password_resets").Key("link_reset").MustBool(false),
|
||||||
"notifications": notificationsEnabled,
|
"notifications": notificationsEnabled,
|
||||||
"version": version,
|
"version": version,
|
||||||
@ -192,6 +194,7 @@ func (app *appContext) MyUserPage(gc *gin.Context) {
|
|||||||
emailEnabled, _ := app.config.Section("invite_emails").Key("enabled").Bool()
|
emailEnabled, _ := app.config.Section("invite_emails").Key("enabled").Bool()
|
||||||
notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
|
notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
|
||||||
ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
|
ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
|
||||||
|
jellyseerrEnabled := app.config.Section("jellyseerr").Key("enabled").MustBool(false)
|
||||||
data := gin.H{
|
data := gin.H{
|
||||||
"urlBase": app.getURLBase(gc),
|
"urlBase": app.getURLBase(gc),
|
||||||
"cssClass": app.cssClass,
|
"cssClass": app.cssClass,
|
||||||
@ -203,6 +206,7 @@ func (app *appContext) MyUserPage(gc *gin.Context) {
|
|||||||
"discordEnabled": discordEnabled,
|
"discordEnabled": discordEnabled,
|
||||||
"matrixEnabled": matrixEnabled,
|
"matrixEnabled": matrixEnabled,
|
||||||
"ombiEnabled": ombiEnabled,
|
"ombiEnabled": ombiEnabled,
|
||||||
|
"jellyseerrEnabled": jellyseerrEnabled,
|
||||||
"pwrEnabled": app.config.Section("password_resets").Key("enabled").MustBool(false),
|
"pwrEnabled": app.config.Section("password_resets").Key("enabled").MustBool(false),
|
||||||
"linkResetEnabled": app.config.Section("password_resets").Key("link_reset").MustBool(false),
|
"linkResetEnabled": app.config.Section("password_resets").Key("link_reset").MustBool(false),
|
||||||
"notifications": notificationsEnabled,
|
"notifications": notificationsEnabled,
|
||||||
@ -278,6 +282,7 @@ func (app *appContext) ResetPassword(gc *gin.Context) {
|
|||||||
"strings": app.storage.lang.PasswordReset[lang].Strings,
|
"strings": app.storage.lang.PasswordReset[lang].Strings,
|
||||||
"success": false,
|
"success": false,
|
||||||
"ombiEnabled": app.config.Section("ombi").Key("enabled").MustBool(false),
|
"ombiEnabled": app.config.Section("ombi").Key("enabled").MustBool(false),
|
||||||
|
"jellyseerrEnabled": app.config.Section("jellyseerr").Key("enabled").MustBool(false),
|
||||||
"customSuccessCard": false,
|
"customSuccessCard": false,
|
||||||
}
|
}
|
||||||
pwr, isInternal := app.internalPWRs[pin]
|
pwr, isInternal := app.internalPWRs[pin]
|
||||||
|
Loading…
Reference in New Issue
Block a user