mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 09:00:10 +00:00
refactor; separate jfapi and ombi into modules
This commit is contained in:
parent
0f4e77364b
commit
c84ea17af4
233
api.go
233
api.go
@ -108,31 +108,33 @@ func (app *appContext) checkInvites() {
|
|||||||
changed := false
|
changed := false
|
||||||
for code, data := range app.storage.invites {
|
for code, data := range app.storage.invites {
|
||||||
expiry := data.ValidTill
|
expiry := data.ValidTill
|
||||||
if current_time.After(expiry) {
|
if !current_time.After(expiry) {
|
||||||
app.debug.Printf("Housekeeping: Deleting old invite %s", code)
|
continue
|
||||||
notify := data.Notify
|
|
||||||
if app.config.Section("notifications").Key("enabled").MustBool(false) && len(notify) != 0 {
|
|
||||||
app.debug.Printf("%s: Expiry notification", code)
|
|
||||||
for address, settings := range notify {
|
|
||||||
if settings["notify-expiry"] {
|
|
||||||
go func() {
|
|
||||||
msg, err := app.email.constructExpiry(code, data, app)
|
|
||||||
if err != nil {
|
|
||||||
app.err.Printf("%s: Failed to construct expiry notification", code)
|
|
||||||
app.debug.Printf("Error: %s", err)
|
|
||||||
} else if err := app.email.send(address, msg); err != nil {
|
|
||||||
app.err.Printf("%s: Failed to send expiry notification", code)
|
|
||||||
app.debug.Printf("Error: %s", err)
|
|
||||||
} else {
|
|
||||||
app.info.Printf("Sent expiry notification to %s", address)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
changed = true
|
|
||||||
delete(app.storage.invites, code)
|
|
||||||
}
|
}
|
||||||
|
app.debug.Printf("Housekeeping: Deleting old invite %s", code)
|
||||||
|
notify := data.Notify
|
||||||
|
if app.config.Section("notifications").Key("enabled").MustBool(false) && len(notify) != 0 {
|
||||||
|
app.debug.Printf("%s: Expiry notification", code)
|
||||||
|
for address, settings := range notify {
|
||||||
|
if !settings["notify-expiry"] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
msg, err := app.email.constructExpiry(code, data, app)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("%s: Failed to construct expiry notification", code)
|
||||||
|
app.debug.Printf("Error: %s", err)
|
||||||
|
} else if err := app.email.send(address, msg); err != nil {
|
||||||
|
app.err.Printf("%s: Failed to send expiry notification", code)
|
||||||
|
app.debug.Printf("Error: %s", err)
|
||||||
|
} else {
|
||||||
|
app.info.Printf("Sent expiry notification to %s", address)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changed = true
|
||||||
|
delete(app.storage.invites, code)
|
||||||
}
|
}
|
||||||
if changed {
|
if changed {
|
||||||
app.storage.storeInvites()
|
app.storage.storeInvites()
|
||||||
@ -143,63 +145,64 @@ func (app *appContext) checkInvite(code string, used bool, username string) bool
|
|||||||
current_time := time.Now()
|
current_time := time.Now()
|
||||||
app.storage.loadInvites()
|
app.storage.loadInvites()
|
||||||
changed := false
|
changed := false
|
||||||
if inv, match := app.storage.invites[code]; match {
|
inv, match := app.storage.invites[code]
|
||||||
expiry := inv.ValidTill
|
if !match {
|
||||||
if current_time.After(expiry) {
|
return false
|
||||||
app.debug.Printf("Housekeeping: Deleting old invite %s", code)
|
}
|
||||||
notify := inv.Notify
|
expiry := inv.ValidTill
|
||||||
if app.config.Section("notifications").Key("enabled").MustBool(false) && len(notify) != 0 {
|
if current_time.After(expiry) {
|
||||||
app.debug.Printf("%s: Expiry notification", code)
|
app.debug.Printf("Housekeeping: Deleting old invite %s", code)
|
||||||
for address, settings := range notify {
|
notify := inv.Notify
|
||||||
if settings["notify-expiry"] {
|
if app.config.Section("notifications").Key("enabled").MustBool(false) && len(notify) != 0 {
|
||||||
go func() {
|
app.debug.Printf("%s: Expiry notification", code)
|
||||||
msg, err := app.email.constructExpiry(code, inv, app)
|
for address, settings := range notify {
|
||||||
if err != nil {
|
if settings["notify-expiry"] {
|
||||||
app.err.Printf("%s: Failed to construct expiry notification", code)
|
go func() {
|
||||||
app.debug.Printf("Error: %s", err)
|
msg, err := app.email.constructExpiry(code, inv, app)
|
||||||
} else if err := app.email.send(address, msg); err != nil {
|
if err != nil {
|
||||||
app.err.Printf("%s: Failed to send expiry notification", code)
|
app.err.Printf("%s: Failed to construct expiry notification", code)
|
||||||
app.debug.Printf("Error: %s", err)
|
app.debug.Printf("Error: %s", err)
|
||||||
} else {
|
} else if err := app.email.send(address, msg); err != nil {
|
||||||
app.info.Printf("Sent expiry notification to %s", address)
|
app.err.Printf("%s: Failed to send expiry notification", code)
|
||||||
}
|
app.debug.Printf("Error: %s", err)
|
||||||
}()
|
} else {
|
||||||
}
|
app.info.Printf("Sent expiry notification to %s", address)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
changed = true
|
}
|
||||||
match = false
|
changed = true
|
||||||
|
match = false
|
||||||
|
delete(app.storage.invites, code)
|
||||||
|
} else if used {
|
||||||
|
changed = true
|
||||||
|
del := false
|
||||||
|
newInv := inv
|
||||||
|
if newInv.RemainingUses == 1 {
|
||||||
|
del = true
|
||||||
delete(app.storage.invites, code)
|
delete(app.storage.invites, code)
|
||||||
} else if used {
|
} else if newInv.RemainingUses != 0 {
|
||||||
changed = true
|
// 0 means infinite i guess?
|
||||||
del := false
|
newInv.RemainingUses -= 1
|
||||||
newInv := inv
|
|
||||||
if newInv.RemainingUses == 1 {
|
|
||||||
del = true
|
|
||||||
delete(app.storage.invites, code)
|
|
||||||
} else if newInv.RemainingUses != 0 {
|
|
||||||
// 0 means infinite i guess?
|
|
||||||
newInv.RemainingUses -= 1
|
|
||||||
}
|
|
||||||
newInv.UsedBy = append(newInv.UsedBy, []string{username, app.formatDatetime(current_time)})
|
|
||||||
if !del {
|
|
||||||
app.storage.invites[code] = newInv
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if changed {
|
newInv.UsedBy = append(newInv.UsedBy, []string{username, app.formatDatetime(current_time)})
|
||||||
app.storage.storeInvites()
|
if !del {
|
||||||
|
app.storage.invites[code] = newInv
|
||||||
}
|
}
|
||||||
return match
|
|
||||||
}
|
}
|
||||||
return false
|
if changed {
|
||||||
|
app.storage.storeInvites()
|
||||||
|
}
|
||||||
|
return match
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, int, error) {
|
func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, int, error) {
|
||||||
ombiUsers, code, err := app.ombi.getUsers()
|
ombiUsers, code, err := app.ombi.GetUsers()
|
||||||
if err != nil || code != 200 {
|
if err != nil || code != 200 {
|
||||||
return nil, code, err
|
return nil, code, err
|
||||||
}
|
}
|
||||||
jfUser, code, err := app.jf.userById(jfID, false)
|
jfUser, code, err := app.jf.UserByID(jfID, false)
|
||||||
if err != nil || code != 200 {
|
if err != nil || code != 200 {
|
||||||
return nil, code, err
|
return nil, code, err
|
||||||
}
|
}
|
||||||
@ -229,14 +232,14 @@ func (app *appContext) getOmbiUser(jfID string) (map[string]interface{}, int, er
|
|||||||
func (app *appContext) NewUserAdmin(gc *gin.Context) {
|
func (app *appContext) NewUserAdmin(gc *gin.Context) {
|
||||||
var req newUserDTO
|
var req newUserDTO
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
existingUser, _, _ := app.jf.userByName(req.Username, false)
|
existingUser, _, _ := app.jf.UserByName(req.Username, false)
|
||||||
if existingUser != nil {
|
if existingUser != nil {
|
||||||
msg := fmt.Sprintf("User already exists named %s", req.Username)
|
msg := fmt.Sprintf("User already exists named %s", req.Username)
|
||||||
app.info.Printf("%s New user failed: %s", req.Username, msg)
|
app.info.Printf("%s New user failed: %s", req.Username, msg)
|
||||||
respond(401, msg, gc)
|
respond(401, msg, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user, status, err := app.jf.newUser(req.Username, req.Password)
|
user, status, err := app.jf.NewUser(req.Username, req.Password)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
app.err.Printf("%s New user failed: Jellyfin responded with %d", req.Username, status)
|
app.err.Printf("%s New user failed: Jellyfin responded with %d", req.Username, status)
|
||||||
respond(401, "Unknown error", gc)
|
respond(401, "Unknown error", gc)
|
||||||
@ -247,15 +250,15 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
|
|||||||
id = user["Id"].(string)
|
id = user["Id"].(string)
|
||||||
}
|
}
|
||||||
if len(app.storage.policy) != 0 {
|
if len(app.storage.policy) != 0 {
|
||||||
status, err = app.jf.setPolicy(id, app.storage.policy)
|
status, err = app.jf.SetPolicy(id, app.storage.policy)
|
||||||
if !(status == 200 || status == 204) {
|
if !(status == 200 || status == 204) {
|
||||||
app.err.Printf("%s: Failed to set user policy: Code %d", req.Username, status)
|
app.err.Printf("%s: Failed to set user policy: Code %d", req.Username, status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(app.storage.configuration) != 0 && len(app.storage.displayprefs) != 0 {
|
if len(app.storage.configuration) != 0 && len(app.storage.displayprefs) != 0 {
|
||||||
status, err = app.jf.setConfiguration(id, app.storage.configuration)
|
status, err = app.jf.SetConfiguration(id, app.storage.configuration)
|
||||||
if (status == 200 || status == 204) && err == nil {
|
if (status == 200 || status == 204) && err == nil {
|
||||||
status, err = app.jf.setDisplayPreferences(id, app.storage.displayprefs)
|
status, err = app.jf.SetDisplayPreferences(id, app.storage.displayprefs)
|
||||||
} else {
|
} else {
|
||||||
app.err.Printf("%s: Failed to set configuration template: Code %d", req.Username, status)
|
app.err.Printf("%s: Failed to set configuration template: Code %d", req.Username, status)
|
||||||
}
|
}
|
||||||
@ -267,7 +270,7 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
|
|||||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
app.storage.loadOmbiTemplate()
|
app.storage.loadOmbiTemplate()
|
||||||
if len(app.storage.ombi_template) != 0 {
|
if len(app.storage.ombi_template) != 0 {
|
||||||
errors, code, err := app.ombi.newUser(req.Username, req.Password, req.Email, app.storage.ombi_template)
|
errors, code, err := app.ombi.NewUser(req.Username, req.Password, req.Email, app.storage.ombi_template)
|
||||||
if err != nil || code != 200 {
|
if err != nil || code != 200 {
|
||||||
app.info.Printf("Failed to create Ombi user (%d): %s", code, err)
|
app.info.Printf("Failed to create Ombi user (%d): %s", code, err)
|
||||||
app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", "))
|
app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", "))
|
||||||
@ -276,7 +279,7 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.jf.cacheExpiry = time.Now()
|
app.jf.CacheExpiry = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Creates a new Jellyfin user via invite code
|
// @Summary Creates a new Jellyfin user via invite code
|
||||||
@ -309,14 +312,14 @@ func (app *appContext) NewUser(gc *gin.Context) {
|
|||||||
gc.Abort()
|
gc.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
existingUser, _, _ := app.jf.userByName(req.Username, false)
|
existingUser, _, _ := app.jf.UserByName(req.Username, false)
|
||||||
if existingUser != nil {
|
if existingUser != nil {
|
||||||
msg := fmt.Sprintf("User already exists named %s", req.Username)
|
msg := fmt.Sprintf("User already exists named %s", req.Username)
|
||||||
app.info.Printf("%s New user failed: %s", req.Code, msg)
|
app.info.Printf("%s New user failed: %s", req.Code, msg)
|
||||||
respond(401, msg, gc)
|
respond(401, msg, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user, status, err := app.jf.newUser(req.Username, req.Password)
|
user, status, err := app.jf.NewUser(req.Username, req.Password)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
app.err.Printf("%s New user failed: Jellyfin responded with %d", req.Code, status)
|
app.err.Printf("%s New user failed: Jellyfin responded with %d", req.Code, status)
|
||||||
respond(401, "Unknown error", gc)
|
respond(401, "Unknown error", gc)
|
||||||
@ -355,16 +358,16 @@ func (app *appContext) NewUser(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
if len(profile.Policy) != 0 {
|
if len(profile.Policy) != 0 {
|
||||||
app.debug.Printf("Applying policy from profile \"%s\"", invite.Profile)
|
app.debug.Printf("Applying policy from profile \"%s\"", invite.Profile)
|
||||||
status, err = app.jf.setPolicy(id, profile.Policy)
|
status, err = app.jf.SetPolicy(id, profile.Policy)
|
||||||
if !(status == 200 || status == 204) {
|
if !(status == 200 || status == 204) {
|
||||||
app.err.Printf("%s: Failed to set user policy: Code %d", req.Code, status)
|
app.err.Printf("%s: Failed to set user policy: Code %d", req.Code, status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(profile.Configuration) != 0 && len(profile.Displayprefs) != 0 {
|
if len(profile.Configuration) != 0 && len(profile.Displayprefs) != 0 {
|
||||||
app.debug.Printf("Applying homescreen from profile \"%s\"", invite.Profile)
|
app.debug.Printf("Applying homescreen from profile \"%s\"", invite.Profile)
|
||||||
status, err = app.jf.setConfiguration(id, profile.Configuration)
|
status, err = app.jf.SetConfiguration(id, profile.Configuration)
|
||||||
if (status == 200 || status == 204) && err == nil {
|
if (status == 200 || status == 204) && err == nil {
|
||||||
status, err = app.jf.setDisplayPreferences(id, profile.Displayprefs)
|
status, err = app.jf.SetDisplayPreferences(id, profile.Displayprefs)
|
||||||
} else {
|
} else {
|
||||||
app.err.Printf("%s: Failed to set configuration template: Code %d", req.Code, status)
|
app.err.Printf("%s: Failed to set configuration template: Code %d", req.Code, status)
|
||||||
}
|
}
|
||||||
@ -377,7 +380,7 @@ func (app *appContext) NewUser(gc *gin.Context) {
|
|||||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
app.storage.loadOmbiTemplate()
|
app.storage.loadOmbiTemplate()
|
||||||
if len(app.storage.ombi_template) != 0 {
|
if len(app.storage.ombi_template) != 0 {
|
||||||
errors, code, err := app.ombi.newUser(req.Username, req.Password, req.Email, app.storage.ombi_template)
|
errors, code, err := app.ombi.NewUser(req.Username, req.Password, req.Email, app.storage.ombi_template)
|
||||||
if err != nil || code != 200 {
|
if err != nil || code != 200 {
|
||||||
app.info.Printf("Failed to create Ombi user (%d): %s", code, err)
|
app.info.Printf("Failed to create Ombi user (%d): %s", code, err)
|
||||||
app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", "))
|
app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", "))
|
||||||
@ -414,7 +417,7 @@ func (app *appContext) DeleteUser(gc *gin.Context) {
|
|||||||
ombiUser, code, err := app.getOmbiUser(userID)
|
ombiUser, code, err := app.getOmbiUser(userID)
|
||||||
if code == 200 && err == nil {
|
if code == 200 && err == nil {
|
||||||
if id, ok := ombiUser["id"]; ok {
|
if id, ok := ombiUser["id"]; ok {
|
||||||
status, err := app.ombi.deleteUser(id.(string))
|
status, err := app.ombi.DeleteUser(id.(string))
|
||||||
if err != nil || status != 200 {
|
if err != nil || status != 200 {
|
||||||
app.err.Printf("Failed to delete ombi user: %d %s", status, err)
|
app.err.Printf("Failed to delete ombi user: %d %s", status, err)
|
||||||
errors[userID] = fmt.Sprintf("Ombi: %d %s, ", status, err)
|
errors[userID] = fmt.Sprintf("Ombi: %d %s, ", status, err)
|
||||||
@ -422,7 +425,7 @@ func (app *appContext) DeleteUser(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status, err := app.jf.deleteUser(userID)
|
status, err := app.jf.DeleteUser(userID)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
msg := fmt.Sprintf("%d: %s", status, err)
|
msg := fmt.Sprintf("%d: %s", status, err)
|
||||||
if _, ok := errors[userID]; !ok {
|
if _, ok := errors[userID]; !ok {
|
||||||
@ -449,7 +452,7 @@ func (app *appContext) DeleteUser(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.jf.cacheExpiry = time.Now()
|
app.jf.CacheExpiry = time.Now()
|
||||||
if len(errors) == len(req.Users) {
|
if len(errors) == len(req.Users) {
|
||||||
respondBool(500, false, gc)
|
respondBool(500, false, gc)
|
||||||
app.err.Printf("Account deletion failed: %s", errors[req.Users[0]])
|
app.err.Printf("Account deletion failed: %s", errors[req.Users[0]])
|
||||||
@ -612,7 +615,7 @@ func (app *appContext) CreateProfile(gc *gin.Context) {
|
|||||||
app.info.Println("Profile creation requested")
|
app.info.Println("Profile creation requested")
|
||||||
var req newProfileDTO
|
var req newProfileDTO
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
user, status, err := app.jf.userById(req.ID, false)
|
user, status, err := app.jf.UserByID(req.ID, false)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
app.err.Printf("Failed to get user from Jellyfin: Code %d", status)
|
app.err.Printf("Failed to get user from Jellyfin: Code %d", status)
|
||||||
app.debug.Printf("Error: %s", err)
|
app.debug.Printf("Error: %s", err)
|
||||||
@ -626,7 +629,7 @@ func (app *appContext) CreateProfile(gc *gin.Context) {
|
|||||||
app.debug.Printf("Creating profile from user \"%s\"", user["Name"].(string))
|
app.debug.Printf("Creating profile from user \"%s\"", user["Name"].(string))
|
||||||
if req.Homescreen {
|
if req.Homescreen {
|
||||||
profile.Configuration = user["Configuration"].(map[string]interface{})
|
profile.Configuration = user["Configuration"].(map[string]interface{})
|
||||||
profile.Displayprefs, status, err = app.jf.getDisplayPreferences(req.ID)
|
profile.Displayprefs, status, err = app.jf.GetDisplayPreferences(req.ID)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
app.err.Printf("Failed to get DisplayPrefs: Code %d", status)
|
app.err.Printf("Failed to get DisplayPrefs: Code %d", status)
|
||||||
app.debug.Printf("Error: %s", err)
|
app.debug.Printf("Error: %s", err)
|
||||||
@ -844,7 +847,7 @@ func (app *appContext) GetUsers(gc *gin.Context) {
|
|||||||
app.debug.Println("Users requested")
|
app.debug.Println("Users requested")
|
||||||
var resp getUsersDTO
|
var resp getUsersDTO
|
||||||
resp.UserList = []respUser{}
|
resp.UserList = []respUser{}
|
||||||
users, status, err := app.jf.getUsers(false)
|
users, status, err := app.jf.GetUsers(false)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
app.err.Printf("Failed to get users from Jellyfin: Code %d", status)
|
app.err.Printf("Failed to get users from Jellyfin: Code %d", status)
|
||||||
app.debug.Printf("Error: %s", err)
|
app.debug.Printf("Error: %s", err)
|
||||||
@ -879,7 +882,7 @@ func (app *appContext) GetUsers(gc *gin.Context) {
|
|||||||
// @tags Ombi
|
// @tags Ombi
|
||||||
func (app *appContext) OmbiUsers(gc *gin.Context) {
|
func (app *appContext) OmbiUsers(gc *gin.Context) {
|
||||||
app.debug.Println("Ombi users requested")
|
app.debug.Println("Ombi users requested")
|
||||||
users, status, err := app.ombi.getUsers()
|
users, status, err := app.ombi.GetUsers()
|
||||||
if err != nil || status != 200 {
|
if err != nil || status != 200 {
|
||||||
app.err.Printf("Failed to get users from Ombi: Code %d", status)
|
app.err.Printf("Failed to get users from Ombi: Code %d", status)
|
||||||
app.debug.Printf("Error: %s", err)
|
app.debug.Printf("Error: %s", err)
|
||||||
@ -907,7 +910,7 @@ func (app *appContext) OmbiUsers(gc *gin.Context) {
|
|||||||
func (app *appContext) SetOmbiDefaults(gc *gin.Context) {
|
func (app *appContext) SetOmbiDefaults(gc *gin.Context) {
|
||||||
var req ombiUser
|
var req ombiUser
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
template, code, err := app.ombi.templateByID(req.ID)
|
template, code, err := app.ombi.TemplateByID(req.ID)
|
||||||
if err != nil || code != 200 || len(template) == 0 {
|
if err != nil || code != 200 || len(template) == 0 {
|
||||||
app.err.Printf("Couldn't get user from Ombi: %d %s", code, err)
|
app.err.Printf("Couldn't get user from Ombi: %d %s", code, err)
|
||||||
respond(500, "Couldn't get user", gc)
|
respond(500, "Couldn't get user", gc)
|
||||||
@ -930,7 +933,7 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
|
|||||||
var req modifyEmailsDTO
|
var req modifyEmailsDTO
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
app.debug.Println("Email modification requested")
|
app.debug.Println("Email modification requested")
|
||||||
users, status, err := app.jf.getUsers(false)
|
users, status, err := app.jf.GetUsers(false)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
app.err.Printf("Failed to get users from Jellyfin: Code %d", status)
|
app.err.Printf("Failed to get users from Jellyfin: Code %d", status)
|
||||||
app.debug.Printf("Error: %s", err)
|
app.debug.Printf("Error: %s", err)
|
||||||
@ -946,7 +949,7 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
|
|||||||
ombiUser, code, err := app.getOmbiUser(id)
|
ombiUser, code, err := app.getOmbiUser(id)
|
||||||
if code == 200 && err == nil {
|
if code == 200 && err == nil {
|
||||||
ombiUser["emailAddress"] = address
|
ombiUser["emailAddress"] = address
|
||||||
code, err = app.ombi.modifyUser(ombiUser)
|
code, err = app.ombi.ModifyUser(ombiUser)
|
||||||
if code != 200 || err != nil {
|
if code != 200 || err != nil {
|
||||||
app.err.Printf("%s: Failed to change ombi email address: %d %s", ombiUser["userName"].(string), code, err)
|
app.err.Printf("%s: Failed to change ombi email address: %d %s", ombiUser["userName"].(string), code, err)
|
||||||
}
|
}
|
||||||
@ -959,42 +962,6 @@ func (app *appContext) ModifyEmails(gc *gin.Context) {
|
|||||||
respondBool(200, true, gc)
|
respondBool(200, true, gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*func (app *appContext) SetDefaults(gc *gin.Context) {
|
|
||||||
var req defaultsReq
|
|
||||||
gc.BindJSON(&req)
|
|
||||||
userID := req.ID
|
|
||||||
user, status, err := app.jf.userById(userID, false)
|
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
|
||||||
app.err.Printf("Failed to get user from Jellyfin: Code %d", status)
|
|
||||||
app.debug.Printf("Error: %s", err)
|
|
||||||
respond(500, "Couldn't get user", gc)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
app.info.Printf("Getting user defaults from \"%s\"", user["Name"].(string))
|
|
||||||
policy := user["Policy"].(map[string]interface{})
|
|
||||||
app.storage.policy = policy
|
|
||||||
app.storage.storePolicy()
|
|
||||||
app.debug.Println("User policy template stored")
|
|
||||||
if req.Homescreen {
|
|
||||||
configuration := user["Configuration"].(map[string]interface{})
|
|
||||||
var displayprefs map[string]interface{}
|
|
||||||
displayprefs, status, err = app.jf.getDisplayPreferences(userID)
|
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
|
||||||
app.err.Printf("Failed to get DisplayPrefs: Code %d", status)
|
|
||||||
app.debug.Printf("Error: %s", err)
|
|
||||||
respond(500, "Couldn't get displayprefs", gc)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
app.storage.configuration = configuration
|
|
||||||
app.storage.displayprefs = displayprefs
|
|
||||||
app.storage.storeConfiguration()
|
|
||||||
app.debug.Println("Configuration template stored")
|
|
||||||
app.storage.storeDisplayprefs()
|
|
||||||
app.debug.Println("DisplayPrefs template stored")
|
|
||||||
}
|
|
||||||
gc.JSON(200, map[string]bool{"success": true})
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// @Summary Apply settings to a list of users, either from a profile or from another user.
|
// @Summary Apply settings to a list of users, either from a profile or from another user.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param userSettingsDTO body userSettingsDTO true "Parameters for applying settings"
|
// @Param userSettingsDTO body userSettingsDTO true "Parameters for applying settings"
|
||||||
@ -1028,7 +995,7 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
policy = app.storage.profiles[req.Profile].Policy
|
policy = app.storage.profiles[req.Profile].Policy
|
||||||
} else if req.From == "user" {
|
} else if req.From == "user" {
|
||||||
applyingFrom = "user"
|
applyingFrom = "user"
|
||||||
user, status, err := app.jf.userById(req.ID, false)
|
user, status, err := app.jf.UserByID(req.ID, false)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
app.err.Printf("Failed to get user from Jellyfin: Code %d", status)
|
app.err.Printf("Failed to get user from Jellyfin: Code %d", status)
|
||||||
app.debug.Printf("Error: %s", err)
|
app.debug.Printf("Error: %s", err)
|
||||||
@ -1038,7 +1005,7 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
applyingFrom = "\"" + user["Name"].(string) + "\""
|
applyingFrom = "\"" + user["Name"].(string) + "\""
|
||||||
policy = user["Policy"].(map[string]interface{})
|
policy = user["Policy"].(map[string]interface{})
|
||||||
if req.Homescreen {
|
if req.Homescreen {
|
||||||
displayprefs, status, err = app.jf.getDisplayPreferences(req.ID)
|
displayprefs, status, err = app.jf.GetDisplayPreferences(req.ID)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
app.err.Printf("Failed to get DisplayPrefs: Code %d", status)
|
app.err.Printf("Failed to get DisplayPrefs: Code %d", status)
|
||||||
app.debug.Printf("Error: %s", err)
|
app.debug.Printf("Error: %s", err)
|
||||||
@ -1054,17 +1021,17 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
|||||||
"homescreen": map[string]string{},
|
"homescreen": map[string]string{},
|
||||||
}
|
}
|
||||||
for _, id := range req.ApplyTo {
|
for _, id := range req.ApplyTo {
|
||||||
status, err := app.jf.setPolicy(id, policy)
|
status, err := app.jf.SetPolicy(id, policy)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
errors["policy"][id] = fmt.Sprintf("%d: %s", status, err)
|
errors["policy"][id] = fmt.Sprintf("%d: %s", status, err)
|
||||||
}
|
}
|
||||||
if req.Homescreen {
|
if req.Homescreen {
|
||||||
status, err = app.jf.setConfiguration(id, configuration)
|
status, err = app.jf.SetConfiguration(id, configuration)
|
||||||
errorString := ""
|
errorString := ""
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
errorString += fmt.Sprintf("Configuration %d: %s ", status, err)
|
errorString += fmt.Sprintf("Configuration %d: %s ", status, err)
|
||||||
} else {
|
} else {
|
||||||
status, err = app.jf.setDisplayPreferences(id, displayprefs)
|
status, err = app.jf.SetDisplayPreferences(id, displayprefs)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
errorString += fmt.Sprintf("Displayprefs %d: %s ", status, err)
|
errorString += fmt.Sprintf("Displayprefs %d: %s ", status, err)
|
||||||
}
|
}
|
||||||
|
2
auth.go
2
auth.go
@ -146,7 +146,7 @@ func (app *appContext) getToken(gc *gin.Context) {
|
|||||||
var status int
|
var status int
|
||||||
var err error
|
var err error
|
||||||
var user map[string]interface{}
|
var user map[string]interface{}
|
||||||
user, status, err = app.authJf.authenticate(creds[0], creds[1])
|
user, status, err = app.authJf.Authenticate(creds[0], creds[1])
|
||||||
if status != 200 || err != nil {
|
if status != 200 || err != nil {
|
||||||
if status == 401 || status == 400 {
|
if status == 401 || status == 400 {
|
||||||
app.info.Println("Auth denied: Invalid username/password (Jellyfin)")
|
app.info.Println("Auth denied: Invalid username/password (Jellyfin)")
|
||||||
|
21
common/common.go
Normal file
21
common/common.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TimeoutHandler recovers from an http timeout.
|
||||||
|
type TimeoutHandler func()
|
||||||
|
|
||||||
|
// NewTimeoutHandler returns a new Timeout handler.
|
||||||
|
func NewTimeoutHandler(name, addr string, noFail bool) TimeoutHandler {
|
||||||
|
return func() {
|
||||||
|
out := fmt.Sprintf("Failed to authenticate with %s @ %s: Timed out", name, addr)
|
||||||
|
if noFail {
|
||||||
|
log.Print(out)
|
||||||
|
} else {
|
||||||
|
log.Fatalf(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
common/go.mod
Normal file
3
common/go.mod
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module github.com/hrfee/jfa-go/common
|
||||||
|
|
||||||
|
go 1.15
|
9
go.mod
9
go.mod
@ -4,6 +4,12 @@ go 1.14
|
|||||||
|
|
||||||
replace github.com/hrfee/jfa-go/docs => ./docs
|
replace github.com/hrfee/jfa-go/docs => ./docs
|
||||||
|
|
||||||
|
replace github.com/hrfee/jfa-go/jfapi => ./jfapi
|
||||||
|
|
||||||
|
replace github.com/hrfee/jfa-go/common => ./common
|
||||||
|
|
||||||
|
replace github.com/hrfee/jfa-go/ombi => ./ombi
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
@ -17,7 +23,10 @@ require (
|
|||||||
github.com/go-playground/validator/v10 v10.4.0 // indirect
|
github.com/go-playground/validator/v10 v10.4.0 // indirect
|
||||||
github.com/golang/protobuf v1.4.2
|
github.com/golang/protobuf v1.4.2
|
||||||
github.com/google/uuid v1.1.2 // indirect
|
github.com/google/uuid v1.1.2 // indirect
|
||||||
|
github.com/hrfee/jfa-go/common v0.0.0-00010101000000-000000000000
|
||||||
github.com/hrfee/jfa-go/docs v0.0.0-20200927200337-7628e5d71da8
|
github.com/hrfee/jfa-go/docs v0.0.0-20200927200337-7628e5d71da8
|
||||||
|
github.com/hrfee/jfa-go/jfapi v0.0.0-00010101000000-000000000000
|
||||||
|
github.com/hrfee/jfa-go/ombi v0.0.0-00010101000000-000000000000
|
||||||
github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible
|
github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible
|
||||||
github.com/json-iterator/go v1.1.10 // indirect
|
github.com/json-iterator/go v1.1.10 // indirect
|
||||||
github.com/knz/strtime v0.0.0-20200924090105-187c67f2bf5e
|
github.com/knz/strtime v0.0.0-20200924090105-187c67f2bf5e
|
||||||
|
7
jfapi/go.mod
Normal file
7
jfapi/go.mod
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
module github.com/hrfee/jfa-go/jfapi
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
replace github.com/hrfee/jfa-go/common => ../common
|
||||||
|
|
||||||
|
require github.com/hrfee/jfa-go/common v0.0.0-00010101000000-000000000000
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package jfapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -7,63 +7,57 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hrfee/jfa-go/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerInfo struct {
|
type serverInfo struct {
|
||||||
LocalAddress string `json:"LocalAddress"`
|
LocalAddress string `json:"LocalAddress"`
|
||||||
Name string `json:"ServerName"`
|
Name string `json:"ServerName"`
|
||||||
Version string `json:"Version"`
|
Version string `json:"Version"`
|
||||||
Os string `json:"OperatingSystem"`
|
OS string `json:"OperatingSystem"`
|
||||||
Id string `json:"Id"`
|
ID string `json:"Id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Jellyfin represents a running Jellyfin instance.
|
||||||
type Jellyfin struct {
|
type Jellyfin struct {
|
||||||
server string
|
Server string
|
||||||
client string
|
client string
|
||||||
version string
|
version string
|
||||||
device string
|
device string
|
||||||
deviceId string
|
deviceID string
|
||||||
useragent string
|
useragent string
|
||||||
auth string
|
auth string
|
||||||
header map[string]string
|
header map[string]string
|
||||||
serverInfo ServerInfo
|
ServerInfo serverInfo
|
||||||
username string
|
Username string
|
||||||
password string
|
password string
|
||||||
authenticated bool
|
Authenticated bool
|
||||||
accessToken string
|
AccessToken string
|
||||||
userId string
|
userID string
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
loginParams map[string]string
|
loginParams map[string]string
|
||||||
userCache []map[string]interface{}
|
userCache []map[string]interface{}
|
||||||
cacheExpiry time.Time
|
CacheExpiry time.Time
|
||||||
cacheLength int
|
cacheLength int
|
||||||
noFail bool
|
noFail bool
|
||||||
|
timeoutHandler common.TimeoutHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func timeoutHandler(name, addr string, noFail bool) {
|
// NewJellyfin returns a new Jellyfin object.
|
||||||
if r := recover(); r != nil {
|
func NewJellyfin(server, client, version, device, deviceID string, timeoutHandler common.TimeoutHandler) (*Jellyfin, error) {
|
||||||
out := fmt.Sprintf("Failed to authenticate with %s @ %s: Timed out", name, addr)
|
|
||||||
if noFail {
|
|
||||||
log.Printf(out)
|
|
||||||
} else {
|
|
||||||
log.Fatalf(out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newJellyfin(server, client, version, device, deviceId string) (*Jellyfin, error) {
|
|
||||||
jf := &Jellyfin{}
|
jf := &Jellyfin{}
|
||||||
jf.server = server
|
jf.Server = server
|
||||||
jf.client = client
|
jf.client = client
|
||||||
jf.version = version
|
jf.version = version
|
||||||
jf.device = device
|
jf.device = device
|
||||||
jf.deviceId = deviceId
|
jf.deviceID = deviceID
|
||||||
jf.useragent = fmt.Sprintf("%s/%s", client, version)
|
jf.useragent = fmt.Sprintf("%s/%s", client, version)
|
||||||
jf.auth = fmt.Sprintf("MediaBrowser Client=%s, Device=%s, DeviceId=%s, Version=%s", client, device, deviceId, version)
|
jf.timeoutHandler = timeoutHandler
|
||||||
|
jf.auth = fmt.Sprintf("MediaBrowser Client=%s, Device=%s, DeviceId=%s, Version=%s", client, device, deviceID, version)
|
||||||
jf.header = map[string]string{
|
jf.header = map[string]string{
|
||||||
"Accept": "application/json",
|
"Accept": "application/json",
|
||||||
"Content-type": "application/json; charset=UTF-8",
|
"Content-type": "application/json; charset=UTF-8",
|
||||||
@ -76,21 +70,22 @@ func newJellyfin(server, client, version, device, deviceId string) (*Jellyfin, e
|
|||||||
jf.httpClient = &http.Client{
|
jf.httpClient = &http.Client{
|
||||||
Timeout: 10 * time.Second,
|
Timeout: 10 * time.Second,
|
||||||
}
|
}
|
||||||
infoUrl := fmt.Sprintf("%s/System/Info/Public", server)
|
infoURL := fmt.Sprintf("%s/System/Info/Public", server)
|
||||||
req, _ := http.NewRequest("GET", infoUrl, nil)
|
req, _ := http.NewRequest("GET", infoURL, nil)
|
||||||
resp, err := jf.httpClient.Do(req)
|
resp, err := jf.httpClient.Do(req)
|
||||||
defer timeoutHandler("Jellyfin", jf.server, jf.noFail)
|
defer jf.timeoutHandler()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
data, _ := ioutil.ReadAll(resp.Body)
|
data, _ := ioutil.ReadAll(resp.Body)
|
||||||
json.Unmarshal(data, &jf.serverInfo)
|
json.Unmarshal(data, &jf.ServerInfo)
|
||||||
}
|
}
|
||||||
jf.cacheLength = 30
|
jf.cacheLength = 30
|
||||||
jf.cacheExpiry = time.Now()
|
jf.CacheExpiry = time.Now()
|
||||||
return jf, nil
|
return jf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) authenticate(username, password string) (map[string]interface{}, int, error) {
|
// Authenticate attempts to authenticate using a username & password
|
||||||
jf.username = username
|
func (jf *Jellyfin) Authenticate(username, password string) (map[string]interface{}, int, error) {
|
||||||
|
jf.Username = username
|
||||||
jf.password = password
|
jf.password = password
|
||||||
jf.loginParams = map[string]string{
|
jf.loginParams = map[string]string{
|
||||||
"Username": username,
|
"Username": username,
|
||||||
@ -105,9 +100,9 @@ func (jf *Jellyfin) authenticate(username, password string) (map[string]interfac
|
|||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
// loginParams, _ := json.Marshal(jf.loginParams)
|
// loginParams, _ := json.Marshal(jf.loginParams)
|
||||||
url := fmt.Sprintf("%s/Users/authenticatebyname", jf.server)
|
url := fmt.Sprintf("%s/Users/authenticatebyname", jf.Server)
|
||||||
req, err := http.NewRequest("POST", url, buffer)
|
req, err := http.NewRequest("POST", url, buffer)
|
||||||
defer timeoutHandler("Jellyfin", jf.server, jf.noFail)
|
defer jf.timeoutHandler()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@ -128,16 +123,16 @@ func (jf *Jellyfin) authenticate(username, password string) (map[string]interfac
|
|||||||
}
|
}
|
||||||
var respData map[string]interface{}
|
var respData map[string]interface{}
|
||||||
json.NewDecoder(data).Decode(&respData)
|
json.NewDecoder(data).Decode(&respData)
|
||||||
jf.accessToken = respData["AccessToken"].(string)
|
jf.AccessToken = respData["AccessToken"].(string)
|
||||||
user := respData["User"].(map[string]interface{})
|
user := respData["User"].(map[string]interface{})
|
||||||
jf.userId = respData["User"].(map[string]interface{})["Id"].(string)
|
jf.userID = respData["User"].(map[string]interface{})["Id"].(string)
|
||||||
jf.auth = fmt.Sprintf("MediaBrowser Client=\"%s\", Device=\"%s\", DeviceId=\"%s\", Version=\"%s\", Token=\"%s\"", jf.client, jf.device, jf.deviceId, jf.version, jf.accessToken)
|
jf.auth = fmt.Sprintf("MediaBrowser Client=\"%s\", Device=\"%s\", DeviceId=\"%s\", Version=\"%s\", Token=\"%s\"", jf.client, jf.device, jf.deviceID, jf.version, jf.AccessToken)
|
||||||
jf.header["X-Emby-Authorization"] = jf.auth
|
jf.header["X-Emby-Authorization"] = jf.auth
|
||||||
jf.authenticated = true
|
jf.Authenticated = true
|
||||||
return user, resp.StatusCode, nil
|
return user, resp.StatusCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) _get(url string, params map[string]string) (string, int, error) {
|
func (jf *Jellyfin) get(url string, params map[string]string) (string, int, error) {
|
||||||
var req *http.Request
|
var req *http.Request
|
||||||
if params != nil {
|
if params != nil {
|
||||||
jsonParams, _ := json.Marshal(params)
|
jsonParams, _ := json.Marshal(params)
|
||||||
@ -149,13 +144,13 @@ func (jf *Jellyfin) _get(url string, params map[string]string) (string, int, err
|
|||||||
req.Header.Add(name, value)
|
req.Header.Add(name, value)
|
||||||
}
|
}
|
||||||
resp, err := jf.httpClient.Do(req)
|
resp, err := jf.httpClient.Do(req)
|
||||||
defer timeoutHandler("Jellyfin", jf.server, jf.noFail)
|
defer jf.timeoutHandler()
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil || resp.StatusCode != 200 {
|
||||||
if resp.StatusCode == 401 && jf.authenticated {
|
if resp.StatusCode == 401 && jf.Authenticated {
|
||||||
jf.authenticated = false
|
jf.Authenticated = false
|
||||||
_, _, authErr := jf.authenticate(jf.username, jf.password)
|
_, _, authErr := jf.Authenticate(jf.Username, jf.password)
|
||||||
if authErr == nil {
|
if authErr == nil {
|
||||||
v1, v2, v3 := jf._get(url, params)
|
v1, v2, v3 := jf.get(url, params)
|
||||||
return v1, v2, v3
|
return v1, v2, v3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,9 +159,6 @@ func (jf *Jellyfin) _get(url string, params map[string]string) (string, int, err
|
|||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
var data io.Reader
|
var data io.Reader
|
||||||
encoding := resp.Header.Get("Content-Encoding")
|
encoding := resp.Header.Get("Content-Encoding")
|
||||||
if TEST {
|
|
||||||
fmt.Println("response encoding:", encoding)
|
|
||||||
}
|
|
||||||
switch encoding {
|
switch encoding {
|
||||||
case "gzip":
|
case "gzip":
|
||||||
data, _ = gzip.NewReader(resp.Body)
|
data, _ = gzip.NewReader(resp.Body)
|
||||||
@ -180,20 +172,20 @@ func (jf *Jellyfin) _get(url string, params map[string]string) (string, int, err
|
|||||||
return buf.String(), resp.StatusCode, nil
|
return buf.String(), resp.StatusCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) _post(url string, data map[string]interface{}, response bool) (string, int, error) {
|
func (jf *Jellyfin) post(url string, data map[string]interface{}, response bool) (string, int, error) {
|
||||||
params, _ := json.Marshal(data)
|
params, _ := json.Marshal(data)
|
||||||
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(params))
|
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(params))
|
||||||
for name, value := range jf.header {
|
for name, value := range jf.header {
|
||||||
req.Header.Add(name, value)
|
req.Header.Add(name, value)
|
||||||
}
|
}
|
||||||
resp, err := jf.httpClient.Do(req)
|
resp, err := jf.httpClient.Do(req)
|
||||||
defer timeoutHandler("Jellyfin", jf.server, jf.noFail)
|
defer jf.timeoutHandler()
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil || resp.StatusCode != 200 {
|
||||||
if resp.StatusCode == 401 && jf.authenticated {
|
if resp.StatusCode == 401 && jf.Authenticated {
|
||||||
jf.authenticated = false
|
jf.Authenticated = false
|
||||||
_, _, authErr := jf.authenticate(jf.username, jf.password)
|
_, _, authErr := jf.Authenticate(jf.Username, jf.password)
|
||||||
if authErr == nil {
|
if authErr == nil {
|
||||||
v1, v2, v3 := jf._post(url, data, response)
|
v1, v2, v3 := jf.post(url, data, response)
|
||||||
return v1, v2, v3
|
return v1, v2, v3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,45 +207,48 @@ func (jf *Jellyfin) _post(url string, data map[string]interface{}, response bool
|
|||||||
return "", resp.StatusCode, nil
|
return "", resp.StatusCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) deleteUser(id string) (int, error) {
|
// DeleteUser deletes the user corresponding to the provided ID.
|
||||||
url := fmt.Sprintf("%s/Users/%s", jf.server, id)
|
func (jf *Jellyfin) DeleteUser(id string) (int, error) {
|
||||||
|
url := fmt.Sprintf("%s/Users/%s", jf.Server, id)
|
||||||
req, _ := http.NewRequest("DELETE", url, nil)
|
req, _ := http.NewRequest("DELETE", url, nil)
|
||||||
for name, value := range jf.header {
|
for name, value := range jf.header {
|
||||||
req.Header.Add(name, value)
|
req.Header.Add(name, value)
|
||||||
}
|
}
|
||||||
resp, err := jf.httpClient.Do(req)
|
resp, err := jf.httpClient.Do(req)
|
||||||
defer timeoutHandler("Jellyfin", jf.server, jf.noFail)
|
defer jf.timeoutHandler()
|
||||||
return resp.StatusCode, err
|
return resp.StatusCode, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) getUsers(public bool) ([]map[string]interface{}, int, error) {
|
// GetUsers returns all (visible) users on the Jellyfin instance.
|
||||||
|
func (jf *Jellyfin) GetUsers(public bool) ([]map[string]interface{}, int, error) {
|
||||||
var result []map[string]interface{}
|
var result []map[string]interface{}
|
||||||
var data string
|
var data string
|
||||||
var status int
|
var status int
|
||||||
var err error
|
var err error
|
||||||
if time.Now().After(jf.cacheExpiry) {
|
if time.Now().After(jf.CacheExpiry) {
|
||||||
if public {
|
if public {
|
||||||
url := fmt.Sprintf("%s/users/public", jf.server)
|
url := fmt.Sprintf("%s/users/public", jf.Server)
|
||||||
data, status, err = jf._get(url, nil)
|
data, status, err = jf.get(url, nil)
|
||||||
} else {
|
} else {
|
||||||
url := fmt.Sprintf("%s/users", jf.server)
|
url := fmt.Sprintf("%s/users", jf.Server)
|
||||||
data, status, err = jf._get(url, jf.loginParams)
|
data, status, err = jf.get(url, jf.loginParams)
|
||||||
}
|
}
|
||||||
if err != nil || status != 200 {
|
if err != nil || status != 200 {
|
||||||
return nil, status, err
|
return nil, status, err
|
||||||
}
|
}
|
||||||
json.Unmarshal([]byte(data), &result)
|
json.Unmarshal([]byte(data), &result)
|
||||||
jf.userCache = result
|
jf.userCache = result
|
||||||
jf.cacheExpiry = time.Now().Add(time.Minute * time.Duration(jf.cacheLength))
|
jf.CacheExpiry = time.Now().Add(time.Minute * time.Duration(jf.cacheLength))
|
||||||
return result, status, nil
|
return result, status, nil
|
||||||
}
|
}
|
||||||
return jf.userCache, 200, nil
|
return jf.userCache, 200, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) userByName(username string, public bool) (map[string]interface{}, int, error) {
|
// UserByName returns the user corresponding to the provided username.
|
||||||
|
func (jf *Jellyfin) UserByName(username string, public bool) (map[string]interface{}, int, error) {
|
||||||
var match map[string]interface{}
|
var match map[string]interface{}
|
||||||
find := func() (map[string]interface{}, int, error) {
|
find := func() (map[string]interface{}, int, error) {
|
||||||
users, status, err := jf.getUsers(public)
|
users, status, err := jf.GetUsers(public)
|
||||||
if err != nil || status != 200 {
|
if err != nil || status != 200 {
|
||||||
return nil, status, err
|
return nil, status, err
|
||||||
}
|
}
|
||||||
@ -266,48 +261,49 @@ func (jf *Jellyfin) userByName(username string, public bool) (map[string]interfa
|
|||||||
}
|
}
|
||||||
match, status, err := find()
|
match, status, err := find()
|
||||||
if match == nil {
|
if match == nil {
|
||||||
jf.cacheExpiry = time.Now()
|
jf.CacheExpiry = time.Now()
|
||||||
match, status, err = find()
|
match, status, err = find()
|
||||||
}
|
}
|
||||||
return match, status, err
|
return match, status, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) userById(userId string, public bool) (map[string]interface{}, int, error) {
|
// UserByID returns the user corresponding to the provided ID.
|
||||||
if jf.cacheExpiry.After(time.Now()) {
|
func (jf *Jellyfin) UserByID(userID string, public bool) (map[string]interface{}, int, error) {
|
||||||
|
if jf.CacheExpiry.After(time.Now()) {
|
||||||
for _, user := range jf.userCache {
|
for _, user := range jf.userCache {
|
||||||
if user["Id"].(string) == userId {
|
if user["Id"].(string) == userID {
|
||||||
return user, 200, nil
|
return user, 200, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if public {
|
if public {
|
||||||
users, status, err := jf.getUsers(public)
|
users, status, err := jf.GetUsers(public)
|
||||||
if err != nil || status != 200 {
|
if err != nil || status != 200 {
|
||||||
return nil, status, err
|
return nil, status, err
|
||||||
}
|
}
|
||||||
for _, user := range users {
|
for _, user := range users {
|
||||||
if user["Id"].(string) == userId {
|
if user["Id"].(string) == userID {
|
||||||
return user, status, nil
|
return user, status, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, status, err
|
return nil, status, err
|
||||||
} else {
|
|
||||||
var result map[string]interface{}
|
|
||||||
var data string
|
|
||||||
var status int
|
|
||||||
var err error
|
|
||||||
url := fmt.Sprintf("%s/users/%s", jf.server, userId)
|
|
||||||
data, status, err = jf._get(url, jf.loginParams)
|
|
||||||
if err != nil || status != 200 {
|
|
||||||
return nil, status, err
|
|
||||||
}
|
|
||||||
json.Unmarshal([]byte(data), &result)
|
|
||||||
return result, status, nil
|
|
||||||
}
|
}
|
||||||
|
var result map[string]interface{}
|
||||||
|
var data string
|
||||||
|
var status int
|
||||||
|
var err error
|
||||||
|
url := fmt.Sprintf("%s/users/%s", jf.Server, userID)
|
||||||
|
data, status, err = jf.get(url, jf.loginParams)
|
||||||
|
if err != nil || status != 200 {
|
||||||
|
return nil, status, err
|
||||||
|
}
|
||||||
|
json.Unmarshal([]byte(data), &result)
|
||||||
|
return result, status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) newUser(username, password string) (map[string]interface{}, int, error) {
|
// NewUser creates a new user with the provided username and password.
|
||||||
url := fmt.Sprintf("%s/Users/New", jf.server)
|
func (jf *Jellyfin) NewUser(username, password string) (map[string]interface{}, int, error) {
|
||||||
|
url := fmt.Sprintf("%s/Users/New", jf.Server)
|
||||||
stringData := map[string]string{
|
stringData := map[string]string{
|
||||||
"Name": username,
|
"Name": username,
|
||||||
"Password": password,
|
"Password": password,
|
||||||
@ -316,7 +312,7 @@ func (jf *Jellyfin) newUser(username, password string) (map[string]interface{},
|
|||||||
for key, value := range stringData {
|
for key, value := range stringData {
|
||||||
data[key] = value
|
data[key] = value
|
||||||
}
|
}
|
||||||
response, status, err := jf._post(url, data, true)
|
response, status, err := jf.post(url, data, true)
|
||||||
var recv map[string]interface{}
|
var recv map[string]interface{}
|
||||||
json.Unmarshal([]byte(response), &recv)
|
json.Unmarshal([]byte(response), &recv)
|
||||||
if err != nil || !(status == 200 || status == 204) {
|
if err != nil || !(status == 200 || status == 204) {
|
||||||
@ -325,24 +321,27 @@ func (jf *Jellyfin) newUser(username, password string) (map[string]interface{},
|
|||||||
return recv, status, nil
|
return recv, status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) setPolicy(userId string, policy map[string]interface{}) (int, error) {
|
// SetPolicy sets the access policy for the user corresponding to the provided ID.
|
||||||
url := fmt.Sprintf("%s/Users/%s/Policy", jf.server, userId)
|
func (jf *Jellyfin) SetPolicy(userID string, policy map[string]interface{}) (int, error) {
|
||||||
_, status, err := jf._post(url, policy, false)
|
url := fmt.Sprintf("%s/Users/%s/Policy", jf.Server, userID)
|
||||||
|
_, status, err := jf.post(url, policy, false)
|
||||||
if err != nil || status != 200 {
|
if err != nil || status != 200 {
|
||||||
return status, err
|
return status, err
|
||||||
}
|
}
|
||||||
return status, nil
|
return status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) setConfiguration(userId string, configuration map[string]interface{}) (int, error) {
|
// SetConfiguration sets the configuration (part of homescreen layout) for the user corresponding to the provided ID.
|
||||||
url := fmt.Sprintf("%s/Users/%s/Configuration", jf.server, userId)
|
func (jf *Jellyfin) SetConfiguration(userID string, configuration map[string]interface{}) (int, error) {
|
||||||
_, status, err := jf._post(url, configuration, false)
|
url := fmt.Sprintf("%s/Users/%s/Configuration", jf.Server, userID)
|
||||||
|
_, status, err := jf.post(url, configuration, false)
|
||||||
return status, err
|
return status, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) getDisplayPreferences(userId string) (map[string]interface{}, int, error) {
|
// GetDisplayPreferences gets the displayPreferences (part of homescreen layout) for the user corresponding to the provided ID.
|
||||||
url := fmt.Sprintf("%s/DisplayPreferences/usersettings?userId=%s&client=emby", jf.server, userId)
|
func (jf *Jellyfin) GetDisplayPreferences(userID string) (map[string]interface{}, int, error) {
|
||||||
data, status, err := jf._get(url, nil)
|
url := fmt.Sprintf("%s/DisplayPreferences/usersettings?userId=%s&client=emby", jf.Server, userID)
|
||||||
|
data, status, err := jf.get(url, nil)
|
||||||
if err != nil || !(status == 204 || status == 200) {
|
if err != nil || !(status == 204 || status == 200) {
|
||||||
return nil, status, err
|
return nil, status, err
|
||||||
}
|
}
|
||||||
@ -354,9 +353,10 @@ func (jf *Jellyfin) getDisplayPreferences(userId string) (map[string]interface{}
|
|||||||
return displayprefs, status, nil
|
return displayprefs, status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jf *Jellyfin) setDisplayPreferences(userId string, displayprefs map[string]interface{}) (int, error) {
|
// SetDisplayPreferences sets the displayPreferences (part of homescreen layout) for the user corresponding to the provided ID.
|
||||||
url := fmt.Sprintf("%s/DisplayPreferences/usersettings?userId=%s&client=emby", jf.server, userId)
|
func (jf *Jellyfin) SetDisplayPreferences(userID string, displayprefs map[string]interface{}) (int, error) {
|
||||||
_, status, err := jf._post(url, displayprefs, false)
|
url := fmt.Sprintf("%s/DisplayPreferences/usersettings?userId=%s&client=emby", jf.Server, userID)
|
||||||
|
_, status, err := jf.post(url, displayprefs, false)
|
||||||
if err != nil || !(status == 204 || status == 200) {
|
if err != nil || !(status == 204 || status == 200) {
|
||||||
return status, err
|
return status, err
|
||||||
}
|
}
|
53
main.go
53
main.go
@ -23,7 +23,10 @@ import (
|
|||||||
"github.com/gin-contrib/pprof"
|
"github.com/gin-contrib/pprof"
|
||||||
"github.com/gin-contrib/static"
|
"github.com/gin-contrib/static"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/hrfee/jfa-go/common"
|
||||||
_ "github.com/hrfee/jfa-go/docs"
|
_ "github.com/hrfee/jfa-go/docs"
|
||||||
|
"github.com/hrfee/jfa-go/jfapi"
|
||||||
|
"github.com/hrfee/jfa-go/ombi"
|
||||||
"github.com/lithammer/shortuuid/v3"
|
"github.com/lithammer/shortuuid/v3"
|
||||||
"github.com/logrusorgru/aurora/v3"
|
"github.com/logrusorgru/aurora/v3"
|
||||||
swaggerFiles "github.com/swaggo/files"
|
swaggerFiles "github.com/swaggo/files"
|
||||||
@ -51,9 +54,9 @@ type appContext struct {
|
|||||||
jellyfinLogin bool
|
jellyfinLogin bool
|
||||||
users []User
|
users []User
|
||||||
invalidTokens []string
|
invalidTokens []string
|
||||||
jf *Jellyfin
|
jf *jfapi.Jellyfin
|
||||||
authJf *Jellyfin
|
authJf *jfapi.Jellyfin
|
||||||
ombi *Ombi
|
ombi *ombi.Ombi
|
||||||
datePattern string
|
datePattern string
|
||||||
timePattern string
|
timePattern string
|
||||||
storage Storage
|
storage Storage
|
||||||
@ -139,18 +142,18 @@ var (
|
|||||||
func test(app *appContext) {
|
func test(app *appContext) {
|
||||||
fmt.Printf("\n\n----\n\n")
|
fmt.Printf("\n\n----\n\n")
|
||||||
settings := map[string]interface{}{
|
settings := map[string]interface{}{
|
||||||
"server": app.jf.server,
|
"server": app.jf.Server,
|
||||||
"server version": app.jf.serverInfo.Version,
|
"server version": app.jf.ServerInfo.Version,
|
||||||
"server name": app.jf.serverInfo.Name,
|
"server name": app.jf.ServerInfo.Name,
|
||||||
"authenticated?": app.jf.authenticated,
|
"authenticated?": app.jf.Authenticated,
|
||||||
"access token": app.jf.accessToken,
|
"access token": app.jf.AccessToken,
|
||||||
"username": app.jf.username,
|
"username": app.jf.Username,
|
||||||
}
|
}
|
||||||
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, status, err := app.jf.GetUsers(false)
|
||||||
fmt.Printf("getUsers: code %d err %s maplength %d\n", status, err, len(users))
|
fmt.Printf("GetUsers: code %d err %s maplength %d\n", status, 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)
|
||||||
@ -161,8 +164,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, status, 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, status, err)
|
||||||
out, err := json.MarshalIndent(user, "", " ")
|
out, err := json.MarshalIndent(user, "", " ")
|
||||||
fmt.Print(string(out))
|
fmt.Print(string(out))
|
||||||
}
|
}
|
||||||
@ -358,19 +361,14 @@ func start(asDaemon, firstCall bool) {
|
|||||||
|
|
||||||
app.debug.Println("Loading storage")
|
app.debug.Println("Loading storage")
|
||||||
|
|
||||||
// app.storage.invite_path = filepath.Join(app.data_path, "invites.json")
|
|
||||||
app.storage.invite_path = app.config.Section("files").Key("invites").String()
|
app.storage.invite_path = app.config.Section("files").Key("invites").String()
|
||||||
app.storage.loadInvites()
|
app.storage.loadInvites()
|
||||||
// app.storage.emails_path = filepath.Join(app.data_path, "emails.json")
|
|
||||||
app.storage.emails_path = app.config.Section("files").Key("emails").String()
|
app.storage.emails_path = app.config.Section("files").Key("emails").String()
|
||||||
app.storage.loadEmails()
|
app.storage.loadEmails()
|
||||||
// app.storage.policy_path = filepath.Join(app.data_path, "user_template.json")
|
|
||||||
app.storage.policy_path = app.config.Section("files").Key("user_template").String()
|
app.storage.policy_path = app.config.Section("files").Key("user_template").String()
|
||||||
app.storage.loadPolicy()
|
app.storage.loadPolicy()
|
||||||
// app.storage.configuration_path = filepath.Join(app.data_path, "user_configuration.json")
|
|
||||||
app.storage.configuration_path = app.config.Section("files").Key("user_configuration").String()
|
app.storage.configuration_path = app.config.Section("files").Key("user_configuration").String()
|
||||||
app.storage.loadConfiguration()
|
app.storage.loadConfiguration()
|
||||||
// app.storage.displayprefs_path = filepath.Join(app.data_path, "user_displayprefs.json")
|
|
||||||
app.storage.displayprefs_path = app.config.Section("files").Key("user_displayprefs").String()
|
app.storage.displayprefs_path = app.config.Section("files").Key("user_displayprefs").String()
|
||||||
app.storage.loadDisplayprefs()
|
app.storage.loadDisplayprefs()
|
||||||
|
|
||||||
@ -397,16 +395,18 @@ func start(asDaemon, firstCall bool) {
|
|||||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
app.storage.ombi_path = app.config.Section("files").Key("ombi_template").String()
|
app.storage.ombi_path = app.config.Section("files").Key("ombi_template").String()
|
||||||
app.storage.loadOmbiTemplate()
|
app.storage.loadOmbiTemplate()
|
||||||
app.ombi = newOmbi(
|
ombiServer := app.config.Section("ombi").Key("server").String()
|
||||||
app.config.Section("ombi").Key("server").String(),
|
app.ombi = ombi.NewOmbi(
|
||||||
|
ombiServer,
|
||||||
app.config.Section("ombi").Key("api_key").String(),
|
app.config.Section("ombi").Key("api_key").String(),
|
||||||
true,
|
common.NewTimeoutHandler("Ombi", ombiServer, true),
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.configBase_path = filepath.Join(app.local_path, "config-base.json")
|
app.configBase_path = filepath.Join(app.local_path, "config-base.json")
|
||||||
config_base, _ := ioutil.ReadFile(app.configBase_path)
|
configBase, _ := ioutil.ReadFile(app.configBase_path)
|
||||||
json.Unmarshal(config_base, &app.configBase)
|
json.Unmarshal(configBase, &app.configBase)
|
||||||
|
|
||||||
themes := map[string]string{
|
themes := map[string]string{
|
||||||
"Jellyfin (Dark)": fmt.Sprintf("bs%d-jf.css", app.bsVersion),
|
"Jellyfin (Dark)": fmt.Sprintf("bs%d-jf.css", app.bsVersion),
|
||||||
@ -435,20 +435,21 @@ func start(asDaemon, firstCall bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
server := app.config.Section("jellyfin").Key("server").String()
|
server := app.config.Section("jellyfin").Key("server").String()
|
||||||
app.jf, _ = newJellyfin(
|
app.jf, _ = jfapi.NewJellyfin(
|
||||||
server,
|
server,
|
||||||
app.config.Section("jellyfin").Key("client").String(),
|
app.config.Section("jellyfin").Key("client").String(),
|
||||||
app.config.Section("jellyfin").Key("version").String(),
|
app.config.Section("jellyfin").Key("version").String(),
|
||||||
app.config.Section("jellyfin").Key("device").String(),
|
app.config.Section("jellyfin").Key("device").String(),
|
||||||
app.config.Section("jellyfin").Key("device_id").String(),
|
app.config.Section("jellyfin").Key("device_id").String(),
|
||||||
|
common.NewTimeoutHandler("Jellyfin", server, true),
|
||||||
)
|
)
|
||||||
var status int
|
var status int
|
||||||
_, status, err = app.jf.authenticate(app.config.Section("jellyfin").Key("username").String(), app.config.Section("jellyfin").Key("password").String())
|
_, status, err = app.jf.Authenticate(app.config.Section("jellyfin").Key("username").String(), app.config.Section("jellyfin").Key("password").String())
|
||||||
if status != 200 || err != nil {
|
if status != 200 || err != nil {
|
||||||
app.err.Fatalf("Failed to authenticate with Jellyfin @ %s: Code %d", server, status)
|
app.err.Fatalf("Failed to authenticate with Jellyfin @ %s: Code %d", server, status)
|
||||||
}
|
}
|
||||||
app.info.Printf("Authenticated with %s", server)
|
app.info.Printf("Authenticated with %s", server)
|
||||||
app.authJf, _ = newJellyfin(server, "jfa-go", app.version, "auth", "auth")
|
app.authJf, _ = jfapi.NewJellyfin(server, "jfa-go", app.version, "auth", "auth", common.NewTimeoutHandler("Jellyfin", server, true))
|
||||||
|
|
||||||
app.loadStrftime()
|
app.loadStrftime()
|
||||||
|
|
||||||
|
5
ombi/go.mod
Normal file
5
ombi/go.mod
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module github.com/hrfee/jfa-go/ombi
|
||||||
|
|
||||||
|
replace github.com/hrfee/jfa-go/common => ../common
|
||||||
|
|
||||||
|
go 1.15
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package ombi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -9,36 +9,40 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/hrfee/jfa-go/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Ombi represents a running Ombi instance.
|
||||||
type Ombi struct {
|
type Ombi struct {
|
||||||
server, key string
|
server, key string
|
||||||
header map[string]string
|
header map[string]string
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
noFail bool
|
userCache []map[string]interface{}
|
||||||
userCache []map[string]interface{}
|
cacheExpiry time.Time
|
||||||
cacheExpiry time.Time
|
cacheLength int
|
||||||
cacheLength int
|
timeoutHandler common.TimeoutHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOmbi(server, key string, noFail bool) *Ombi {
|
// NewOmbi returns an Ombi object.
|
||||||
|
func NewOmbi(server, key string, timeoutHandler common.TimeoutHandler) *Ombi {
|
||||||
return &Ombi{
|
return &Ombi{
|
||||||
server: server,
|
server: server,
|
||||||
key: key,
|
key: key,
|
||||||
noFail: noFail,
|
|
||||||
httpClient: &http.Client{
|
httpClient: &http.Client{
|
||||||
Timeout: 10 * time.Second,
|
Timeout: 10 * time.Second,
|
||||||
},
|
},
|
||||||
header: map[string]string{
|
header: map[string]string{
|
||||||
"ApiKey": key,
|
"ApiKey": key,
|
||||||
},
|
},
|
||||||
cacheLength: 30,
|
cacheLength: 30,
|
||||||
cacheExpiry: time.Now(),
|
cacheExpiry: time.Now(),
|
||||||
|
timeoutHandler: timeoutHandler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// does a GET and returns the response as a string.
|
// does a GET and returns the response as a string.
|
||||||
func (ombi *Ombi) _getJSON(url string, params map[string]string) (string, int, error) {
|
func (ombi *Ombi) getJSON(url string, params map[string]string) (string, int, error) {
|
||||||
if ombi.key == "" {
|
if ombi.key == "" {
|
||||||
return "", 401, fmt.Errorf("No API key provided")
|
return "", 401, fmt.Errorf("No API key provided")
|
||||||
}
|
}
|
||||||
@ -53,7 +57,7 @@ func (ombi *Ombi) _getJSON(url string, params map[string]string) (string, int, e
|
|||||||
req.Header.Add(name, value)
|
req.Header.Add(name, value)
|
||||||
}
|
}
|
||||||
resp, err := ombi.httpClient.Do(req)
|
resp, err := ombi.httpClient.Do(req)
|
||||||
defer timeoutHandler("Ombi", ombi.server, ombi.noFail)
|
defer ombi.timeoutHandler()
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil || resp.StatusCode != 200 {
|
||||||
if resp.StatusCode == 401 {
|
if resp.StatusCode == 401 {
|
||||||
return "", 401, fmt.Errorf("Invalid API Key")
|
return "", 401, fmt.Errorf("Invalid API Key")
|
||||||
@ -77,7 +81,7 @@ func (ombi *Ombi) _getJSON(url string, params map[string]string) (string, int, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// does a POST and optionally returns response as string. Returns a string instead of an io.reader bcs i couldn't get it working otherwise.
|
// does a POST and optionally returns response as string. Returns a string instead of an io.reader bcs i couldn't get it working otherwise.
|
||||||
func (ombi *Ombi) _send(mode string, url string, data map[string]interface{}, response bool) (string, int, error) {
|
func (ombi *Ombi) send(mode string, url string, data map[string]interface{}, response bool) (string, int, error) {
|
||||||
responseText := ""
|
responseText := ""
|
||||||
params, _ := json.Marshal(data)
|
params, _ := json.Marshal(data)
|
||||||
req, _ := http.NewRequest(mode, url, bytes.NewBuffer(params))
|
req, _ := http.NewRequest(mode, url, bytes.NewBuffer(params))
|
||||||
@ -86,7 +90,7 @@ func (ombi *Ombi) _send(mode string, url string, data map[string]interface{}, re
|
|||||||
req.Header.Add(name, value)
|
req.Header.Add(name, value)
|
||||||
}
|
}
|
||||||
resp, err := ombi.httpClient.Do(req)
|
resp, err := ombi.httpClient.Do(req)
|
||||||
defer timeoutHandler("Ombi", ombi.server, ombi.noFail)
|
defer ombi.timeoutHandler()
|
||||||
if err != nil || !(resp.StatusCode == 200 || resp.StatusCode == 201) {
|
if err != nil || !(resp.StatusCode == 200 || resp.StatusCode == 201) {
|
||||||
if resp.StatusCode == 401 {
|
if resp.StatusCode == 401 {
|
||||||
return "", 401, fmt.Errorf("Invalid API Key")
|
return "", 401, fmt.Errorf("Invalid API Key")
|
||||||
@ -112,24 +116,26 @@ func (ombi *Ombi) _send(mode string, url string, data map[string]interface{}, re
|
|||||||
return responseText, resp.StatusCode, nil
|
return responseText, resp.StatusCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ombi *Ombi) _post(url string, data map[string]interface{}, response bool) (string, int, error) {
|
func (ombi *Ombi) post(url string, data map[string]interface{}, response bool) (string, int, error) {
|
||||||
return ombi._send("POST", url, data, response)
|
return ombi.send("POST", url, data, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ombi *Ombi) _put(url string, data map[string]interface{}, response bool) (string, int, error) {
|
func (ombi *Ombi) put(url string, data map[string]interface{}, response bool) (string, int, error) {
|
||||||
return ombi._send("PUT", url, data, response)
|
return ombi.send("PUT", url, data, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ombi *Ombi) modifyUser(user map[string]interface{}) (status int, err error) {
|
// ModifyUser applies the given modified user object to the corresponding user.
|
||||||
|
func (ombi *Ombi) ModifyUser(user map[string]interface{}) (status int, 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
|
||||||
}
|
}
|
||||||
_, status, err = ombi._put(ombi.server+"/api/v1/Identity", user, false)
|
_, status, err = ombi.put(ombi.server+"/api/v1/Identity", user, false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ombi *Ombi) deleteUser(id string) (code int, err error) {
|
// DeleteUser deletes the user corresponding to the given ID.
|
||||||
|
func (ombi *Ombi) DeleteUser(id string) (code int, 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")
|
||||||
@ -137,21 +143,21 @@ func (ombi *Ombi) deleteUser(id string) (code int, err error) {
|
|||||||
req.Header.Add(name, value)
|
req.Header.Add(name, value)
|
||||||
}
|
}
|
||||||
resp, err := ombi.httpClient.Do(req)
|
resp, err := ombi.httpClient.Do(req)
|
||||||
defer timeoutHandler("Ombi", ombi.server, ombi.noFail)
|
defer ombi.timeoutHandler()
|
||||||
return resp.StatusCode, err
|
return resp.StatusCode, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets an ombi user by their 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{}, code int, 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)
|
||||||
json.Unmarshal([]byte(resp), &result)
|
json.Unmarshal([]byte(resp), &result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets a list of all users.
|
// GetUsers returns all users on the Ombi instance.
|
||||||
func (ombi *Ombi) getUsers() ([]map[string]interface{}, int, error) {
|
func (ombi *Ombi) GetUsers() ([]map[string]interface{}, int, 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{}
|
||||||
json.Unmarshal([]byte(resp), &result)
|
json.Unmarshal([]byte(resp), &result)
|
||||||
ombi.userCache = result
|
ombi.userCache = result
|
||||||
@ -175,9 +181,9 @@ var stripFromOmbi = []string{
|
|||||||
"userName",
|
"userName",
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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{}, code int, err error) {
|
||||||
result, code, err = ombi.userByID(id)
|
result, code, err = ombi.UserByID(id)
|
||||||
if err != nil || code != 200 {
|
if err != nil || code != 200 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -194,14 +200,14 @@ func (ombi *Ombi) templateByID(id string) (result map[string]interface{}, code i
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates a new user.
|
// 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, int, 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)
|
||||||
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 || code != 200 {
|
@ -59,7 +59,7 @@ 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, status, err := app.jf.UserByName(pwr.Username, false)
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
app.err.Printf("Failed to get users from Jellyfin: Code %d", status)
|
app.err.Printf("Failed to get users from Jellyfin: Code %d", status)
|
||||||
app.debug.Printf("Error: %s", err)
|
app.debug.Printf("Error: %s", err)
|
||||||
|
7
setup.go
7
setup.go
@ -2,6 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/hrfee/jfa-go/common"
|
||||||
|
"github.com/hrfee/jfa-go/jfapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testReq struct {
|
type testReq struct {
|
||||||
@ -13,9 +15,8 @@ type testReq struct {
|
|||||||
func (app *appContext) TestJF(gc *gin.Context) {
|
func (app *appContext) TestJF(gc *gin.Context) {
|
||||||
var req testReq
|
var req testReq
|
||||||
gc.BindJSON(&req)
|
gc.BindJSON(&req)
|
||||||
tempjf, _ := newJellyfin(req.Host, "jfa-go-setup", app.version, "auth", "auth")
|
tempjf, _ := jfapi.NewJellyfin(req.Host, "jfa-go-setup", app.version, "auth", "auth", common.NewTimeoutHandler("authJF", req.Host, true))
|
||||||
tempjf.noFail = true
|
_, status, err := tempjf.Authenticate(req.Username, req.Password)
|
||||||
_, status, err := tempjf.authenticate(req.Username, req.Password)
|
|
||||||
if !(status == 200 || status == 204) || err != nil {
|
if !(status == 200 || status == 204) || err != nil {
|
||||||
app.info.Printf("Auth failed with code %d (%s)", status, err)
|
app.info.Printf("Auth failed with code %d (%s)", status, err)
|
||||||
gc.JSON(401, map[string]bool{"success": false})
|
gc.JSON(401, map[string]bool{"success": false})
|
||||||
|
Loading…
Reference in New Issue
Block a user