profiles: fix application

moving to a DB meant empty slices in the Configuration & Policy structs
were being stored as null, and striking a nerve with Jellyfin.
Mediabrowser library change fixed that by de-nulling them itself, and a
new bool field called "Homescreen" is now used to decide if a profile
has a homescreen layout stored or not. This field is hopefully correctly
filled in during migration.
pull/279/head
Harvey Tindall 1 year ago
parent d2253ff069
commit b17d8424e9
No known key found for this signature in database
GPG Key ID: BBC65952848FB1A2

@ -79,8 +79,9 @@ func (app *appContext) CreateProfile(gc *gin.Context) {
return return
} }
profile := Profile{ profile := Profile{
FromUser: user.Name, FromUser: user.Name,
Policy: user.Policy, Policy: user.Policy,
Homescreen: req.Homescreen,
} }
app.debug.Printf("Creating profile from user \"%s\"", user.Name) app.debug.Printf("Creating profile from user \"%s\"", user.Name)
if req.Homescreen { if req.Homescreen {

@ -45,8 +45,13 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
} }
id := user.ID id := user.ID
profile := app.storage.GetDefaultProfile() profile := app.storage.GetDefaultProfile()
// Check profile isn't empty if req.Profile != "" && req.Profile != "none" {
if profile.Policy.BlockedTags != nil { if p, ok := app.storage.GetProfileKey(req.Profile); ok {
profile = p
} else {
app.debug.Printf("Couldn't find profile \"%s\", using default", req.Profile)
}
status, err = app.jf.SetPolicy(id, profile.Policy) status, err = app.jf.SetPolicy(id, profile.Policy)
if !(status == 200 || status == 204 || err == nil) { if !(status == 200 || status == 204 || err == nil) {
app.err.Printf("%s: Failed to set user policy (%d): %v", req.Username, status, err) app.err.Printf("%s: Failed to set user policy (%d): %v", req.Username, status, err)
@ -64,7 +69,6 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
app.storage.SetEmailsKey(id, EmailAddress{Addr: req.Email, Contact: true}) app.storage.SetEmailsKey(id, EmailAddress{Addr: req.Email, Contact: true})
} }
if app.config.Section("ombi").Key("enabled").MustBool(false) { if app.config.Section("ombi").Key("enabled").MustBool(false) {
profile := app.storage.GetDefaultProfile()
if profile.Ombi == nil { if profile.Ombi == nil {
profile.Ombi = map[string]interface{}{} profile.Ombi = map[string]interface{}{}
} }
@ -305,22 +309,18 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
if !ok { if !ok {
profile = app.storage.GetDefaultProfile() profile = app.storage.GetDefaultProfile()
} }
if profile.Policy.BlockedTags != nil { 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) && err == nil) {
if !((status == 200 || status == 204) && err == nil) { app.err.Printf("%s: Failed to set user policy (%d): %v", req.Code, status, err)
app.err.Printf("%s: Failed to set user policy (%d): %v", req.Code, status, err)
}
} }
if profile.Configuration.GroupedFolders != nil && 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) }
} if !((status == 200 || status == 204) && err == nil) {
if !((status == 200 || status == 204) && err == nil) { app.err.Printf("%s: Failed to set configuration template (%d): %v", req.Code, status, err)
app.err.Printf("%s: Failed to set configuration template (%d): %v", req.Code, status, err)
}
} }
} }
// if app.config.Section("password_resets").Key("enabled").MustBool(false) { // if app.config.Section("password_resets").Key("enabled").MustBool(false) {
@ -1010,13 +1010,13 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
if req.From == "profile" { if req.From == "profile" {
// Check profile exists & isn't empty // Check profile exists & isn't empty
profile, ok := app.storage.GetProfileKey(req.Profile) profile, ok := app.storage.GetProfileKey(req.Profile)
if !ok || profile.Policy.BlockedTags == nil { if !ok {
app.err.Printf("Couldn't find profile \"%s\" or profile was empty", req.Profile) app.err.Printf("Couldn't find profile \"%s\" or profile was empty", req.Profile)
respond(500, "Couldn't find profile", gc) respond(500, "Couldn't find profile", gc)
return return
} }
if req.Homescreen { if req.Homescreen {
if profile.Configuration.GroupedFolders == nil || len(profile.Displayprefs) == 0 { if !profile.Homescreen {
app.err.Printf("No homescreen saved in profile \"%s\"", req.Profile) app.err.Printf("No homescreen saved in profile \"%s\"", req.Profile)
respond(500, "No homescreen template available", gc) respond(500, "No homescreen template available", gc)
return return

@ -222,7 +222,6 @@ func (d *DiscordDaemon) NewTempInvite(ageSeconds, maxUses int) (inviteURL, iconU
} }
// FIXME: Fix CSS, and handle no icon // FIXME: Fix CSS, and handle no icon
iconURL = guild.IconURL("256") iconURL = guild.IconURL("256")
fmt.Println("GOT ICON", iconURL)
return return
} }

@ -31,7 +31,6 @@ require (
github.com/hrfee/jfa-go/linecache v0.0.0-20230421170108-d800b97f69b6 github.com/hrfee/jfa-go/linecache v0.0.0-20230421170108-d800b97f69b6
github.com/hrfee/jfa-go/logger v0.0.0-20230421170108-d800b97f69b6 github.com/hrfee/jfa-go/logger v0.0.0-20230421170108-d800b97f69b6
github.com/hrfee/jfa-go/ombi v0.0.0-20230421170108-d800b97f69b6 github.com/hrfee/jfa-go/ombi v0.0.0-20230421170108-d800b97f69b6
github.com/hrfee/mediabrowser v0.3.8
github.com/itchyny/timefmt-go v0.1.5 github.com/itchyny/timefmt-go v0.1.5
github.com/lithammer/shortuuid/v3 v3.0.7 github.com/lithammer/shortuuid/v3 v3.0.7
github.com/mailgun/mailgun-go/v4 v4.9.0 github.com/mailgun/mailgun-go/v4 v4.9.0
@ -84,6 +83,7 @@ require (
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect
github.com/hrfee/mediabrowser v0.3.10 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.13.1 // indirect github.com/klauspost/compress v1.13.1 // indirect

@ -216,6 +216,10 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hrfee/mediabrowser v0.3.8 h1:y0iBCb6jE3QKcsiCJSYva2fFPHRn4UA+sGRzoPuJ/Dk= github.com/hrfee/mediabrowser v0.3.8 h1:y0iBCb6jE3QKcsiCJSYva2fFPHRn4UA+sGRzoPuJ/Dk=
github.com/hrfee/mediabrowser v0.3.8/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U= github.com/hrfee/mediabrowser v0.3.8/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=
github.com/hrfee/mediabrowser v0.3.9 h1:ecBUd7LMjQrh+9SFRen2T2DzQqI7W8J7vV2lGExD0YU=
github.com/hrfee/mediabrowser v0.3.9/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=
github.com/hrfee/mediabrowser v0.3.10 h1:MUrgZQVY3mk76Bhn7PsZ4LFRhtGitkZA4FP+1qg1HFo=
github.com/hrfee/mediabrowser v0.3.10/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=

@ -29,6 +29,11 @@
<input type="text" class="field input ~neutral @high mt-4 mb-2" placeholder="{{ .strings.username }}" id="add-user-user"> <input type="text" class="field input ~neutral @high mt-4 mb-2" placeholder="{{ .strings.username }}" id="add-user-user">
<input type="email" class="field input ~neutral @high mt-4 mb-2" placeholder="{{ .strings.emailAddress }}"> <input type="email" class="field input ~neutral @high mt-4 mb-2" placeholder="{{ .strings.emailAddress }}">
<input type="password" class="field input ~neutral @high mb-4" placeholder="{{ .strings.password }}" id="add-user-password"> <input type="password" class="field input ~neutral @high mb-4" placeholder="{{ .strings.password }}" id="add-user-password">
<label class="label supra">{{ .strings.profile }}</label>
<div class="select ~neutral @low mb-2 mt-4">
<select id="add-user-profile">
</select>
</div>
<label> <label>
<input type="submit" class="unfocused"> <input type="submit" class="unfocused">
<span class="button ~urge @low full-width center supra submit">{{ .strings.create }}</span> <span class="button ~urge @low full-width center supra submit">{{ .strings.create }}</span>

@ -286,6 +286,9 @@ func migrateToBadger(app *appContext) {
} }
for k, v := range app.storage.deprecatedProfiles { for k, v := range app.storage.deprecatedProfiles {
if v.Configuration.GroupedFolders != nil || len(v.Displayprefs) != 0 {
v.Homescreen = true
}
app.storage.SetProfileKey(k, v) app.storage.SetProfileKey(k, v)
} }

@ -25,6 +25,7 @@ type newUserDTO struct {
MatrixContact bool `json:"matrix_contact"` // Whether or not to use matrix for notifications/pwrs MatrixContact bool `json:"matrix_contact"` // Whether or not to use matrix for notifications/pwrs
CaptchaID string `json:"captcha_id"` // Captcha ID (if enabled) CaptchaID string `json:"captcha_id"` // Captcha ID (if enabled)
CaptchaText string `json:"captcha_text"` // Captcha text (if enabled) CaptchaText string `json:"captcha_text"` // Captcha text (if enabled)
Profile string `json:"profile"` // Profile (for admins only)
} }
type newUserResponse struct { type newUserResponse struct {

@ -330,6 +330,9 @@ func (st *Storage) GetProfileKey(k string) (Profile, bool) {
// fmt.Printf("Failed to find profile: %v\n", err) // fmt.Printf("Failed to find profile: %v\n", err)
ok = false ok = false
} }
if result.Policy.BlockedTags == nil {
result.Policy.BlockedTags = []interface{}{}
}
return result, ok return result, ok
} }
@ -471,6 +474,7 @@ type Profile struct {
Admin bool `json:"admin,omitempty" badgerhold:"index"` Admin bool `json:"admin,omitempty" badgerhold:"index"`
LibraryAccess string `json:"libraries,omitempty"` LibraryAccess string `json:"libraries,omitempty"`
FromUser string `json:"fromUser,omitempty"` FromUser string `json:"fromUser,omitempty"`
Homescreen bool `json:"homescreen"`
Policy mediabrowser.Policy `json:"policy,omitempty"` Policy mediabrowser.Policy `json:"policy,omitempty"`
Configuration mediabrowser.Configuration `json:"configuration,omitempty"` Configuration mediabrowser.Configuration `json:"configuration,omitempty"`
Displayprefs map[string]interface{} `json:"displayprefs,omitempty"` Displayprefs map[string]interface{} `json:"displayprefs,omitempty"`

@ -765,6 +765,7 @@ export class accountsList {
private _addUserName = this._addUserForm.querySelector("input[type=text]") as HTMLInputElement; private _addUserName = this._addUserForm.querySelector("input[type=text]") as HTMLInputElement;
private _addUserEmail = this._addUserForm.querySelector("input[type=email]") as HTMLInputElement; private _addUserEmail = this._addUserForm.querySelector("input[type=email]") as HTMLInputElement;
private _addUserPassword = this._addUserForm.querySelector("input[type=password]") as HTMLInputElement; private _addUserPassword = this._addUserForm.querySelector("input[type=password]") as HTMLInputElement;
private _addUserProfile = this._addUserForm.querySelector("select") as HTMLSelectElement;
// Columns for sorting. // Columns for sorting.
private _columns: { [className: string]: Column } = {}; private _columns: { [className: string]: Column } = {};
@ -1252,7 +1253,8 @@ export class accountsList {
const send = { const send = {
"username": this._addUserName.value, "username": this._addUserName.value,
"email": this._addUserEmail.value, "email": this._addUserEmail.value,
"password": this._addUserPassword.value "password": this._addUserPassword.value,
"profile": this._addUserProfile.value,
}; };
for (let field in send) { for (let field in send) {
if (!send[field]) { if (!send[field]) {
@ -1733,6 +1735,15 @@ export class accountsList {
} }
} }
private _populateAddUserProfiles = () => {
this._addUserProfile.textContent = "";
let innerHTML = `<option value="none">${window.lang.strings("inviteNoProfile")}</option>`;
for (let i = 0; i < window.availableProfiles.length; i++) {
innerHTML += `<option value="${window.availableProfiles[i]}" ${i == 0 ? "selected" : ""}>${window.availableProfiles[i]}</option>`;
}
this._addUserProfile.innerHTML = innerHTML;
}
constructor() { constructor() {
this._populateNumbers(); this._populateNumbers();
this._users = {}; this._users = {};
@ -1743,7 +1754,10 @@ export class accountsList {
document.addEventListener("accounts-reload", this.reload); document.addEventListener("accounts-reload", this.reload);
document.addEventListener("accountCheckEvent", () => { this._checkCount++; this._checkCheckCount(); }); document.addEventListener("accountCheckEvent", () => { this._checkCount++; this._checkCheckCount(); });
document.addEventListener("accountUncheckEvent", () => { this._checkCount--; this._checkCheckCount(); }); document.addEventListener("accountUncheckEvent", () => { this._checkCount--; this._checkCheckCount(); });
this._addUserButton.onclick = window.modals.addUser.toggle; this._addUserButton.onclick = () => {
this._populateAddUserProfiles();
window.modals.addUser.toggle();
};
this._addUserForm.addEventListener("submit", this._addUser); this._addUserForm.addEventListener("submit", this._addUser);
this._deleteNotify.onchange = () => { this._deleteNotify.onchange = () => {

Loading…
Cancel
Save