api clients: return data, error, no status

jellyseerr already did this, but it's been standardised a little more.

Mediabrowser uses it's own genericErr function and error types due to
being a separate package, while jellyseerr and ombi now share errors
defined in common/.
pull/297/head
Harvey Tindall 4 months ago
parent 284312713c
commit 2310130e6b
No known key found for this signature in database
GPG Key ID: BBC65952848FB1A2

@ -211,7 +211,7 @@ $(COPY_TARGET): $(INLINE_TARGET) $(STATIC_SRC)
GO_SRC = $(shell find ./ -name "*.go") GO_SRC = $(shell find ./ -name "*.go")
GO_TARGET = build/jfa-go GO_TARGET = build/jfa-go
$(GO_TARGET): $(CONFIG_DESCRIPTION) $(CONFIG_DEFAULT) $(EMAIL_TARGET) $(COPY_TARGET) $(SWAGGER_TARGET) $(GO_SRC) $(GO_TARGET): $(CONFIG_DESCRIPTION) $(CONFIG_DEFAULT) $(EMAIL_TARGET) $(COPY_TARGET) $(SWAGGER_TARGET) $(GO_SRC) go.mod go.sum
$(info Downloading deps) $(info Downloading deps)
$(GOBINARY) mod download $(GOBINARY) mod download
$(info Building) $(info Building)

