@ -2,33 +2,34 @@ package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/knz/strtime"
"github.com/lithammer/shortuuid/v3"
"gopkg.in/ini.v1"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
"github.com/knz/strtime"
"github.com/lithammer/shortuuid/v3"
"gopkg.in/ini.v1"
)
func ( ctx * appContext ) loadStrftime ( ) {
ctx . datePattern = ctx . config . Section ( "email" ) . Key ( "date_format" ) . String ( )
ctx . timePattern = ` %H:%M `
if val , _ := ctx . config . Section ( "email" ) . Key ( "use_24h" ) . Bool ( ) ; ! val {
ctx . timePattern = ` %I:%M %p `
func ( app * appContext ) loadStrftime ( ) {
app. datePattern = app . config . Section ( "email" ) . Key ( "date_format" ) . String ( )
app . timePattern = ` %H:%M `
if val , _ := app . config . Section ( "email" ) . Key ( "use_24h" ) . Bool ( ) ; ! val {
app . timePattern = ` %I:%M %p `
}
return
}
func ( ctx * appContext ) prettyTime ( dt time . Time ) ( date , time string ) {
date , _ = strtime . Strftime ( dt , ctx . datePattern )
time , _ = strtime . Strftime ( dt , ctx . timePattern )
func ( app * appContext ) prettyTime ( dt time . Time ) ( date , time string ) {
date , _ = strtime . Strftime ( dt , app . datePattern )
time , _ = strtime . Strftime ( dt , app . timePattern )
return
}
func ( ctx * appContext ) formatDatetime ( dt time . Time ) string {
d , t := ctx . prettyTime ( dt )
func ( app * appContext ) formatDatetime ( dt time . Time ) string {
d , t := app . prettyTime ( dt )
return d + " " + t
}
@ -79,60 +80,60 @@ func timeDiff(a, b time.Time) (year, month, day, hour, min, sec int) {
return
}
func ( ctx * appContext ) checkInvites ( ) {
func ( app * appContext ) checkInvites ( ) {
current_time := time . Now ( )
ctx . storage . loadInvites ( )
app . storage . loadInvites ( )
changed := false
for code , data := range ctx . storage . invites {
for code , data := range app . storage . invites {
expiry := data . ValidTill
if current_time . After ( expiry ) {
ctx . debug . Printf ( "Housekeeping: Deleting old invite %s" , code )
app . debug . Printf ( "Housekeeping: Deleting old invite %s" , code )
notify := data . Notify
if ctx . config . Section ( "notifications" ) . Key ( "enabled" ) . MustBool ( false ) && len ( notify ) != 0 {
ctx . debug . Printf ( "%s: Expiry notification" , code )
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 ( ) {
if ctx . email . constructExpiry ( code , data , ctx ) != nil {
ctx . err . Printf ( "%s: Failed to construct expiry notification" , code )
} else if ctx. email . send ( address , ctx ) != nil {
ctx . err . Printf ( "%s: Failed to send expiry notification" , code )
if app . email . constructExpiry ( code , data , app ) != nil {
app . err . Printf ( "%s: Failed to construct expiry notification" , code )
} else if app. email . send ( address , app ) != nil {
app . err . Printf ( "%s: Failed to send expiry notification" , code )
} else {
ctx . info . Printf ( "Sent expiry notification to %s" , address )
app . info . Printf ( "Sent expiry notification to %s" , address )
}
} ( )
}
}
}
changed = true
delete ( ctx . storage . invites , code )
delete ( app . storage . invites , code )
}
}
if changed {
ctx . storage . storeInvites ( )
app . storage . storeInvites ( )
}
}
func ( ctx * appContext ) checkInvite ( code string , used bool , username string ) bool {
func ( app * appContext ) checkInvite ( code string , used bool , username string ) bool {
current_time := time . Now ( )
ctx . storage . loadInvites ( )
app . storage . loadInvites ( )
changed := false
if inv , match := ctx . storage . invites [ code ] ; match {
if inv , match := app . storage . invites [ code ] ; match {
expiry := inv . ValidTill
if current_time . After ( expiry ) {
ctx . debug . Printf ( "Housekeeping: Deleting old invite %s" , code )
app . debug . Printf ( "Housekeeping: Deleting old invite %s" , code )
notify := inv . Notify
if ctx . config . Section ( "notifications" ) . Key ( "enabled" ) . MustBool ( false ) && len ( notify ) != 0 {
ctx . debug . Printf ( "%s: Expiry notification" , code )
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 ( ) {
if ctx . email . constructExpiry ( code , inv , ctx ) != nil {
ctx . err . Printf ( "%s: Failed to construct expiry notification" , code )
} else if ctx. email . send ( address , ctx ) != nil {
ctx . err . Printf ( "%s: Failed to send expiry notification" , code )
if app . email . constructExpiry ( code , inv , app ) != nil {
app . err . Printf ( "%s: Failed to construct expiry notification" , code )
} else if app. email . send ( address , app ) != nil {
app . err . Printf ( "%s: Failed to send expiry notification" , code )
} else {
ctx . info . Printf ( "Sent expiry notification to %s" , address )
app . info . Printf ( "Sent expiry notification to %s" , address )
}
} ( )
}
@ -140,25 +141,25 @@ func (ctx *appContext) checkInvite(code string, used bool, username string) bool
}
changed = true
match = false
delete ( ctx . storage . invites , code )
delete ( app . storage . invites , code )
} else if used {
changed = true
del := false
newInv := inv
if newInv . RemainingUses == 1 {
del = true
delete ( ctx . storage . invites , code )
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 , ctx . formatDatetime ( current_time ) } )
newInv . UsedBy = append ( newInv . UsedBy , [ ] string { username , app . formatDatetime ( current_time ) } )
if ! del {
ctx . storage . invites [ code ] = newInv
app . storage . invites [ code ] = newInv
}
}
if changed {
ctx . storage . storeInvites ( )
app . storage . storeInvites ( )
}
return match
}
@ -174,17 +175,17 @@ type newUserReq struct {
Code string ` json:"code" `
}
func ( ctx * appContext ) NewUser ( gc * gin . Context ) {
func ( app * appContext ) NewUser ( gc * gin . Context ) {
var req newUserReq
gc . BindJSON ( & req )
ctx . debug . Printf ( "%s: New user attempt" , req . Code )
if ! ctx . checkInvite ( req . Code , false , "" ) {
ctx . info . Printf ( "%s New user failed: invalid code" , req . Code )
app . debug . Printf ( "%s: New user attempt" , req . Code )
if ! app . checkInvite ( req . Code , false , "" ) {
app . info . Printf ( "%s New user failed: invalid code" , req . Code )
gc . JSON ( 401 , map [ string ] bool { "success" : false } )
gc . Abort ( )
return
}
validation := ctx . validator . validate ( req . Password )
validation := app . validator . validate ( req . Password )
valid := true
for _ , val := range validation {
if ! val {
@ -193,38 +194,38 @@ func (ctx *appContext) NewUser(gc *gin.Context) {
}
if ! valid {
// 200 bcs idk what i did in js
ctx . info . Printf ( "%s New user failed: Invalid password" , req . Code )
app . info . Printf ( "%s New user failed: Invalid password" , req . Code )
gc . JSON ( 200 , validation )
gc . Abort ( )
return
}
existingUser , _ , _ := ctx . jf . userByName ( req . Username , false )
existingUser , _ , _ := app . jf . userByName ( req . Username , false )
if existingUser != nil {
msg := fmt . Sprintf ( "User already exists named %s" , req . Username )
ctx . 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 )
return
}
user , status , err := ctx . jf . newUser ( req . Username , req . Password )
user , status , err := app . jf . newUser ( req . Username , req . Password )
if ! ( status == 200 || status == 204 ) || err != nil {
ctx . 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 )
return
}
ctx . checkInvite ( req . Code , true , req . Username )
invite := ctx . storage . invites [ req . Code ]
if ctx . config . Section ( "notifications" ) . Key ( "enabled" ) . MustBool ( false ) {
app . checkInvite ( req . Code , true , req . Username )
invite := app . storage . invites [ req . Code ]
if app . config . Section ( "notifications" ) . Key ( "enabled" ) . MustBool ( false ) {
for address , settings := range invite . Notify {
if settings [ "notify-creation" ] {
go func ( ) {
if ctx . email . constructCreated ( req . Code , req . Username , req . Email , invite , ctx ) != nil {
ctx . err . Printf ( "%s: Failed to construct user creation notification" , req . Code )
ctx . debug . Printf ( "%s: Error: %s" , req . Code , err )
} else if ctx. email . send ( address , ctx ) != nil {
ctx . err . Printf ( "%s: Failed to send user creation notification" , req . Code )
ctx . debug . Printf ( "%s: Error: %s" , req . Code , err )
if app . email . constructCreated ( req . Code , req . Username , req . Email , invite , app ) != nil {
app . err . Printf ( "%s: Failed to construct user creation notification" , req . Code )
app . debug . Printf ( "%s: Error: %s" , req . Code , err )
} else if app. email . send ( address , app ) != nil {
app . err . Printf ( "%s: Failed to send user creation notification" , req . Code )
app . debug . Printf ( "%s: Error: %s" , req . Code , err )
} else {
ctx . info . Printf ( "%s: Sent user creation notification to %s" , req . Code , address )
app . info . Printf ( "%s: Sent user creation notification to %s" , req . Code , address )
}
} ( )
}
@ -234,23 +235,23 @@ func (ctx *appContext) NewUser(gc *gin.Context) {
if user [ "Id" ] != nil {
id = user [ "Id" ] . ( string )
}
if len ( ctx . storage . policy ) != 0 {
status , err = ctx. jf . setPolicy ( id , ctx . storage . policy )
if len ( app . storage . policy ) != 0 {
status , err = app. jf . setPolicy ( id , app . storage . policy )
if ! ( status == 200 || status == 204 ) {
ctx . 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 ( ctx . storage . configuration ) != 0 && len ( ctx . storage . displayprefs ) != 0 {
status , err = ctx. jf . setConfiguration ( id , ctx . storage . configuration )
if len ( app . storage . configuration ) != 0 && len ( app . storage . displayprefs ) != 0 {
status , err = app. jf . setConfiguration ( id , app . storage . configuration )
if ( status == 200 || status == 204 ) && err == nil {
status , err = ctx. jf . setDisplayPreferences ( id , ctx . storage . displayprefs )
status , err = app. jf . setDisplayPreferences ( id , app . storage . displayprefs )
} else {
ctx . 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 )
}
}
if ctx . config . Section ( "password_resets" ) . Key ( "enabled" ) . MustBool ( false ) {
ctx . storage . emails [ id ] = req . Email
ctx . storage . storeEmails ( )
if app . config . Section ( "password_resets" ) . Key ( "enabled" ) . MustBool ( false ) {
app . storage . emails [ id ] = req . Email
app . storage . storeEmails ( )
}
gc . JSON ( 200 , validation )
}
@ -265,10 +266,10 @@ type generateInviteReq struct {
RemainingUses int ` json:"remaining-uses" `
}
func ( ctx * appContext ) GenerateInvite ( gc * gin . Context ) {
func ( app * appContext ) GenerateInvite ( gc * gin . Context ) {
var req generateInviteReq
ctx . debug . Println ( "Generating new invite" )
ctx . storage . loadInvites ( )
app . debug . Println ( "Generating new invite" )
app . storage . loadInvites ( )
gc . BindJSON ( & req )
current_time := time . Now ( )
valid_till := current_time . AddDate ( 0 , 0 , req . Days )
@ -286,40 +287,40 @@ func (ctx *appContext) GenerateInvite(gc *gin.Context) {
invite . RemainingUses = 1
}
invite . ValidTill = valid_till
if req . Email != "" && ctx . config . Section ( "invite_emails" ) . Key ( "enabled" ) . MustBool ( false ) {
ctx . debug . Printf ( "%s: Sending invite email" , invite_code )
if req . Email != "" && app . config . Section ( "invite_emails" ) . Key ( "enabled" ) . MustBool ( false ) {
app . debug . Printf ( "%s: Sending invite email" , invite_code )
invite . Email = req . Email
if err := ctx . email . constructInvite ( invite_code , invite , ctx ) ; err != nil {
if err := app . email . constructInvite ( invite_code , invite , app ) ; err != nil {
invite . Email = fmt . Sprintf ( "Failed to send to %s" , req . Email )
ctx . err . Printf ( "%s: Failed to construct invite email" , invite_code )
ctx . debug . Printf ( "%s: Error: %s" , invite_code , err )
} else if err := ctx . email . send ( req . Email , ctx ) ; err != nil {
app . err . Printf ( "%s: Failed to construct invite email" , invite_code )
app . debug . Printf ( "%s: Error: %s" , invite_code , err )
} else if err := app . email . send ( req . Email , app ) ; err != nil {
invite . Email = fmt . Sprintf ( "Failed to send to %s" , req . Email )
ctx . err . Printf ( "%s: %s" , invite_code , invite . Email )
ctx . debug . Printf ( "%s: Error: %s" , invite_code , err )
app . err . Printf ( "%s: %s" , invite_code , invite . Email )
app . debug . Printf ( "%s: Error: %s" , invite_code , err )
} else {
ctx . info . Printf ( "%s: Sent invite email to %s" , invite_code , req . Email )
app . info . Printf ( "%s: Sent invite email to %s" , invite_code , req . Email )
}
}
ctx . storage . invites [ invite_code ] = invite
ctx . storage . storeInvites ( )
app . storage . invites [ invite_code ] = invite
app . storage . storeInvites ( )
gc . JSON ( 200 , map [ string ] bool { "success" : true } )
}
func ( ctx * appContext ) GetInvites ( gc * gin . Context ) {
ctx . debug . Println ( "Invites requested" )
func ( app * appContext ) GetInvites ( gc * gin . Context ) {
app . debug . Println ( "Invites requested" )
current_time := time . Now ( )
ctx . storage . loadInvites ( )
ctx . checkInvites ( )
app . storage . loadInvites ( )
app . checkInvites ( )
var invites [ ] map [ string ] interface { }
for code , inv := range ctx . storage . invites {
for code , inv := range app . storage . invites {
_ , _ , days , hours , minutes , _ := timeDiff ( inv . ValidTill , current_time )
invite := make ( map [ string ] interface { } )
invite [ "code" ] = code
invite [ "days" ] = days
invite [ "hours" ] = hours
invite [ "minutes" ] = minutes
invite [ "created" ] = ctx . formatDatetime ( inv . Created )
invite [ "created" ] = app . formatDatetime ( inv . Created )
if len ( inv . UsedBy ) != 0 {
invite [ "used-by" ] = inv . UsedBy
}
@ -335,11 +336,11 @@ func (ctx *appContext) GetInvites(gc *gin.Context) {
}
if len ( inv . Notify ) != 0 {
var address string
if ctx . config . Section ( "ui" ) . Key ( "jellyfin_login" ) . MustBool ( false ) {
ctx . storage . loadEmails ( )
address = ctx . storage . emails [ gc . GetString ( "jfId" ) ] . ( string )
if app . config . Section ( "ui" ) . Key ( "jellyfin_login" ) . MustBool ( false ) {
app . storage . loadEmails ( )
address = app . storage . emails [ gc . GetString ( "jfId" ) ] . ( string )
} else {
address = ctx . config . Section ( "ui" ) . Key ( "email" ) . String ( )
address = app . config . Section ( "ui" ) . Key ( "email" ) . String ( )
}
if _ , ok := inv . Notify [ address ] ; ok {
for _ , notify_type := range [ ] string { "notify-expiry" , "notify-creation" } {
@ -362,34 +363,34 @@ type notifySetting struct {
NotifyCreation bool ` json:"notify-creation" `
}
func ( ctx * appContext ) SetNotify ( gc * gin . Context ) {
func ( app * appContext ) SetNotify ( gc * gin . Context ) {
var req map [ string ] notifySetting
gc . BindJSON ( & req )
changed := false
for code , settings := range req {
ctx . debug . Printf ( "%s: Notification settings change requested" , code )
ctx . storage . loadInvites ( )
ctx . storage . loadEmails ( )
invite , ok := ctx . storage . invites [ code ]
app . debug . Printf ( "%s: Notification settings change requested" , code )
app . storage . loadInvites ( )
app . storage . loadEmails ( )
invite , ok := app . storage . invites [ code ]
if ! ok {
ctx . err . Printf ( "%s Notification setting change failed: Invalid code" , code )
app . err . Printf ( "%s Notification setting change failed: Invalid code" , code )
gc . JSON ( 400 , map [ string ] string { "error" : "Invalid invite code" } )
gc . Abort ( )
return
}
var address string
if ctx . config . Section ( "ui" ) . Key ( "jellyfin_login" ) . MustBool ( false ) {
if app . config . Section ( "ui" ) . Key ( "jellyfin_login" ) . MustBool ( false ) {
var ok bool
address , ok = ctx . storage . emails [ gc . GetString ( "jfId" ) ] . ( string )
address , ok = app . storage . emails [ gc . GetString ( "jfId" ) ] . ( string )
if ! ok {
ctx . err . Printf ( "%s: Couldn't find email address. Make sure it's set" , code )
ctx . debug . Printf ( "%s: User ID \"%s\"" , code , gc . GetString ( "jfId" ) )
app . err . Printf ( "%s: Couldn't find email address. Make sure it's set" , code )
app . debug . Printf ( "%s: User ID \"%s\"" , code , gc . GetString ( "jfId" ) )
gc . JSON ( 500 , map [ string ] string { "error" : "Missing user email" } )
gc . Abort ( )
return
}
} else {
address = ctx . config . Section ( "ui" ) . Key ( "email" ) . String ( )
address = app . config . Section ( "ui" ) . Key ( "email" ) . String ( )
}
if invite . Notify == nil {
invite . Notify = map [ string ] map [ string ] bool { }
@ -401,20 +402,20 @@ func (ctx *appContext) SetNotify(gc *gin.Context) {
* /
if invite . Notify [ address ] [ "notify-expiry" ] != settings . NotifyExpiry {
invite . Notify [ address ] [ "notify-expiry" ] = settings . NotifyExpiry
ctx . debug . Printf ( "%s: Set \"notify-expiry\" to %t for %s" , code , settings . NotifyExpiry , address )
app . debug . Printf ( "%s: Set \"notify-expiry\" to %t for %s" , code , settings . NotifyExpiry , address )
changed = true
}
if invite . Notify [ address ] [ "notify-creation" ] != settings . NotifyCreation {
invite . Notify [ address ] [ "notify-creation" ] = settings . NotifyCreation
ctx . debug . Printf ( "%s: Set \"notify-creation\" to %t for %s" , code , settings . NotifyExpiry , address )
app . debug . Printf ( "%s: Set \"notify-creation\" to %t for %s" , code , settings . NotifyExpiry , address )
changed = true
}
if changed {
ctx . storage . invites [ code ] = invite
app . storage . invites [ code ] = invite
}
}
if changed {
ctx . storage . storeInvites ( )
app . storage . storeInvites ( )
}
}
@ -422,20 +423,20 @@ type deleteReq struct {
Code string ` json:"code" `
}
func ( ctx * appContext ) DeleteInvite ( gc * gin . Context ) {
func ( app * appContext ) DeleteInvite ( gc * gin . Context ) {
var req deleteReq
gc . BindJSON ( & req )
ctx . debug . Printf ( "%s: Deletion requested" , req . Code )
app . debug . Printf ( "%s: Deletion requested" , req . Code )
var ok bool
_ , ok = ctx . storage . invites [ req . Code ]
_ , ok = app . storage . invites [ req . Code ]
if ok {
delete ( ctx . storage . invites , req . Code )
ctx . storage . storeInvites ( )
ctx . info . Printf ( "%s: Invite deleted" , req . Code )
delete ( app . storage . invites , req . Code )
app . storage . storeInvites ( )
app . info . Printf ( "%s: Invite deleted" , req . Code )
gc . JSON ( 200 , map [ string ] bool { "success" : true } )
return
}
ctx . err . Printf ( "%s: Deletion failed: Invalid code" , req . Code )
app . err . Printf ( "%s: Deletion failed: Invalid code" , req . Code )
respond ( 401 , "Code doesn't exist" , gc )
}
@ -448,21 +449,21 @@ type respUser struct {
Email string ` json:"email,omitempty" `
}
func ( ctx * appContext ) GetUsers ( gc * gin . Context ) {
ctx . debug . Println ( "Users requested" )
func ( app * appContext ) GetUsers ( gc * gin . Context ) {
app . debug . Println ( "Users requested" )
var resp userResp
resp . UserList = [ ] respUser { }
users , status , err := ctx . jf . getUsers ( false )
users , status , err := app . jf . getUsers ( false )
if ! ( status == 200 || status == 204 ) || err != nil {
ctx . err . Printf ( "Failed to get users from Jellyfin: Code %d" , status )
ctx . debug . Printf ( "Error: %s" , err )
app . err . Printf ( "Failed to get users from Jellyfin: Code %d" , status )
app . debug . Printf ( "Error: %s" , err )
respond ( 500 , "Couldn't get users" , gc )
return
}
for _ , jfUser := range users {
var user respUser
user . Name = jfUser [ "Name" ] . ( string )
if email , ok := ctx . storage . emails [ jfUser [ "Id" ] . ( string ) ] ; ok {
if email , ok := app . storage . emails [ jfUser [ "Id" ] . ( string ) ] ; ok {
user . Email = email . ( string )
}
resp . UserList = append ( resp . UserList , user )
@ -470,24 +471,24 @@ func (ctx *appContext) GetUsers(gc *gin.Context) {
gc . JSON ( 200 , resp )
}
func ( ctx * appContext ) ModifyEmails ( gc * gin . Context ) {
func ( app * appContext ) ModifyEmails ( gc * gin . Context ) {
var req map [ string ] string
gc . BindJSON ( & req )
ctx . debug . Println ( "Email modification requested" )
users , status , err := ctx . jf . getUsers ( false )
app . debug . Println ( "Email modification requested" )
users , status , err := app . jf . getUsers ( false )
if ! ( status == 200 || status == 204 ) || err != nil {
ctx . err . Printf ( "Failed to get users from Jellyfin: Code %d" , status )
ctx . debug . Printf ( "Error: %s" , err )
app . err . Printf ( "Failed to get users from Jellyfin: Code %d" , status )
app . debug . Printf ( "Error: %s" , err )
respond ( 500 , "Couldn't get users" , gc )
return
}
for _ , jfUser := range users {
if address , ok := req [ jfUser [ "Name" ] . ( string ) ] ; ok {
ctx . storage . emails [ jfUser [ "Id" ] . ( string ) ] = address
app . storage . emails [ jfUser [ "Id" ] . ( string ) ] = address
}
}
ctx . storage . storeEmails ( )
ctx . info . Println ( "Email list modified" )
app . storage . storeEmails ( )
app . info . Println ( "Email list modified" )
gc . JSON ( 200 , map [ string ] bool { "success" : true } )
}
@ -496,46 +497,46 @@ type defaultsReq struct {
Homescreen bool ` json:"homescreen" `
}
func ( ctx * appContext ) SetDefaults ( gc * gin . Context ) {
func ( app * appContext ) SetDefaults ( gc * gin . Context ) {
var req defaultsReq
gc . BindJSON ( & req )
ctx . info . Printf ( "Getting user defaults from \"%s\"" , req . Username )
user , status , err := ctx . jf . userByName ( req . Username , false )
app . info . Printf ( "Getting user defaults from \"%s\"" , req . Username )
user , status , err := app . jf . userByName ( req . Username , false )
if ! ( status == 200 || status == 204 ) || err != nil {
ctx . err . Printf ( "Failed to get user from Jellyfin: Code %d" , status )
ctx . debug . Printf ( "Error: %s" , err )
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
}
userId := user [ "Id" ] . ( string )
policy := user [ "Policy" ] . ( map [ string ] interface { } )
ctx . storage . policy = policy
ctx . storage . storePolicy ( )
ctx . debug . Println ( "User policy template stored" )
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 = ctx . jf . getDisplayPreferences ( userId )
displayprefs , status , err = app . jf . getDisplayPreferences ( userId )
if ! ( status == 200 || status == 204 ) || err != nil {
ctx . err . Printf ( "Failed to get DisplayPrefs: Code %d" , status )
ctx . debug . Printf ( "Error: %s" , err )
app . err . Printf ( "Failed to get DisplayPrefs: Code %d" , status )
app . debug . Printf ( "Error: %s" , err )
respond ( 500 , "Couldn't get displayprefs" , gc )
return
}
ctx . storage . configuration = configuration
ctx . storage . displayprefs = displayprefs
ctx . storage . storeConfiguration ( )
ctx . debug . Println ( "Configuration template stored" )
ctx . storage . storeDisplayprefs ( )
ctx . debug . Println ( "DisplayPrefs template stored" )
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 } )
}
func ( ctx * appContext ) GetConfig ( gc * gin . Context ) {
ctx . info . Println ( "Config requested" )
func ( app * appContext ) GetConfig ( gc * gin . Context ) {
app . info . Println ( "Config requested" )
resp := map [ string ] interface { } { }
for section , settings := range ctx . configBase {
for section , settings := range app . configBase {
if section == "order" {
resp [ section ] = settings . ( [ ] interface { } )
} else {
@ -547,7 +548,7 @@ func (ctx *appContext) GetConfig(gc *gin.Context) {
resp [ section ] . ( map [ string ] interface { } ) [ key ] = values . ( map [ string ] interface { } )
if key != "meta" {
dataType := resp [ section ] . ( map [ string ] interface { } ) [ key ] . ( map [ string ] interface { } ) [ "type" ] . ( string )
configKey := ctx . config . Section ( section ) . Key ( key )
configKey := app . config . Section ( section ) . Key ( key )
if dataType == "number" {
if val , err := configKey . Int ( ) ; err == nil {
resp [ section ] . ( map [ string ] interface { } ) [ key ] . ( map [ string ] interface { } ) [ "value" ] = val
@ -565,11 +566,11 @@ func (ctx *appContext) GetConfig(gc *gin.Context) {
gc . JSON ( 200 , resp )
}
func ( ctx * appContext ) ModifyConfig ( gc * gin . Context ) {
ctx . info . Println ( "Config modification requested" )
func ( app * appContext ) ModifyConfig ( gc * gin . Context ) {
app . info . Println ( "Config modification requested" )
var req map [ string ] interface { }
gc . BindJSON ( & req )
tempConfig , _ := ini . Load ( ctx . config_path )
tempConfig , _ := ini . Load ( app . config_path )
for section , settings := range req {
_ , err := tempConfig . GetSection ( section )
if section != "restart-program" && err == nil {
@ -578,33 +579,33 @@ func (ctx *appContext) ModifyConfig(gc *gin.Context) {
}
}
}
tempConfig . SaveTo ( ctx . config_path )
ctx . debug . Println ( "Config saved" )
tempConfig . SaveTo ( app . config_path )
app . debug . Println ( "Config saved" )
gc . JSON ( 200 , map [ string ] bool { "success" : true } )
if req [ "restart-program" ] . ( bool ) {
ctx . info . Println ( "Restarting..." )
err := ctx . Restart ( )
app . info . Println ( "Restarting..." )
err := app . Restart ( )
if err != nil {
ctx . err . Printf ( "Couldn't restart, try restarting manually. (%s)" , err )
app . err . Printf ( "Couldn't restart, try restarting manually. (%s)" , err )
}
}
ctx . loadConfig ( )
app . loadConfig ( )
// Reinitialize password validator on config change, as opposed to every applicable request like in python.
if _ , ok := req [ "password_validation" ] ; ok {
ctx . debug . Println ( "Reinitializing validator" )
app . debug . Println ( "Reinitializing validator" )
validatorConf := ValidatorConf {
"characters" : ctx . config . Section ( "password_validation" ) . Key ( "min_length" ) . MustInt ( 0 ) ,
"uppercase characters" : ctx . config . Section ( "password_validation" ) . Key ( "upper" ) . MustInt ( 0 ) ,
"lowercase characters" : ctx . config . Section ( "password_validation" ) . Key ( "lower" ) . MustInt ( 0 ) ,
"numbers" : ctx . config . Section ( "password_validation" ) . Key ( "number" ) . MustInt ( 0 ) ,
"special characters" : ctx . config . Section ( "password_validation" ) . Key ( "special" ) . MustInt ( 0 ) ,
"characters" : app . config . Section ( "password_validation" ) . Key ( "min_length" ) . MustInt ( 0 ) ,
"uppercase characters" : app . config . Section ( "password_validation" ) . Key ( "upper" ) . MustInt ( 0 ) ,
"lowercase characters" : app . config . Section ( "password_validation" ) . Key ( "lower" ) . MustInt ( 0 ) ,
"numbers" : app . config . Section ( "password_validation" ) . Key ( "number" ) . MustInt ( 0 ) ,
"special characters" : app . config . Section ( "password_validation" ) . Key ( "special" ) . MustInt ( 0 ) ,
}
if ! ctx . config . Section ( "password_validation" ) . Key ( "enabled" ) . MustBool ( false ) {
if ! app . config . Section ( "password_validation" ) . Key ( "enabled" ) . MustBool ( false ) {
for key := range validatorConf {
validatorConf [ key ] = 0
}
}
ctx . validator . init ( validatorConf )
app . validator . init ( validatorConf )
}
}
@ -634,11 +635,11 @@ func (ctx *appContext) ModifyConfig(gc *gin.Context) {
// panic(fmt.Errorf("restarting"))
// }
func ( ctx * appContext ) Restart ( ) error {
func ( app * appContext ) Restart ( ) error {
defer func ( ) {
if r := recover ( ) ; r != nil {
signal . Notify ( ctx . quit , os . Interrupt )
<- ctx . quit
signal . Notify ( app . quit , os . Interrupt )
<- app . quit
}
} ( )
args := os . Args