@ -144,13 +144,13 @@ func (app *appContext) GetActivities(gc *gin.Context) {
if act.Type == ActivityDeletion || act.Type == ActivityCreation { if act.Type == ActivityDeletion || act.Type == ActivityCreation {
resp.Activities[i].Username = act.Value resp.Activities[i].Username = act.Value
resp.Activities[i].Value = "" resp.Activities[i].Value = ""
} else if user, status, err := app.jf.UserByID(act.UserID, false); status == 200 && err == nil { } else if user, err := app.jf.UserByID(act.UserID, false); err == nil {
resp.Activities[i].Username = user.Name resp.Activities[i].Username = user.Name
} }
if (act.SourceType == ActivityUser || act.SourceType == ActivityAdmin) && act.Source != "" { if (act.SourceType == ActivityUser || act.SourceType == ActivityAdmin) && act.Source != "" {
user, status, err := app.jf.UserByID(act.Source, false) user, err := app.jf.UserByID(act.Source, false)
if status == 200 && err == nil { if err == nil {
resp.Activities[i].SourceUsername = user.Name resp.Activities[i].SourceUsername = user.Name
} }
} }

@ -1,34 +1,35 @@
package main package main
import ( import (
"errors"
"fmt" "fmt"
"net/url" "net/url"
"strings" "strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/hrfee/jfa-go/common"
lm "github.com/hrfee/jfa-go/logmessages" lm "github.com/hrfee/jfa-go/logmessages"
"github.com/hrfee/jfa-go/ombi" "github.com/hrfee/jfa-go/ombi"
"github.com/hrfee/mediabrowser" "github.com/hrfee/mediabrowser"
) )
func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, int, error) { func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, error) {
jfUser, code, err := app.jf.UserByID(jfID, false) jfUser, err := app.jf.UserByID(jfID, false)
if err != nil || code != 200 { if err != nil {
return nil, code, err return nil, err
} }
username := jfUser.Name username := jfUser.Name
email := "" email := ""
if e, ok := app.storage.GetEmailsKey(jfID); ok { if e, ok := app.storage.GetEmailsKey(jfID); ok {
email = e.Addr email = e.Addr
} }
return app.ombi.getUser(username, email) user, err := app.ombi.getUser(username, email)
return user, err
} }
func (ombi *OmbiWrapper) getUser(username string, email string) (map[string]interface{}, int, error) { func (ombi *OmbiWrapper) getUser(username string, email string) (map[string]interface{}, error) {
ombiUsers, code, err := ombi.GetUsers() ombiUsers, err := ombi.GetUsers()
if err != nil || code != 200 { if err != nil {
return nil, code, err return nil, err
} }
for _, ombiUser := range ombiUsers { for _, ombiUser := range ombiUsers {
ombiAddr := "" ombiAddr := ""
@ -36,18 +37,19 @@ func (ombi *OmbiWrapper) getUser(username string, email string) (map[string]inte
ombiAddr = a.(string) ombiAddr = a.(string)
} }
if ombiUser["userName"].(string) == username || (ombiAddr == email && email != "") { if ombiUser["userName"].(string) == username || (ombiAddr == email && email != "") {
return ombiUser, code, err return ombiUser, err
} }
} }
return nil, 400, errors.New(lm.NotFound) // Gets a generic "not found" type error
return nil, common.GenericErr(404, err)
} }
// Returns a user with the given name who has been imported from Jellyfin/Emby by Ombi // Returns a user with the given name who has been imported from Jellyfin/Emby by Ombi
func (ombi *OmbiWrapper) getImportedUser(name string) (map[string]interface{}, int, error) { func (ombi *OmbiWrapper) getImportedUser(name string) (map[string]interface{}, error) {
// Ombi User Types: 3/4 = Emby, 5 = Jellyfin // Ombi User Types: 3/4 = Emby, 5 = Jellyfin
ombiUsers, code, err := ombi.GetUsers() ombiUsers, err := ombi.GetUsers()
if err != nil || code != 200 { if err != nil {
return nil, code, err return nil, err
} }
for _, ombiUser := range ombiUsers { for _, ombiUser := range ombiUsers {
if ombiUser["userName"].(string) == name { if ombiUser["userName"].(string) == name {
@ -60,10 +62,11 @@ func (ombi *OmbiWrapper) getImportedUser(name string) (map[string]interface{}, i
} else if uType != 3 && uType != 4 { // Emby } else if uType != 3 && uType != 4 { // Emby
continue continue
} }
return ombiUser, code, err return ombiUser, err
} }
} }
return nil, 400, fmt.Errorf("couldn't find user") // Gets a generic "not found" type error
return nil, common.GenericErr(404, err)
} }
// @Summary Get a list of Ombi users. // @Summary Get a list of Ombi users.
@ -74,8 +77,8 @@ func (ombi *OmbiWrapper) getImportedUser(name string) (map[string]interface{}, i
// @Security Bearer // @Security Bearer
// @tags Ombi // @tags Ombi
func (app *appContext) OmbiUsers(gc *gin.Context) { func (app *appContext) OmbiUsers(gc *gin.Context) {
users, status, err := app.ombi.GetUsers() users, err := app.ombi.GetUsers()
if err != nil || status != 200 { if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Ombi, err) app.err.Printf(lm.FailedGetUsers, lm.Ombi, err)
respond(500, "Couldn't get users", gc) respond(500, "Couldn't get users", gc)
return return
@ -110,8 +113,8 @@ func (app *appContext) SetOmbiProfile(gc *gin.Context) {
respondBool(400, false, gc) respondBool(400, false, gc)
return return
} }
template, code, err := app.ombi.TemplateByID(req.ID) template, err := app.ombi.TemplateByID(req.ID)
if err != nil || code != 200 || len(template) == 0 { if err != nil || len(template) == 0 {
app.err.Printf(lm.FailedGetUsers, lm.Ombi, err) app.err.Printf(lm.FailedGetUsers, lm.Ombi, err)
respond(500, "Couldn't get user", gc) respond(500, "Couldn't get user", gc)
return return
@ -147,7 +150,7 @@ type OmbiWrapper struct {
*ombi.Ombi *ombi.Ombi
} }
func (ombi *OmbiWrapper) applyProfile(user map[string]interface{}, profile map[string]interface{}) (status int, err error) { func (ombi *OmbiWrapper) applyProfile(user map[string]interface{}, profile map[string]interface{}) (err error) {
for k, v := range profile { for k, v := range profile {
switch v.(type) { switch v.(type) {
case map[string]interface{}, []interface{}: case map[string]interface{}, []interface{}:
@ -158,22 +161,21 @@ func (ombi *OmbiWrapper) applyProfile(user map[string]interface{}, profile map[s
} }
} }
} }
status, err = ombi.ModifyUser(user) err = ombi.ModifyUser(user)
return return
} }
func (ombi *OmbiWrapper) ImportUser(jellyfinID string, req newUserDTO, profile Profile) (err error, ok bool) { func (ombi *OmbiWrapper) ImportUser(jellyfinID string, req newUserDTO, profile Profile) (err error, ok bool) {
errors, code, err := ombi.NewUser(req.Username, req.Password, req.Email, profile.Ombi) errors, err := ombi.NewUser(req.Username, req.Password, req.Email, profile.Ombi)
var ombiUser map[string]interface{} var ombiUser map[string]interface{}
var status int if err != nil {
if err != nil || code != 200 {
// Check if on the off chance, Ombi's user importer has already added the account. // Check if on the off chance, Ombi's user importer has already added the account.
ombiUser, status, err = ombi.getImportedUser(req.Username) ombiUser, err = ombi.getImportedUser(req.Username)
if status == 200 && err == nil { if err == nil {
// app.info.Println(lm.Ombi + " " + lm.UserExists) // app.info.Println(lm.Ombi + " " + lm.UserExists)
profile.Ombi["password"] = req.Password profile.Ombi["password"] = req.Password
status, err = ombi.applyProfile(ombiUser, profile.Ombi) err = ombi.applyProfile(ombiUser, profile.Ombi)
if status != 200 || err != nil { if err != nil {
err = fmt.Errorf(lm.FailedApplyProfile, lm.Ombi, req.Username, err) err = fmt.Errorf(lm.FailedApplyProfile, lm.Ombi, req.Username, err)
} }
} else { } else {
@ -189,9 +191,8 @@ func (ombi *OmbiWrapper) ImportUser(jellyfinID string, req newUserDTO, profile P
func (ombi *OmbiWrapper) AddContactMethods(jellyfinID string, req newUserDTO, discord *DiscordUser, telegram *TelegramUser) (err error) { func (ombi *OmbiWrapper) AddContactMethods(jellyfinID string, req newUserDTO, discord *DiscordUser, telegram *TelegramUser) (err error) {
var ombiUser map[string]interface{} var ombiUser map[string]interface{}
var status int ombiUser, err = ombi.getUser(req.Username, req.Email)
ombiUser, status, err = ombi.getUser(req.Username, req.Email) if err != nil {
if status != 200 || err != nil {
return return
} }
if discordEnabled || telegramEnabled { if discordEnabled || telegramEnabled {
@ -204,9 +205,8 @@ func (ombi *OmbiWrapper) AddContactMethods(jellyfinID string, req newUserDTO, di
tUser = telegram.Username tUser = telegram.Username
} }
var resp string var resp string
var status int resp, err = ombi.SetNotificationPrefs(ombiUser, dID, tUser)
resp, status, err = ombi.SetNotificationPrefs(ombiUser, dID, tUser) if err != nil {
if !(status == 200 || status == 204) || err != nil {
if resp != "" { if resp != "" {
err = fmt.Errorf("%v, %s", err, resp) err = fmt.Errorf("%v, %s", err, resp)
} }

@ -84,8 +84,8 @@ func (app *appContext) CreateProfile(gc *gin.Context) {
var req newProfileDTO var req newProfileDTO
gc.BindJSON(&req) gc.BindJSON(&req)
app.jf.CacheExpiry = time.Now() app.jf.CacheExpiry = time.Now()
user, status, err := app.jf.UserByID(req.ID, false) user, err := app.jf.UserByID(req.ID, false)
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err)
respond(500, "Couldn't get user", gc) respond(500, "Couldn't get user", gc)
return return
@ -98,8 +98,8 @@ func (app *appContext) CreateProfile(gc *gin.Context) {
app.debug.Printf(lm.CreateProfileFromUser, user.Name) app.debug.Printf(lm.CreateProfileFromUser, user.Name)
if req.Homescreen { if req.Homescreen {
profile.Configuration = user.Configuration profile.Configuration = user.Configuration
profile.Displayprefs, status, err = app.jf.GetDisplayPreferences(req.ID) profile.Displayprefs, err = app.jf.GetDisplayPreferences(req.ID)
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedGetJellyfinDisplayPrefs, req.ID, err) app.err.Printf(lm.FailedGetJellyfinDisplayPrefs, req.ID, err)
respond(500, "Couldn't get displayprefs", gc) respond(500, "Couldn't get displayprefs", gc)
return return

@ -29,8 +29,8 @@ func (app *appContext) MyDetails(gc *gin.Context) {
Id: gc.GetString("jfId"), Id: gc.GetString("jfId"),
} }
user, status, err := app.jf.UserByID(resp.Id, false) user, err := app.jf.UserByID(resp.Id, false)
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err)
respond(500, "Failed to get user", gc) respond(500, "Failed to get user", gc)
return return
@ -259,9 +259,9 @@ func (app *appContext) ModifyMyEmail(gc *gin.Context) {
} }
if emailEnabled && app.config.Section("email_confirmation").Key("enabled").MustBool(false) { if emailEnabled && app.config.Section("email_confirmation").Key("enabled").MustBool(false) {
user, status, err := app.jf.UserByID(id, false) user, err := app.jf.UserByID(id, false)
name := "" name := ""
if status == 200 && err == nil { if err == nil {
name = user.Name name = user.Name
} }
app.debug.Printf(lm.EmailConfirmationRequired, id) app.debug.Printf(lm.EmailConfirmationRequired, id)
@ -688,20 +688,20 @@ func (app *appContext) ChangeMyPassword(gc *gin.Context) {
return return
} }
} }
user, status, err := app.jf.UserByID(gc.GetString("jfId"), false) user, err := app.jf.UserByID(gc.GetString("jfId"), false)
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUser, gc.GetString("jfId"), lm.Jellyfin, err) app.err.Printf(lm.FailedGetUser, gc.GetString("jfId"), lm.Jellyfin, err)
respondBool(500, false, gc) respondBool(500, false, gc)
return return
} }
// Authenticate as user to confirm old password. // Authenticate as user to confirm old password.
user, status, err = app.authJf.Authenticate(user.Name, req.Old) user, err = app.authJf.Authenticate(user.Name, req.Old)
if status != 200 || err != nil { if err != nil {
respondBool(401, false, gc) respondBool(401, false, gc)
return return
} }
status, err = app.jf.SetPassword(gc.GetString("jfId"), req.Old, req.New) err = app.jf.SetPassword(gc.GetString("jfId"), req.Old, req.New)
if (status != 200 && status != 204) || err != nil { if err != nil {
respondBool(500, false, gc) respondBool(500, false, gc)
return return
} }
@ -716,14 +716,14 @@ func (app *appContext) ChangeMyPassword(gc *gin.Context) {
if app.config.Section("ombi").Key("enabled").MustBool(false) { if app.config.Section("ombi").Key("enabled").MustBool(false) {
func() { func() {
ombiUser, status, err := app.getOmbiUser(gc.GetString("jfId")) ombiUser, err := app.getOmbiUser(gc.GetString("jfId"))
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUser, user.Name, lm.Ombi, err) app.err.Printf(lm.FailedGetUser, user.Name, lm.Ombi, err)
return return
} }
ombiUser["password"] = req.New ombiUser["password"] = req.New
status, err = app.ombi.ModifyUser(ombiUser) err = app.ombi.ModifyUser(ombiUser)
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedChangePassword, lm.Ombi, ombiUser["userName"], err) app.err.Printf(lm.FailedChangePassword, lm.Ombi, ombiUser["userName"], err)
return return
} }

@ -379,9 +379,9 @@ func (app *appContext) EnableDisableUsers(gc *gin.Context) {
activityType = ActivityEnabled activityType = ActivityEnabled
} }
for _, userID := range req.Users { for _, userID := range req.Users {
user, status, err := app.jf.UserByID(userID, false) user, err := app.jf.UserByID(userID, false)
if status != 200 || err != nil { if err != nil {
errors["GetUser"][user.ID] = fmt.Sprintf("%d %v", status, err) errors["GetUser"][user.ID] = err.Error()
app.err.Printf(lm.FailedGetUser, user.ID, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUser, user.ID, lm.Jellyfin, err)
continue continue
} }
@ -440,10 +440,7 @@ func (app *appContext) DeleteUsers(gc *gin.Context) {
} }
} }
for _, userID := range req.Users { for _, userID := range req.Users {
user, status, err := app.jf.UserByID(userID, false) user, err := app.jf.UserByID(userID, false)
if status != 200 && err == nil {
err = fmt.Errorf("failed (code %d)", status)
}
if err != nil { if err != nil {
app.err.Printf(lm.FailedGetUser, user.ID, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUser, user.ID, lm.Jellyfin, err)
errors[userID] = err.Error() errors[userID] = err.Error()
@ -522,8 +519,8 @@ func (app *appContext) ExtendExpiry(gc *gin.Context) {
app.storage.SetUserExpiryKey(id, expiry) app.storage.SetUserExpiryKey(id, expiry)
if messagesEnabled && req.Notify { if messagesEnabled && req.Notify {
go func(uid string, exp time.Time) { go func(uid string, exp time.Time) {
user, status, err := app.jf.UserByID(uid, false) user, err := app.jf.UserByID(uid, false)
if status != 200 || err != nil { if err != nil {
return return
} }
msg, err := app.email.constructExpiryAdjusted(user.Name, exp, req.Reason, app, false) msg, err := app.email.constructExpiryAdjusted(user.Name, exp, req.Reason, app, false)
@ -655,8 +652,8 @@ func (app *appContext) Announce(gc *gin.Context) {
unique := strings.Contains(req.Message, "{username}") unique := strings.Contains(req.Message, "{username}")
if unique { if unique {
for _, userID := range req.Users { for _, userID := range req.Users {
user, status, err := app.jf.UserByID(userID, false) user, err := app.jf.UserByID(userID, false)
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUser, userID, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUser, userID, lm.Jellyfin, err)
continue continue
} }
@ -835,9 +832,9 @@ func (app *appContext) AdminPasswordReset(gc *gin.Context) {
// @tags Users // @tags Users
func (app *appContext) GetUsers(gc *gin.Context) { func (app *appContext) GetUsers(gc *gin.Context) {
var resp getUsersDTO var resp getUsersDTO
users, status, err := app.jf.GetUsers(false) users, err := app.jf.GetUsers(false)
resp.UserList = make([]respUser, len(users)) resp.UserList = make([]respUser, len(users))
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err)
respond(500, "Couldn't get users", gc) respond(500, "Couldn't get users", gc)
return return
@ -910,8 +907,8 @@ func (app *appContext) GetUsers(gc *gin.Context) {
func (app *appContext) SetAccountsAdmin(gc *gin.Context) { func (app *appContext) SetAccountsAdmin(gc *gin.Context) {
var req setAccountsAdminDTO var req setAccountsAdminDTO
gc.BindJSON(&req) gc.BindJSON(&req)
users, status, err := app.jf.GetUsers(false) users, err := app.jf.GetUsers(false)
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err)
respond(500, "Couldn't get users", gc) respond(500, "Couldn't get users", gc)
return return
@ -942,8 +939,8 @@ func (app *appContext) SetAccountsAdmin(gc *gin.Context) {
func (app *appContext) ModifyLabels(gc *gin.Context) { func (app *appContext) ModifyLabels(gc *gin.Context) {
var req modifyEmailsDTO var req modifyEmailsDTO
gc.BindJSON(&req) gc.BindJSON(&req)
users, status, err := app.jf.GetUsers(false) users, err := app.jf.GetUsers(false)
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err)
respond(500, "Couldn't get users", gc) respond(500, "Couldn't get users", gc)
return return
@ -976,11 +973,11 @@ func (app *appContext) modifyEmail(jfID string, addr string) {
emailStore.Addr = addr emailStore.Addr = addr
app.storage.SetEmailsKey(jfID, emailStore) app.storage.SetEmailsKey(jfID, emailStore)
if app.config.Section("ombi").Key("enabled").MustBool(false) { if app.config.Section("ombi").Key("enabled").MustBool(false) {
ombiUser, code, err := app.getOmbiUser(jfID) ombiUser, err := app.getOmbiUser(jfID)
if code == 200 && err == nil { if err == nil {
ombiUser["emailAddress"] = addr ombiUser["emailAddress"] = addr
code, err = app.ombi.ModifyUser(ombiUser) err = app.ombi.ModifyUser(ombiUser)
if code != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedSetEmailAddress, lm.Ombi, jfID, err) app.err.Printf(lm.FailedSetEmailAddress, lm.Ombi, jfID, err)
} }
} }
@ -1012,8 +1009,8 @@ func (app *appContext) modifyEmail(jfID string, addr string) {
func (app *appContext) ModifyEmails(gc *gin.Context) { func (app *appContext) ModifyEmails(gc *gin.Context) {
var req modifyEmailsDTO var req modifyEmailsDTO
gc.BindJSON(&req) gc.BindJSON(&req)
users, status, err := app.jf.GetUsers(false) users, err := app.jf.GetUsers(false)
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err)
respond(500, "Couldn't get users", gc) respond(500, "Couldn't get users", gc)
return return
@ -1099,8 +1096,8 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
} else if req.From == "user" { } else if req.From == "user" {
applyingFromType = lm.User applyingFromType = lm.User
app.jf.CacheExpiry = time.Now() app.jf.CacheExpiry = time.Now()
user, status, err := app.jf.UserByID(req.ID, false) user, err := app.jf.UserByID(req.ID, false)
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUser, req.ID, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUser, req.ID, lm.Jellyfin, err)
respond(500, "Couldn't get user", gc) respond(500, "Couldn't get user", gc)
return return
@ -1110,8 +1107,8 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
policy = user.Policy policy = user.Policy
} }
if req.Homescreen { if req.Homescreen {
displayprefs, status, err = app.jf.GetDisplayPreferences(req.ID) displayprefs, err = app.jf.GetDisplayPreferences(req.ID)
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedGetJellyfinDisplayPrefs, req.ID, err) app.err.Printf(lm.FailedGetJellyfinDisplayPrefs, req.ID, err)
respond(500, "Couldn't get displayprefs", gc) respond(500, "Couldn't get displayprefs", gc)
return return
@ -1136,26 +1133,25 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
app.debug.Printf(lm.DelayingRequests, requestDelayThreshold) app.debug.Printf(lm.DelayingRequests, requestDelayThreshold)
} }
for _, id := range req.ApplyTo { for _, id := range req.ApplyTo {
var status int
var err error var err error
if req.Policy { if req.Policy {
status, err = app.jf.SetPolicy(id, policy) err = app.jf.SetPolicy(id, policy)
if !(status == 200 || status == 204) || err != nil { if err != nil {
errors["policy"][id] = fmt.Sprintf("%d: %s", status, err) errors["policy"][id] = err.Error()
} }
} }
if shouldDelay { if shouldDelay {
time.Sleep(250 * time.Millisecond) time.Sleep(250 * time.Millisecond)
} }
if req.Homescreen { if req.Homescreen {
status, err = app.jf.SetConfiguration(id, configuration) err = app.jf.SetConfiguration(id, configuration)
errorString := "" errorString := ""
if !(status == 200 || status == 204) || err != nil { if err != nil {
errorString += fmt.Sprintf("Configuration %d: %v ", status, err) errorString += fmt.Sprintf("Configuration: %v", err)
} else { } else {
status, err = app.jf.SetDisplayPreferences(id, displayprefs) err = app.jf.SetDisplayPreferences(id, displayprefs)
if !(status == 200 || status == 204) || err != nil { if err != nil {
errorString += fmt.Sprintf("Displayprefs %d: %v ", status, err) errorString += fmt.Sprintf("Displayprefs;) %v ", err)
} }
} }
if errorString != "" { if errorString != "" {
@ -1164,18 +1160,18 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
} }
if ombi != nil { if ombi != nil {
errorString := "" errorString := ""
user, status, err := app.getOmbiUser(id) user, err := app.getOmbiUser(id)
if status != 200 || err != nil { if err != nil {
errorString += fmt.Sprintf("Ombi GetUser %d: %v ", status, err) errorString += fmt.Sprintf("Ombi GetUser: %v ", err)
} else { } else {
// newUser := ombi // newUser := ombi
// newUser["id"] = user["id"] // newUser["id"] = user["id"]
// newUser["userName"] = user["userName"] // newUser["userName"] = user["userName"]
// newUser["alias"] = user["alias"] // newUser["alias"] = user["alias"]
// newUser["emailAddress"] = user["emailAddress"] // newUser["emailAddress"] = user["emailAddress"]
status, err = app.ombi.applyProfile(user, ombi) err = app.ombi.applyProfile(user, ombi)
if status != 200 || err != nil { if err != nil {
errorString += fmt.Sprintf("Apply %d: %v ", status, err) errorString += fmt.Sprintf("Apply: %v ", err)
} }
} }
if errorString != "" { if errorString != "" {

@ -148,18 +148,18 @@ func (app *appContext) ResetSetPassword(gc *gin.Context) {
userID = reset.ID userID = reset.ID
username = reset.Username username = reset.Username
status, err := app.jf.ResetPasswordAdmin(userID) err := app.jf.ResetPasswordAdmin(userID)
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedChangePassword, lm.Jellyfin, userID, err) app.err.Printf(lm.FailedChangePassword, lm.Jellyfin, userID, err)
respondBool(status, false, gc) respondBool(500, false, gc)
return return
} }
delete(app.internalPWRs, req.PIN) delete(app.internalPWRs, req.PIN)
} else { } else {
resp, status, err := app.jf.ResetPassword(req.PIN) resp, err := app.jf.ResetPassword(req.PIN)
if status != 200 || err != nil || !resp.Success { if err != nil || !resp.Success {
app.err.Printf(lm.FailedChangePassword, lm.Jellyfin, userID, err) app.err.Printf(lm.FailedChangePassword, lm.Jellyfin, userID, err)
respondBool(status, false, gc) respondBool(500, false, gc)
return return
} }
if req.Password == "" || len(resp.UsersReset) == 0 { if req.Password == "" || len(resp.UsersReset) == 0 {
@ -170,14 +170,13 @@ func (app *appContext) ResetSetPassword(gc *gin.Context) {
} }
var user mediabrowser.User var user mediabrowser.User
var status int
var err error var err error
if isInternal { if isInternal {
user, status, err = app.jf.UserByID(userID, false) user, err = app.jf.UserByID(userID, false)
} else { } else {
user, status, err = app.jf.UserByName(username, false) user, err = app.jf.UserByName(username, false)
} }
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUser, userID, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUser, userID, lm.Jellyfin, err)
respondBool(500, false, gc) respondBool(500, false, gc)
return return
@ -195,8 +194,8 @@ func (app *appContext) ResetSetPassword(gc *gin.Context) {
if isInternal { if isInternal {
prevPassword = "" prevPassword = ""
} }
status, err = app.jf.SetPassword(user.ID, prevPassword, req.Password) err = app.jf.SetPassword(user.ID, prevPassword, req.Password)
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedChangePassword, lm.Jellyfin, user.ID, err) app.err.Printf(lm.FailedChangePassword, lm.Jellyfin, user.ID, err)
respondBool(500, false, gc) respondBool(500, false, gc)
return return
@ -210,15 +209,15 @@ func (app *appContext) ResetSetPassword(gc *gin.Context) {
respondBool(200, true, gc) respondBool(200, true, gc)
return return
} */ } */
ombiUser, status, err := app.getOmbiUser(user.ID) ombiUser, err := app.getOmbiUser(user.ID)
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUser, user.ID, lm.Ombi, err) app.err.Printf(lm.FailedGetUser, user.ID, lm.Ombi, err)
respondBool(200, true, gc) respondBool(200, true, gc)
return return
} }
ombiUser["password"] = req.Password ombiUser["password"] = req.Password
status, err = app.ombi.ModifyUser(ombiUser) err = app.ombi.ModifyUser(ombiUser)
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedChangePassword, lm.Ombi, user.ID, err) app.err.Printf(lm.FailedChangePassword, lm.Ombi, user.ID, err)
respondBool(200, true, gc) respondBool(200, true, gc)
return return

@ -2,6 +2,7 @@ package main
import ( import (
"encoding/base64" "encoding/base64"
"errors"
"fmt" "fmt"
"os" "os"
"strings" "strings"
@ -166,19 +167,19 @@ func (app *appContext) decodeValidateLoginHeader(gc *gin.Context, userpage bool)
func (app *appContext) validateJellyfinCredentials(username, password string, gc *gin.Context, userpage bool) (user mediabrowser.User, ok bool) { func (app *appContext) validateJellyfinCredentials(username, password string, gc *gin.Context, userpage bool) (user mediabrowser.User, ok bool) {
ok = false ok = false
user, status, err := app.authJf.Authenticate(username, password) user, err := app.authJf.Authenticate(username, password)
if status != 200 || err != nil { if err != nil {
if status == 401 || status == 400 { if errors.Is(err, mediabrowser.ErrUnauthorized{}) {
app.logIpInfo(gc, userpage, fmt.Sprintf(lm.FailedAuthRequest, lm.InvalidUserOrPass)) app.logIpInfo(gc, userpage, fmt.Sprintf(lm.FailedAuthRequest, lm.InvalidUserOrPass))
respond(401, "Unauthorized", gc) respond(401, "Unauthorized", gc)
return return
} }
if status == 403 { if errors.Is(err, mediabrowser.ErrForbidden{}) {
app.logIpInfo(gc, userpage, fmt.Sprintf(lm.FailedAuthRequest, lm.UserDisabled)) app.logIpInfo(gc, userpage, fmt.Sprintf(lm.FailedAuthRequest, lm.UserDisabled))
respond(403, "yourAccountWasDisabled", gc) respond(403, "yourAccountWasDisabled", gc)
return return
} }
app.authLog(fmt.Sprintf(lm.FailedAuthJellyfin, app.jf.Server, status, err)) app.authLog(fmt.Sprintf(lm.FailedAuthJellyfin, app.jf.Server, err))
respond(500, "Jellyfin error", gc) respond(500, "Jellyfin error", gc)
return return
} }

@ -1,8 +1,11 @@
package common package common
import ( import (
"errors"
"fmt" "fmt"
"log" "log"
lm "github.com/hrfee/jfa-go/logmessages"
) )
// TimeoutHandler recovers from an http timeout or panic. // TimeoutHandler recovers from an http timeout or panic.
@ -12,7 +15,7 @@ type TimeoutHandler func()
func NewTimeoutHandler(name, addr string, noFail bool) TimeoutHandler { func NewTimeoutHandler(name, addr string, noFail bool) TimeoutHandler {
return func() { return func() {
if r := recover(); r != nil { if r := recover(); r != nil {
out := fmt.Sprintf("Failed to authenticate with %s @ \"%s\": Timed out", name, addr) out := fmt.Sprintf(lm.FailedAuth, name, addr, 0, lm.TimedOut)
if noFail { if noFail {
log.Print(out) log.Print(out)
} else { } else {
@ -21,3 +24,50 @@ func NewTimeoutHandler(name, addr string, noFail bool) TimeoutHandler {
} }
} }
} }
// most 404 errors are from UserNotFound, so this generic error doesn't really need any detail.
type ErrNotFound error
type ErrUnauthorized struct{}
func (err ErrUnauthorized) Error() string {
return lm.Unauthorized
}
type ErrForbidden struct{}
func (err ErrForbidden) Error() string {
return lm.Forbidden
}
var (
NotFound ErrNotFound = errors.New(lm.NotFound)
)
type ErrUnknown struct {
code int
}
func (err ErrUnknown) Error() string {
msg := fmt.Sprintf(lm.FailedGenericWithCode, err.code)
return msg
}
// GenericErr returns an error appropriate to the given HTTP status (or actual error, if given).
func GenericErr(status int, err error) error {
if err != nil {
return err
}
switch status {
case 200, 204, 201:
return nil
case 401, 400:
return ErrUnauthorized{}
case 404:
return NotFound
case 403:
return ErrForbidden{}
default:
return ErrUnknown{code: status}
}
}

@ -1,3 +1,7 @@
module github.com/hrfee/jfa-go/common module github.com/hrfee/jfa-go/common
go 1.15 replace github.com/hrfee/jfa-go/logmessages => ../logmessages
go 1.22.4
require github.com/hrfee/jfa-go/logmessages v0.0.0-20240805130902-86c37fb4237b

@ -968,11 +968,10 @@ func (app *appContext) getAddressOrName(jfID string) string {
// returns "" if none found. returns only the first match, might be an issue if there are users with the same contact method usernames. // returns "" if none found. returns only the first match, might be an issue if there are users with the same contact method usernames.
func (app *appContext) ReverseUserSearch(address string, matchUsername, matchEmail, matchContactMethod bool) (user mediabrowser.User, ok bool) { func (app *appContext) ReverseUserSearch(address string, matchUsername, matchEmail, matchContactMethod bool) (user mediabrowser.User, ok bool) {
ok = false ok = false
var status int
var err error = nil var err error = nil
if matchUsername { if matchUsername {
user, status, err = app.jf.UserByName(address, false) user, err = app.jf.UserByName(address, false)
if status == 200 && err == nil { if err == nil {
ok = true ok = true
return return
} }
@ -983,8 +982,8 @@ func (app *appContext) ReverseUserSearch(address string, matchUsername, matchEma
err = app.storage.db.Find(&emailAddresses, badgerhold.Where("Addr").Eq(address)) err = app.storage.db.Find(&emailAddresses, badgerhold.Where("Addr").Eq(address))
if err == nil && len(emailAddresses) > 0 { if err == nil && len(emailAddresses) > 0 {
for _, emailUser := range emailAddresses { for _, emailUser := range emailAddresses {
user, status, err = app.jf.UserByID(emailUser.JellyfinID, false) user, err = app.jf.UserByID(emailUser.JellyfinID, false)
if status == 200 && err == nil { if err == nil {
ok = true ok = true
return return
} }
@ -997,8 +996,8 @@ func (app *appContext) ReverseUserSearch(address string, matchUsername, matchEma
if matchContactMethod { if matchContactMethod {
for _, dcUser := range app.storage.GetDiscord() { for _, dcUser := range app.storage.GetDiscord() {
if RenderDiscordUsername(dcUser) == strings.ToLower(address) { if RenderDiscordUsername(dcUser) == strings.ToLower(address) {
user, status, err = app.jf.UserByID(dcUser.JellyfinID, false) user, err = app.jf.UserByID(dcUser.JellyfinID, false)
if status == 200 && err == nil { if err == nil {
ok = true ok = true
return return
} }
@ -1009,8 +1008,8 @@ func (app *appContext) ReverseUserSearch(address string, matchUsername, matchEma
err = app.storage.db.Find(&telegramUsers, badgerhold.Where("Username").Eq(tgUsername)) err = app.storage.db.Find(&telegramUsers, badgerhold.Where("Username").Eq(tgUsername))
if err == nil && len(telegramUsers) > 0 { if err == nil && len(telegramUsers) > 0 {
for _, telegramUser := range telegramUsers { for _, telegramUser := range telegramUsers {
user, status, err = app.jf.UserByID(telegramUser.JellyfinID, false) user, err = app.jf.UserByID(telegramUser.JellyfinID, false)
if status == 200 && err == nil { if err == nil {
ok = true ok = true
return return
} }
@ -1020,8 +1019,8 @@ func (app *appContext) ReverseUserSearch(address string, matchUsername, matchEma
err = app.storage.db.Find(&matrixUsers, badgerhold.Where("UserID").Eq(address)) err = app.storage.db.Find(&matrixUsers, badgerhold.Where("UserID").Eq(address))
if err == nil && len(matrixUsers) > 0 { if err == nil && len(matrixUsers) > 0 {
for _, matrixUser := range matrixUsers { for _, matrixUser := range matrixUsers {
user, status, err = app.jf.UserByID(matrixUser.JellyfinID, false) user, err = app.jf.UserByID(matrixUser.JellyfinID, false)
if status == 200 && err == nil { if err == nil {
ok = true ok = true
return return
} }

@ -33,13 +33,15 @@ 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-20240728190513-dabef831d769 github.com/hrfee/jfa-go/common v0.0.0-20240805130902-86c37fb4237b
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/jellyseerr v0.0.0-20240805130902-86c37fb4237b
github.com/hrfee/jfa-go/linecache v0.0.0-20230626224816-f72960635dc3 github.com/hrfee/jfa-go/linecache v0.0.0-20230626224816-f72960635dc3
github.com/hrfee/jfa-go/logger v0.0.0-20240731152135-2d066ea7cd32 github.com/hrfee/jfa-go/logger v0.0.0-20240731152135-2d066ea7cd32
github.com/hrfee/jfa-go/ombi v0.0.0-20230626224816-f72960635dc3 github.com/hrfee/jfa-go/logmessages v0.0.0-20240805130902-86c37fb4237b
github.com/hrfee/mediabrowser v0.3.14 github.com/hrfee/jfa-go/ombi v0.0.0-20240805130902-86c37fb4237b
github.com/hrfee/mediabrowser v0.3.18
github.com/itchyny/timefmt-go v0.1.5 github.com/itchyny/timefmt-go v0.1.5
github.com/lithammer/shortuuid/v3 v3.0.7 github.com/lithammer/shortuuid/v3 v3.0.7
github.com/mailgun/mailgun-go/v4 v4.9.1 github.com/mailgun/mailgun-go/v4 v4.9.1
@ -92,8 +94,6 @@ 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/hrfee/jfa-go/logmessages 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

@ -1,6 +1,7 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
@ -94,6 +95,7 @@ github.com/getlantern/systray v1.2.2/go.mod h1:pXFOI1wwqwYXEhLPm9ZGjS2u/vVELeIgN
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg= github.com/gin-contrib/pprof v1.4.0 h1:XxiBSf5jWZ5i16lNOPbMTVdgHBdhfGRD5PZ1LWazzvg=
github.com/gin-contrib/pprof v1.4.0/go.mod h1:RrehPJasUVBPK6yTUwOl8/NP6i0vbUgmxtis+Z5KE90= github.com/gin-contrib/pprof v1.4.0/go.mod h1:RrehPJasUVBPK6yTUwOl8/NP6i0vbUgmxtis+Z5KE90=
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
@ -140,6 +142,7 @@ github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogB
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@ -213,6 +216,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -224,10 +228,10 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hrfee/mediabrowser v0.3.13 h1:NgQNbq+JWwsP68BdWXL/rwbpfE/oO5LJ5KVkE+aNbX8= github.com/hrfee/mediabrowser v0.3.17 h1:gerX/sxQ8V64mZ13I0zuK9hpCJnScdTpAzD2j0a7bvE=
github.com/hrfee/mediabrowser v0.3.13/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U= github.com/hrfee/mediabrowser v0.3.17/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=
github.com/hrfee/mediabrowser v0.3.14 h1:/hxtwefV4pA63fyHussk00JBFry6p+uDDOumA49M1eY= github.com/hrfee/mediabrowser v0.3.18 h1:6UDyae0srEVjiMG+utPQfJJp4UId6/T3WN9EDCQKRTk=
github.com/hrfee/mediabrowser v0.3.14/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U= github.com/hrfee/mediabrowser v0.3.18/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
@ -289,6 +293,7 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -351,6 +356,7 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
@ -420,6 +426,7 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
@ -455,6 +462,7 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

@ -16,7 +16,7 @@ func (app *appContext) clearEmails() {
app.debug.Println(lm.HousekeepingEmail) app.debug.Println(lm.HousekeepingEmail)
emails := app.storage.GetEmails() emails := app.storage.GetEmails()
for _, email := range emails { for _, email := range emails {
_, _, err := app.jf.UserByID(email.JellyfinID, false) _, err := app.jf.UserByID(email.JellyfinID, false)
// Make sure the user doesn't exist, and no other error has occured // Make sure the user doesn't exist, and no other error has occured
switch err.(type) { switch err.(type) {
case mediabrowser.ErrUserNotFound: case mediabrowser.ErrUserNotFound:
@ -32,7 +32,7 @@ func (app *appContext) clearDiscord() {
app.debug.Println(lm.HousekeepingDiscord) app.debug.Println(lm.HousekeepingDiscord)
discordUsers := app.storage.GetDiscord() discordUsers := app.storage.GetDiscord()
for _, discordUser := range discordUsers { for _, discordUser := range discordUsers {
user, _, err := app.jf.UserByID(discordUser.JellyfinID, false) user, err := app.jf.UserByID(discordUser.JellyfinID, false)
// Make sure the user doesn't exist, and no other error has occured // Make sure the user doesn't exist, and no other error has occured
switch err.(type) { switch err.(type) {
case mediabrowser.ErrUserNotFound: case mediabrowser.ErrUserNotFound:
@ -53,7 +53,7 @@ func (app *appContext) clearMatrix() {
app.debug.Println(lm.HousekeepingMatrix) app.debug.Println(lm.HousekeepingMatrix)
matrixUsers := app.storage.GetMatrix() matrixUsers := app.storage.GetMatrix()
for _, matrixUser := range matrixUsers { for _, matrixUser := range matrixUsers {
_, _, err := app.jf.UserByID(matrixUser.JellyfinID, false) _, err := app.jf.UserByID(matrixUser.JellyfinID, false)
// Make sure the user doesn't exist, and no other error has occured // Make sure the user doesn't exist, and no other error has occured
switch err.(type) { switch err.(type) {
case mediabrowser.ErrUserNotFound: case mediabrowser.ErrUserNotFound:
@ -69,7 +69,7 @@ func (app *appContext) clearTelegram() {
app.debug.Println(lm.HousekeepingTelegram) app.debug.Println(lm.HousekeepingTelegram)
telegramUsers := app.storage.GetTelegram() telegramUsers := app.storage.GetTelegram()
for _, telegramUser := range telegramUsers { for _, telegramUser := range telegramUsers {
_, _, err := app.jf.UserByID(telegramUser.JellyfinID, false) _, err := app.jf.UserByID(telegramUser.JellyfinID, false)
// Make sure the user doesn't exist, and no other error has occured // Make sure the user doesn't exist, and no other error has occured
switch err.(type) { switch err.(type) {
case mediabrowser.ErrUserNotFound: case mediabrowser.ErrUserNotFound:

@ -44,7 +44,7 @@
</form> </form>
</div> </div>
<div id="modal-about" class="modal"> <div id="modal-about" class="modal">
<div class="relative mx-auto my-[10%] w-11/12 sm:w-4/5 lg:w-1/3 content card"> <div class="relative mx-auto my-[10%] w-11/12 sm:w-4/5 lg:w-1/2 content card">
<img src="{{ .urlBase }}/banner.svg" class="banner header" alt="jfa-go banner"> <img src="{{ .urlBase }}/banner.svg" class="banner header" alt="jfa-go banner">
<span class="heading"><span class="modal-close">&times;</span></span> <span class="heading"><span class="modal-close">&times;</span></span>
<p>{{ .strings.version }} <span class="text-black dark:text-white font-mono bg-inherit">{{ .version }}</span></p> <p>{{ .strings.version }} <span class="text-black dark:text-white font-mono bg-inherit">{{ .version }}</span></p>

@ -58,8 +58,8 @@ func (app *appContext) SynchronizeJellyseerrUser(jfID string) {
} }
func (app *appContext) SynchronizeJellyseerrUsers() { func (app *appContext) SynchronizeJellyseerrUsers() {
users, status, err := app.jf.GetUsers(false) users, err := app.jf.GetUsers(false)
if err != nil || status != 200 { if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err)
return return
} }

@ -12,7 +12,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/hrfee/jfa-go/common" co "github.com/hrfee/jfa-go/common"
) )
const ( const (
@ -28,13 +28,13 @@ type Jellyseerr struct {
userCache map[string]User // Map of jellyfin IDs to users userCache map[string]User // Map of jellyfin IDs to users
cacheExpiry time.Time cacheExpiry time.Time
cacheLength time.Duration cacheLength time.Duration
timeoutHandler common.TimeoutHandler timeoutHandler co.TimeoutHandler
LogRequestBodies bool LogRequestBodies bool
AutoImportUsers bool AutoImportUsers bool
} }
// NewJellyseerr returns an Ombi object. // NewJellyseerr returns an Ombi object.
func NewJellyseerr(server, key string, timeoutHandler common.TimeoutHandler) *Jellyseerr { func NewJellyseerr(server, key string, timeoutHandler co.TimeoutHandler) *Jellyseerr {
if !strings.HasSuffix(server, API_SUFFIX) { if !strings.HasSuffix(server, API_SUFFIX) {
server = server + API_SUFFIX server = server + API_SUFFIX
} }
@ -82,25 +82,23 @@ func (js *Jellyseerr) req(mode string, uri string, data any, queryParams url.Val
} }
} }
resp, err := js.httpClient.Do(req) resp, err := js.httpClient.Do(req)
reqFailed := err != nil || !(resp.StatusCode == 200 || resp.StatusCode == 201) err = co.GenericErr(resp.StatusCode, err)
defer js.timeoutHandler() defer js.timeoutHandler()
var responseText string var responseText string
defer resp.Body.Close() defer resp.Body.Close()
if response || reqFailed { if response || err != nil {
responseText, err = js.decodeResp(resp) responseText, err = js.decodeResp(resp)
if err != nil { if err != nil {
return responseText, resp.StatusCode, err return responseText, resp.StatusCode, err
} }
} }
if reqFailed { if err != nil {
var msg ErrorDTO var msg ErrorDTO
err = json.Unmarshal([]byte(responseText), &msg) err = json.Unmarshal([]byte(responseText), &msg)
if err != nil { if err != nil {
return responseText, resp.StatusCode, err return responseText, resp.StatusCode, err
} }
if msg.Message == "" { if msg.Message != "" {
err = fmt.Errorf("failed (error %d)", resp.StatusCode)
} else {
err = fmt.Errorf("got %d: %s", resp.StatusCode, msg.Message) err = fmt.Errorf("got %d: %s", resp.StatusCode, msg.Message)
} }
return responseText, resp.StatusCode, err return responseText, resp.StatusCode, err
@ -145,14 +143,11 @@ func (js *Jellyseerr) ImportFromJellyfin(jfIDs ...string) ([]User, error) {
params := map[string]interface{}{ params := map[string]interface{}{
"jellyfinUserIds": jfIDs, "jellyfinUserIds": jfIDs,
} }
resp, status, err := js.post(js.server+"/user/import-from-jellyfin", params, true) resp, _, err := js.post(js.server+"/user/import-from-jellyfin", params, true)
var data []User var data []User
if err != nil { if err != nil {
return data, err return data, err
} }
if status != 200 && status != 201 {
return data, fmt.Errorf("failed (error %d)", status)
}
err = json.Unmarshal([]byte(resp), &data) err = json.Unmarshal([]byte(resp), &data)
for _, u := range data { for _, u := range data {
if u.JellyfinUserID != "" { if u.JellyfinUserID != "" {
@ -197,15 +192,11 @@ func (js *Jellyseerr) getUserPage(page int) (GetUsersDTO, error) {
if js.LogRequestBodies { if js.LogRequestBodies {
fmt.Printf("Jellyseerr API Client: Sending with URL params \"%+v\"\n", params) fmt.Printf("Jellyseerr API Client: Sending with URL params \"%+v\"\n", params)
} }
resp, status, err := js.get(js.server+"/user", nil, params) resp, _, err := js.get(js.server+"/user", nil, params)
var data GetUsersDTO var data GetUsersDTO
if status != 200 { if err == nil {
return data, fmt.Errorf("failed (error %d)", status)
}
if err != nil {
return data, err
}
err = json.Unmarshal([]byte(resp), &data) err = json.Unmarshal([]byte(resp), &data)
}
return data, err return data, err
} }
@ -261,12 +252,9 @@ func (js *Jellyseerr) getUser(jfID string) (User, error) {
} }
func (js *Jellyseerr) Me() (User, error) { func (js *Jellyseerr) Me() (User, error) {
resp, status, err := js.get(js.server+"/auth/me", nil, url.Values{}) resp, _, err := js.get(js.server+"/auth/me", nil, url.Values{})
var data User var data User
data.ID = -1 data.ID = -1
if status != 200 {
return data, fmt.Errorf("failed (error %d)", status)
}
if err != nil { if err != nil {
return data, err return data, err
} }
@ -281,13 +269,10 @@ func (js *Jellyseerr) GetPermissions(jfID string) (Permissions, error) {
return data.Permissions, err return data.Permissions, err
} }
resp, status, err := js.get(fmt.Sprintf(js.server+"/user/%d/settings/permissions", u.ID), nil, url.Values{}) resp, _, err := js.get(fmt.Sprintf(js.server+"/user/%d/settings/permissions", u.ID), nil, url.Values{})
if err != nil { if err != nil {
return data.Permissions, err return data.Permissions, err
} }
if status != 200 {
return data.Permissions, fmt.Errorf("failed (error %d)", status)
}
err = json.Unmarshal([]byte(resp), &data) err = json.Unmarshal([]byte(resp), &data)
return data.Permissions, err return data.Permissions, err
} }
@ -298,13 +283,10 @@ func (js *Jellyseerr) SetPermissions(jfID string, perm Permissions) error {
return err return err
} }
_, status, err := js.post(fmt.Sprintf(js.server+"/user/%d/settings/permissions", u.ID), permissionsDTO{Permissions: perm}, false) _, _, err = js.post(fmt.Sprintf(js.server+"/user/%d/settings/permissions", u.ID), permissionsDTO{Permissions: perm}, false)
if err != nil { if err != nil {
return err return err
} }
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
u.Permissions = perm u.Permissions = perm
js.userCache[jfID] = u js.userCache[jfID] = u
return nil return nil
@ -316,13 +298,10 @@ func (js *Jellyseerr) ApplyTemplateToUser(jfID string, tmpl UserTemplate) error
return err return err
} }
_, status, err := js.put(fmt.Sprintf(js.server+"/user/%d", u.ID), tmpl, false) _, _, err = js.put(fmt.Sprintf(js.server+"/user/%d", u.ID), tmpl, false)
if err != nil { if err != nil {
return err return err
} }
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
u.UserTemplate = tmpl u.UserTemplate = tmpl
js.userCache[jfID] = u js.userCache[jfID] = u
return nil return nil
@ -337,13 +316,10 @@ func (js *Jellyseerr) ModifyUser(jfID string, conf map[UserField]any) error {
return err return err
} }
_, status, err := js.put(fmt.Sprintf(js.server+"/user/%d", u.ID), conf, false) _, _, err = js.put(fmt.Sprintf(js.server+"/user/%d", u.ID), conf, false)
if err != nil { if err != nil {
return err return err
} }
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
// Lazily just invalidate the cache. // Lazily just invalidate the cache.
js.cacheExpiry = time.Now() js.cacheExpiry = time.Now()
return nil return nil
@ -355,10 +331,7 @@ func (js *Jellyseerr) DeleteUser(jfID string) error {
return err return err
} }
status, err := js.delete(fmt.Sprintf(js.server+"/user/%d", u.ID), nil) _, err = js.delete(fmt.Sprintf(js.server+"/user/%d", u.ID), nil)
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
if err != nil { if err != nil {
return err return err
} }
@ -376,13 +349,10 @@ func (js *Jellyseerr) GetNotificationPreferences(jfID string) (Notifications, er
func (js *Jellyseerr) GetNotificationPreferencesByID(jellyseerrID int64) (Notifications, error) { func (js *Jellyseerr) GetNotificationPreferencesByID(jellyseerrID int64) (Notifications, error) {
var data Notifications var data Notifications
resp, status, err := js.get(fmt.Sprintf(js.server+"/user/%d/settings/notifications", jellyseerrID), nil, url.Values{}) resp, _, err := js.get(fmt.Sprintf(js.server+"/user/%d/settings/notifications", jellyseerrID), nil, url.Values{})
if err != nil { if err != nil {
return data, err return data, err
} }
if status != 200 {
return data, fmt.Errorf("failed (error %d)", status)
}
err = json.Unmarshal([]byte(resp), &data) err = json.Unmarshal([]byte(resp), &data)
return data, err return data, err
} }
@ -397,13 +367,10 @@ func (js *Jellyseerr) ApplyNotificationsTemplateToUser(jfID string, tmpl Notific
return err return err
} }
_, status, err := js.post(fmt.Sprintf(js.server+"/user/%d/settings/notifications", u.ID), tmpl, false) _, _, err = js.post(fmt.Sprintf(js.server+"/user/%d/settings/notifications", u.ID), tmpl, false)
if err != nil { if err != nil {
return err return err
} }
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
return nil return nil
} }
@ -413,13 +380,10 @@ func (js *Jellyseerr) ModifyNotifications(jfID string, conf map[NotificationsFie
return err return err
} }
_, status, err := js.post(fmt.Sprintf(js.server+"/user/%d/settings/notifications", u.ID), conf, false) _, _, err = js.post(fmt.Sprintf(js.server+"/user/%d/settings/notifications", u.ID), conf, false)
if err != nil { if err != nil {
return err return err
} }
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
return nil return nil
} }
@ -429,11 +393,8 @@ func (js *Jellyseerr) GetUsers() (map[string]User, error) {
} }
func (js *Jellyseerr) UserByID(jellyseerrID int64) (User, error) { func (js *Jellyseerr) UserByID(jellyseerrID int64) (User, error) {
resp, status, err := js.get(js.server+fmt.Sprintf("/user/%d", jellyseerrID), nil, url.Values{}) resp, _, err := js.get(js.server+fmt.Sprintf("/user/%d", jellyseerrID), nil, url.Values{})
var data User var data User
if status != 200 {
return data, fmt.Errorf("failed (error %d)", status)
}
if err != nil { if err != nil {
return data, err return data, err
} }
@ -447,13 +408,10 @@ func (js *Jellyseerr) ModifyMainUserSettings(jfID string, conf MainUserSettings)
return err return err
} }
_, status, err := js.post(fmt.Sprintf(js.server+"/user/%d/settings/main", u.ID), conf, false) _, _, err = js.post(fmt.Sprintf(js.server+"/user/%d/settings/main", u.ID), conf, false)
if err != nil { if err != nil {
return err return err
} }
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
// Lazily just invalidate the cache. // Lazily just invalidate the cache.
js.cacheExpiry = time.Now() js.cacheExpiry = time.Now()
return nil return nil

@ -1,3 +1,3 @@
module github.com/hrfee/logmessages module github.com/hrfee/jfa-go/logmessages
go 1.22.4 go 1.22.4

@ -45,7 +45,7 @@ const (
UsingTLS = "Using TLS/HTTP2" UsingTLS = "Using TLS/HTTP2"
UsingOmbi = "Starting " + " + Ombi + " + " client" UsingOmbi = "Starting " + Ombi + " client"
UsingJellyseerr = "Starting " + Jellyseerr + " client" UsingJellyseerr = "Starting " + Jellyseerr + " client"
UsingEmby = "Using Emby server type (EXPERIMENTAL: PWRs are not available, and support is limited.)" UsingEmby = "Using Emby server type (EXPERIMENTAL: PWRs are not available, and support is limited.)"
UsingJellyfin = "Using " + Jellyfin + " server type" UsingJellyfin = "Using " + Jellyfin + " server type"
@ -54,6 +54,13 @@ const (
AuthJellyfin = "Authenticated with " + Jellyfin + " @ \"%s\"" AuthJellyfin = "Authenticated with " + Jellyfin + " @ \"%s\""
FailedAuthJellyfin = "Failed to authenticate with " + Jellyfin + " @ \"%s\" (code %d): %v" FailedAuthJellyfin = "Failed to authenticate with " + Jellyfin + " @ \"%s\" (code %d): %v"
FailedAuth = "Failed to authenticate with %s @ \"%s\" (code %d): %v"
Unauthorized = "unauthorized, check credentials"
Forbidden = "forbidden, the user may not have correct permissions"
NotFound = "not found"
TimedOut = "timed out"
FailedGenericWithCode = "failed (code %d)"
InitDiscord = "Initialized Discord daemon" InitDiscord = "Initialized Discord daemon"
FailedInitDiscord = "Failed to initialize Discord daemon: %v" FailedInitDiscord = "Failed to initialize Discord daemon: %v"
@ -213,7 +220,6 @@ const (
FailedGetDiscordChannel = "Failed to get " + Discord + " channel \"%s\": %v" FailedGetDiscordChannel = "Failed to get " + Discord + " channel \"%s\": %v"
MonitorAllDiscordChannels = "Will monitor all " + Discord + " channels" MonitorAllDiscordChannels = "Will monitor all " + Discord + " channels"
FailedCreateDiscordDMChannel = "Failed to create " + Discord + " private DM channel with \"%s\": %v" FailedCreateDiscordDMChannel = "Failed to create " + Discord + " private DM channel with \"%s\": %v"
NotFound = "not found"
RegisterDiscordChoice = "Registered " + Discord + " %s choice \"%s\"" RegisterDiscordChoice = "Registered " + Discord + " %s choice \"%s\""
FailedRegisterDiscordChoices = "Failed to register " + Discord + " %s choices: %v" FailedRegisterDiscordChoices = "Failed to register " + Discord + " %s choices: %v"
FailedDeregDiscordChoice = "Failed to deregister " + Discord + " %s choice \"%s\": %v" FailedDeregDiscordChoice = "Failed to deregister " + Discord + " %s choice \"%s\": %v"

@ -154,8 +154,8 @@ func test(app *appContext) {
for n, v := range settings { for n, v := range settings {
fmt.Println(n, ":", v) fmt.Println(n, ":", v)
} }
users, status, err := app.jf.GetUsers(false) users, err := app.jf.GetUsers(false)
fmt.Printf("GetUsers: code %d err %s maplength %d\n", status, err, len(users)) fmt.Printf("GetUsers: err %s maplength %d\n", err, len(users))
fmt.Printf("View output? [y/n]: ") fmt.Printf("View output? [y/n]: ")
var choice string var choice string
fmt.Scanln(&choice) fmt.Scanln(&choice)
@ -166,8 +166,8 @@ func test(app *appContext) {
fmt.Printf("Enter a user to grab: ") fmt.Printf("Enter a user to grab: ")
var username string var username string
fmt.Scanln(&username) fmt.Scanln(&username)
user, status, err := app.jf.UserByName(username, false) user, err := app.jf.UserByName(username, false)
fmt.Printf("UserByName (%s): code %d err %s", username, status, err) fmt.Printf("UserByName (%s): code %d err %s", username, err)
out, _ := json.MarshalIndent(user, "", " ") out, _ := json.MarshalIndent(user, "", " ")
fmt.Print(string(out)) fmt.Print(string(out))
} }
@ -436,8 +436,8 @@ func start(asDaemon, firstCall bool) {
RetryGap: time.Duration(app.config.Section("advanced").Key("auth_retry_gap").MustInt(10)) * time.Second, RetryGap: time.Duration(app.config.Section("advanced").Key("auth_retry_gap").MustInt(10)) * time.Second,
LogFailures: true, LogFailures: true,
} }
_, status, err = app.jf.MustAuthenticate(app.config.Section("jellyfin").Key("username").String(), app.config.Section("jellyfin").Key("password").String(), retryOpts) _, err = app.jf.MustAuthenticate(app.config.Section("jellyfin").Key("username").String(), app.config.Section("jellyfin").Key("password").String(), retryOpts)
if status != 200 || err != nil { if err != nil {
app.err.Fatalf(lm.FailedAuthJellyfin, server, status, err) app.err.Fatalf(lm.FailedAuthJellyfin, server, status, err)
} }
app.info.Printf(lm.AuthJellyfin, server) app.info.Printf(lm.AuthJellyfin, server)

@ -185,14 +185,14 @@ func linkExistingOmbiDiscordTelegram(app *appContext) error {
idList[user.JellyfinID] = vals idList[user.JellyfinID] = vals
} }
for jfID, ids := range idList { for jfID, ids := range idList {
ombiUser, status, err := app.getOmbiUser(jfID) ombiUser, err := app.getOmbiUser(jfID)
if status != 200 || err != nil { if err != nil {
app.debug.Printf("Failed to get Ombi user with Discord/Telegram \"%s\"/\"%s\" (%d): %v", ids[0], ids[1], status, err) app.debug.Printf("Failed to get Ombi user with Discord/Telegram \"%s\"/\"%s\": %v", ids[0], ids[1], err)
continue continue
} }
_, status, err = app.ombi.SetNotificationPrefs(ombiUser, ids[0], ids[1]) _, err = app.ombi.SetNotificationPrefs(ombiUser, ids[0], ids[1])
if status != 200 || err != nil { if err != nil {
app.debug.Printf("Failed to set prefs for Ombi user \"%s\" (%d): %v", ombiUser["userName"].(string), status, err) app.debug.Printf("Failed to set prefs for Ombi user \"%s\": %v", ombiUser["userName"].(string), err)
continue continue
} }
} }

@ -3,3 +3,5 @@ module github.com/hrfee/jfa-go/ombi
replace github.com/hrfee/jfa-go/common => ../common replace github.com/hrfee/jfa-go/common => ../common
go 1.15 go 1.15
require github.com/hrfee/jfa-go/common v0.0.0-20240805130902-86c37fb4237b // indirect

@ -10,7 +10,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/hrfee/jfa-go/common" co "github.com/hrfee/jfa-go/common"
) )
const ( const (
@ -26,11 +26,11 @@ type Ombi struct {
userCache []map[string]interface{} userCache []map[string]interface{}
cacheExpiry time.Time cacheExpiry time.Time
cacheLength int cacheLength int
timeoutHandler common.TimeoutHandler timeoutHandler co.TimeoutHandler
} }
// NewOmbi returns an Ombi object. // NewOmbi returns an Ombi object.
func NewOmbi(server, key string, timeoutHandler common.TimeoutHandler) *Ombi { func NewOmbi(server, key string, timeoutHandler co.TimeoutHandler) *Ombi {
return &Ombi{ return &Ombi{
server: server, server: server,
key: key, key: key,
@ -133,17 +133,19 @@ func (ombi *Ombi) put(url string, data map[string]interface{}, response bool) (s
} }
// ModifyUser applies the given modified user object to the corresponding user. // ModifyUser applies the given modified user object to the corresponding user.
func (ombi *Ombi) ModifyUser(user map[string]interface{}) (status int, err error) { func (ombi *Ombi) ModifyUser(user map[string]interface{}) (err error) {
if _, ok := user["id"]; !ok { if _, ok := user["id"]; !ok {
err = fmt.Errorf("No ID provided") err = fmt.Errorf("No ID provided")
return return
} }
var status int
_, status, err = ombi.put(ombi.server+"/api/v1/Identity/", user, false) _, status, err = ombi.put(ombi.server+"/api/v1/Identity/", user, false)
err = co.GenericErr(status, err)
return return
} }
// DeleteUser deletes the user corresponding to the given ID. // DeleteUser deletes the user corresponding to the given ID.
func (ombi *Ombi) DeleteUser(id string) (code int, err error) { func (ombi *Ombi) DeleteUser(id string) (err error) {
url := fmt.Sprintf("%s/api/v1/Identity/%s", ombi.server, id) url := fmt.Sprintf("%s/api/v1/Identity/%s", ombi.server, id)
req, _ := http.NewRequest("DELETE", url, nil) req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("Content-Type", "application/json") req.Header.Add("Content-Type", "application/json")
@ -152,18 +154,19 @@ func (ombi *Ombi) DeleteUser(id string) (code int, err error) {
} }
resp, err := ombi.httpClient.Do(req) resp, err := ombi.httpClient.Do(req)
defer ombi.timeoutHandler() defer ombi.timeoutHandler()
return resp.StatusCode, err return co.GenericErr(resp.StatusCode, err)
} }
// UserByID returns the user corresponding to the provided ID. // UserByID returns the user corresponding to the provided ID.
func (ombi *Ombi) UserByID(id string) (result map[string]interface{}, code int, err error) { func (ombi *Ombi) UserByID(id string) (result map[string]interface{}, err error) {
resp, code, err := ombi.getJSON(fmt.Sprintf("%s/api/v1/Identity/User/%s", ombi.server, id), nil) resp, code, err := ombi.getJSON(fmt.Sprintf("%s/api/v1/Identity/User/%s", ombi.server, id), nil)
err = co.GenericErr(code, err)
json.Unmarshal([]byte(resp), &result) json.Unmarshal([]byte(resp), &result)
return return
} }
// GetUsers returns all users on the Ombi instance. // GetUsers returns all users on the Ombi instance.
func (ombi *Ombi) GetUsers() ([]map[string]interface{}, int, error) { func (ombi *Ombi) GetUsers() ([]map[string]interface{}, error) {
if time.Now().After(ombi.cacheExpiry) { if time.Now().After(ombi.cacheExpiry) {
resp, code, err := ombi.getJSON(fmt.Sprintf("%s/api/v1/Identity/Users", ombi.server), nil) resp, code, err := ombi.getJSON(fmt.Sprintf("%s/api/v1/Identity/Users", ombi.server), nil)
var result []map[string]interface{} var result []map[string]interface{}
@ -172,9 +175,10 @@ func (ombi *Ombi) GetUsers() ([]map[string]interface{}, int, error) {
if (code == 200 || code == 204) && err == nil { if (code == 200 || code == 204) && err == nil {
ombi.cacheExpiry = time.Now().Add(time.Minute * time.Duration(ombi.cacheLength)) ombi.cacheExpiry = time.Now().Add(time.Minute * time.Duration(ombi.cacheLength))
} }
return result, code, err err = co.GenericErr(code, err)
return result, err
} }
return ombi.userCache, 200, nil return ombi.userCache, nil
} }
// Strip these from a user when saving as a template. // Strip these from a user when saving as a template.
@ -190,9 +194,9 @@ var stripFromOmbi = []string{
} }
// TemplateByID returns a template based on the user corresponding to the provided ID's settings. // TemplateByID returns a template based on the user corresponding to the provided ID's settings.
func (ombi *Ombi) TemplateByID(id string) (result map[string]interface{}, code int, err error) { func (ombi *Ombi) TemplateByID(id string) (result map[string]interface{}, err error) {
result, code, err = ombi.UserByID(id) result, err = ombi.UserByID(id)
if err != nil || code != 200 { if err != nil {
return return
} }
for _, key := range stripFromOmbi { for _, key := range stripFromOmbi {
@ -209,24 +213,25 @@ func (ombi *Ombi) TemplateByID(id string) (result map[string]interface{}, code i
} }
// NewUser creates a new user with the given username, password and email address. // NewUser creates a new user with the given username, password and email address.
func (ombi *Ombi) NewUser(username, password, email string, template map[string]interface{}) ([]string, int, error) { func (ombi *Ombi) NewUser(username, password, email string, template map[string]interface{}) ([]string, error) {
url := fmt.Sprintf("%s/api/v1/Identity", ombi.server) url := fmt.Sprintf("%s/api/v1/Identity", ombi.server)
user := template user := template
user["userName"] = username user["userName"] = username
user["password"] = password user["password"] = password
user["emailAddress"] = email user["emailAddress"] = email
resp, code, err := ombi.post(url, user, true) resp, code, err := ombi.post(url, user, true)
err = co.GenericErr(code, err)
var data map[string]interface{} var data map[string]interface{}
json.Unmarshal([]byte(resp), &data) json.Unmarshal([]byte(resp), &data)
if err != nil || code != 200 { if err != nil {
var lst []string var lst []string
if data["errors"] != nil { if data["errors"] != nil {
lst = data["errors"].([]string) lst = data["errors"].([]string)
} }
return lst, code, err return lst, err
} }
ombi.cacheExpiry = time.Now() ombi.cacheExpiry = time.Now()
return nil, code, err return nil, err
} }
type NotificationPref struct { type NotificationPref struct {
@ -236,7 +241,7 @@ type NotificationPref struct {
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
} }
func (ombi *Ombi) SetNotificationPrefs(user map[string]interface{}, discordID, telegramUser string) (result string, code int, err error) { func (ombi *Ombi) SetNotificationPrefs(user map[string]interface{}, discordID, telegramUser string) (result string, err error) {
id := user["id"].(string) id := user["id"].(string)
url := fmt.Sprintf("%s/api/v1/Identity/NotificationPreferences", ombi.server) url := fmt.Sprintf("%s/api/v1/Identity/NotificationPreferences", ombi.server)
data := []NotificationPref{} data := []NotificationPref{}
@ -246,6 +251,8 @@ func (ombi *Ombi) SetNotificationPrefs(user map[string]interface{}, discordID, t
if telegramUser != "" { if telegramUser != "" {
data = append(data, NotificationPref{NotifAgentTelegram, id, telegramUser, true}) data = append(data, NotificationPref{NotifAgentTelegram, id, telegramUser, true})
} }
var code int
result, code, err = ombi.send("POST", url, data, true, map[string]string{"UserName": user["userName"].(string)}) result, code, err = ombi.send("POST", url, data, true, map[string]string{"UserName": user["userName"].(string)})
err = co.GenericErr(code, err)
return return
} }

@ -14,8 +14,8 @@ import (
// GenInternalReset generates a local password reset PIN, for use with the PWR option on the Admin page. // GenInternalReset generates a local password reset PIN, for use with the PWR option on the Admin page.
func (app *appContext) GenInternalReset(userID string) (InternalPWR, error) { func (app *appContext) GenInternalReset(userID string) (InternalPWR, error) {
pin := genAuthToken() pin := genAuthToken()
user, status, err := app.jf.UserByID(userID, false) user, err := app.jf.UserByID(userID, false)
if err != nil || status != 200 { if err != nil {
return InternalPWR{}, err return InternalPWR{}, err
} }
pwr := InternalPWR{ pwr := InternalPWR{
@ -95,8 +95,8 @@ func pwrMonitor(app *appContext, watcher *fsnotify.Watcher) {
} }
app.info.Printf("New password reset for user \"%s\"", pwr.Username) app.info.Printf("New password reset for user \"%s\"", pwr.Username)
if currentTime := time.Now(); pwr.Expiry.After(currentTime) { if currentTime := time.Now(); pwr.Expiry.After(currentTime) {
user, status, err := app.jf.UserByName(pwr.Username, false) user, err := app.jf.UserByName(pwr.Username, false)
if !(status == 200 || status == 204) || err != nil || user.ID == "" { if err != nil || user.ID == "" {
app.err.Printf(lm.FailedGetUser, pwr.Username, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUser, pwr.Username, lm.Jellyfin, err)
return return
} }

@ -91,19 +91,22 @@ func (app *appContext) TestJF(gc *gin.Context) {
tempjf.SetTransport(transport) tempjf.SetTransport(transport)
} }
user, status, err := tempjf.Authenticate(req.Username, req.Password) user, err := tempjf.Authenticate(req.Username, req.Password)
if !(status == 200 || status == 204) || err != nil { if err != nil {
msg := "" msg := ""
switch status { status := 500
case 0: switch err.(type) {
msg = "errorConnectionRefused" case mediabrowser.ErrUnauthorized:
status = 500
case 401:
msg = "errorInvalidUserPass" msg = "errorInvalidUserPass"
case 403: status = 401
case mediabrowser.ErrForbidden:
msg = "errorUserDisabled" msg = "errorUserDisabled"
case 404: status = 403
case mediabrowser.ErrNotFound:
msg = "error404" msg = "error404"
status = 404
default:
msg = "errorConnectionRefused"
} }
app.err.Printf(lm.FailedAuthJellyfin, req.Server, status, err) app.err.Printf(lm.FailedAuthJellyfin, req.Server, status, err)
if msg != "" { if msg != "" {

@ -24,8 +24,8 @@ func (app *appContext) checkUsers() {
} }
app.info.Println(lm.CheckUserExpiries) app.info.Println(lm.CheckUserExpiries)
users, status, err := app.jf.GetUsers(false) users, err := app.jf.GetUsers(false)
if err != nil || status != 200 { if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUsers, lm.Jellyfin, err)
return return
} }
@ -89,7 +89,7 @@ func (app *appContext) checkUsers() {
err, _, _ = app.SetUserDisabled(user, true) err, _, _ = app.SetUserDisabled(user, true)
activity.Type = ActivityDisabled activity.Type = ActivityDisabled
} }
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedDeleteOrDisableExpiredUser, user.ID, err) app.err.Printf(lm.FailedDeleteOrDisableExpiredUser, user.ID, err)
continue continue
} }

@ -1,7 +1,6 @@
package main package main
import ( import (
"fmt"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -68,7 +67,7 @@ func (app *appContext) NewUserPostVerification(p NewUserParams) (out NewUserData
} }
} }
existingUser, _, _ := app.jf.UserByName(p.Req.Username, false) existingUser, _ := app.jf.UserByName(p.Req.Username, false)
if existingUser.Name != "" { if existingUser.Name != "" {
out.Message = lm.UserExists out.Message = lm.UserExists
deferLogInfo(lm.FailedCreateUser, lm.Jellyfin, p.Req.Username, out.Message) deferLogInfo(lm.FailedCreateUser, lm.Jellyfin, p.Req.Username, out.Message)
@ -76,10 +75,9 @@ func (app *appContext) NewUserPostVerification(p NewUserParams) (out NewUserData
return return
} }
var status int
var err error var err error
out.User, status, err = app.jf.NewUser(p.Req.Username, p.Req.Password) out.User, err = app.jf.NewUser(p.Req.Username, p.Req.Password)
if !(status == 200 || status == 204) || err != nil { if err != nil {
out.Message = err.Error() out.Message = err.Error()
deferLogError(lm.FailedCreateUser, lm.Jellyfin, p.Req.Username, out.Message) deferLogError(lm.FailedCreateUser, lm.Jellyfin, p.Req.Username, out.Message)
out.Status = 401 out.Status = 401
@ -100,15 +98,15 @@ func (app *appContext) NewUserPostVerification(p NewUserParams) (out NewUserData
}, p.ContextForIPLogging, (p.SourceType != ActivityAdmin)) }, p.ContextForIPLogging, (p.SourceType != ActivityAdmin))
if p.Profile != nil { if p.Profile != nil {
status, err = app.jf.SetPolicy(out.User.ID, p.Profile.Policy) err = app.jf.SetPolicy(out.User.ID, p.Profile.Policy)
if !((status == 200 || status == 204) && err == nil) { if err != nil {
app.err.Printf(lm.FailedApplyTemplate, "policy", lm.Jellyfin, out.User.ID, err) app.err.Printf(lm.FailedApplyTemplate, "policy", lm.Jellyfin, out.User.ID, err)
} }
status, err = app.jf.SetConfiguration(out.User.ID, p.Profile.Configuration) err = app.jf.SetConfiguration(out.User.ID, p.Profile.Configuration)
if (status == 200 || status == 204) && err == nil { if err == nil {
status, err = app.jf.SetDisplayPreferences(out.User.ID, p.Profile.Displayprefs) err = app.jf.SetDisplayPreferences(out.User.ID, p.Profile.Displayprefs)
} }
if !((status == 200 || status == 204) && err == nil) { if err != nil {
app.err.Printf(lm.FailedApplyTemplate, "configuration", lm.Jellyfin, out.User.ID, err) app.err.Printf(lm.FailedApplyTemplate, "configuration", lm.Jellyfin, out.User.ID, err)
} }
@ -164,11 +162,7 @@ func (app *appContext) SetUserDisabled(user mediabrowser.User, disabled bool) (e
change = user.Policy.IsDisabled != disabled change = user.Policy.IsDisabled != disabled
user.Policy.IsDisabled = disabled user.Policy.IsDisabled = disabled
var status int err = app.jf.SetPolicy(user.ID, user.Policy)
status, err = app.jf.SetPolicy(user.ID, user.Policy)
if !(status == 200 || status == 204) && err == nil {
err = fmt.Errorf("failed (code %d)", status)
}
if err != nil { if err != nil {
return return
} }
@ -185,16 +179,12 @@ func (app *appContext) SetUserDisabled(user mediabrowser.User, disabled bool) (e
} }
func (app *appContext) DeleteUser(user mediabrowser.User) (err error, deleted bool) { func (app *appContext) DeleteUser(user mediabrowser.User) (err error, deleted bool) {
var status int
if app.ombi != nil { if app.ombi != nil {
var tpUser map[string]any var tpUser map[string]any
tpUser, status, err = app.getOmbiUser(user.ID) tpUser, err = app.getOmbiUser(user.ID)
if status == 200 && err == nil { if err == nil {
if id, ok := tpUser["id"]; ok { if id, ok := tpUser["id"]; ok {
status, err = app.ombi.DeleteUser(id.(string)) err = app.ombi.DeleteUser(id.(string))
if status != 200 && err == nil {
err = fmt.Errorf("failed (code %d)", status)
}
if err != nil { if err != nil {
app.err.Printf(lm.FailedDeleteUser, lm.Ombi, user.ID, err) app.err.Printf(lm.FailedDeleteUser, lm.Ombi, user.ID, err)
} }
@ -211,10 +201,7 @@ func (app *appContext) DeleteUser(user mediabrowser.User) (err error, deleted bo
} }
} }
status, err = app.jf.DeleteUser(user.ID) err = app.jf.DeleteUser(user.ID)
if status != 200 && status != 204 && err == nil {
err = fmt.Errorf("failed (code %d)", status)
}
if err != nil { if err != nil {
return return
} }

@ -333,26 +333,25 @@ func (app *appContext) ResetPassword(gc *gin.Context) {
// data["pin"] = pin // data["pin"] = pin
// } // }
var resp mediabrowser.PasswordResetResponse var resp mediabrowser.PasswordResetResponse
var status int
var err error var err error
var username string var username string
if !isInternal && !setPassword { if !isInternal && !setPassword {
resp, status, err = app.jf.ResetPassword(pin) resp, err = app.jf.ResetPassword(pin)
} else if time.Now().After(pwr.Expiry) { } else if time.Now().After(pwr.Expiry) {
app.debug.Printf(lm.FailedChangePassword, lm.Jellyfin, "?", fmt.Sprintf(lm.ExpiredPIN, pin)) app.debug.Printf(lm.FailedChangePassword, lm.Jellyfin, "?", fmt.Sprintf(lm.ExpiredPIN, pin))
app.NoRouteHandler(gc) app.NoRouteHandler(gc)
return return
} else { } else {
status, err = app.jf.ResetPasswordAdmin(pwr.ID) err = app.jf.ResetPasswordAdmin(pwr.ID)
if !(status == 200 || status == 204) || err != nil { if err != nil {
app.err.Printf(lm.FailedChangePassword, lm.Jellyfin, "?", err) app.err.Printf(lm.FailedChangePassword, lm.Jellyfin, "?", err)
} else { } else {
status, err = app.jf.SetPassword(pwr.ID, "", pin) err = app.jf.SetPassword(pwr.ID, "", pin)
} }
username = pwr.Username username = pwr.Username
} }
if (status == 200 || status == 204) && err == nil && (isInternal || resp.Success) { if err == nil && (isInternal || resp.Success) {
data["success"] = true data["success"] = true
data["pin"] = pin data["pin"] = pin
if !isInternal { if !isInternal {
@ -364,8 +363,8 @@ func (app *appContext) ResetPassword(gc *gin.Context) {
// Only log PWRs we know the user for. // Only log PWRs we know the user for.
if username != "" { if username != "" {
jfUser, status, err := app.jf.UserByName(username, false) jfUser, err := app.jf.UserByName(username, false)
if err == nil && status == 200 { if err == nil {
app.storage.SetActivityKey(shortuuid.New(), Activity{ app.storage.SetActivityKey(shortuuid.New(), Activity{
Type: ActivityResetPassword, Type: ActivityResetPassword,
UserID: jfUser.ID, UserID: jfUser.ID,
@ -377,19 +376,19 @@ func (app *appContext) ResetPassword(gc *gin.Context) {
} }
if app.config.Section("ombi").Key("enabled").MustBool(false) { if app.config.Section("ombi").Key("enabled").MustBool(false) {
jfUser, status, err := app.jf.UserByName(username, false) jfUser, err := app.jf.UserByName(username, false)
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUser, username, lm.Jellyfin, err) app.err.Printf(lm.FailedGetUser, username, lm.Jellyfin, err)
return return
} }
ombiUser, status, err := app.getOmbiUser(jfUser.ID) ombiUser, err := app.getOmbiUser(jfUser.ID)
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedGetUser, username, lm.Ombi, err) app.err.Printf(lm.FailedGetUser, username, lm.Ombi, err)
return return
} }
ombiUser["password"] = pin ombiUser["password"] = pin
status, err = app.ombi.ModifyUser(ombiUser) err = app.ombi.ModifyUser(ombiUser)
if status != 200 || err != nil { if err != nil {
app.err.Printf(lm.FailedChangePassword, lm.Ombi, ombiUser["userName"], err) app.err.Printf(lm.FailedChangePassword, lm.Ombi, ombiUser["userName"], err)
return return
} }
@ -749,8 +748,8 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
fromUser := "" fromUser := ""
if invite.ReferrerJellyfinID != "" { if invite.ReferrerJellyfinID != "" {
sender, status, err := app.jf.UserByID(invite.ReferrerJellyfinID, false) sender, err := app.jf.UserByID(invite.ReferrerJellyfinID, false)
if status == 200 && err == nil { if err == nil {
fromUser = sender.Name fromUser = sender.Name
} }
} }

Loading…
Cancel
Save