mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 09:00:10 +00:00
db: migrate user profiles
This commit is contained in:
parent
63948a6de0
commit
a735e4ff29
@ -10,6 +10,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/itchyny/timefmt-go"
|
||||
"github.com/lithammer/shortuuid/v3"
|
||||
"github.com/timshannon/badgerhold/v4"
|
||||
)
|
||||
|
||||
func (app *appContext) checkInvites() {
|
||||
@ -202,7 +203,7 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
|
||||
}
|
||||
}
|
||||
if req.Profile != "" {
|
||||
if _, ok := app.storage.profiles[req.Profile]; ok {
|
||||
if _, ok := app.storage.GetProfileKey(req.Profile); ok {
|
||||
invite.Profile = req.Profile
|
||||
} else {
|
||||
invite.Profile = "Default"
|
||||
@ -283,17 +284,18 @@ func (app *appContext) GetInvites(gc *gin.Context) {
|
||||
}
|
||||
invites = append(invites, invite)
|
||||
}
|
||||
profiles := make([]string, len(app.storage.profiles))
|
||||
if len(app.storage.profiles) != 0 {
|
||||
profiles[0] = app.storage.defaultProfile
|
||||
fullProfileList := app.storage.GetProfiles()
|
||||
profiles := make([]string, len(fullProfileList))
|
||||
if len(profiles) != 0 {
|
||||
defaultProfile := app.storage.GetDefaultProfile()
|
||||
profiles[0] = defaultProfile.Name
|
||||
i := 1
|
||||
if len(app.storage.profiles) > 1 {
|
||||
for p := range app.storage.profiles {
|
||||
if p != app.storage.defaultProfile {
|
||||
profiles[i] = p
|
||||
if len(fullProfileList) > 1 {
|
||||
app.storage.db.ForEach(badgerhold.Where("Name").Ne(profiles[0]), func(p *Profile) error {
|
||||
profiles[i] = p.Name
|
||||
i++
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
resp := getInvitesDTO{
|
||||
@ -316,7 +318,7 @@ func (app *appContext) SetProfile(gc *gin.Context) {
|
||||
gc.BindJSON(&req)
|
||||
app.debug.Printf("%s: Setting profile to \"%s\"", req.Invite, req.Profile)
|
||||
// "" means "Don't apply profile"
|
||||
if _, ok := app.storage.profiles[req.Profile]; !ok && req.Profile != "" {
|
||||
if _, ok := app.storage.GetProfileKey(req.Profile); !ok && req.Profile != "" {
|
||||
app.err.Printf("%s: Profile \"%s\" not found", req.Invite, req.Profile)
|
||||
respond(500, "Profile not found", gc)
|
||||
return
|
||||
|
18
api-ombi.go
18
api-ombi.go
@ -71,7 +71,7 @@ func (app *appContext) SetOmbiProfile(gc *gin.Context) {
|
||||
var req ombiUser
|
||||
gc.BindJSON(&req)
|
||||
profileName := gc.Param("profile")
|
||||
profile, ok := app.storage.profiles[profileName]
|
||||
profile, ok := app.storage.GetProfileKey(profileName)
|
||||
if !ok {
|
||||
respondBool(400, false, gc)
|
||||
return
|
||||
@ -83,12 +83,7 @@ func (app *appContext) SetOmbiProfile(gc *gin.Context) {
|
||||
return
|
||||
}
|
||||
profile.Ombi = template
|
||||
app.storage.profiles[profileName] = profile
|
||||
if err := app.storage.storeProfiles(); err != nil {
|
||||
respond(500, "Failed to store profile", gc)
|
||||
app.err.Printf("Failed to store profiles: %v", err)
|
||||
return
|
||||
}
|
||||
app.storage.SetProfileKey(profileName, profile)
|
||||
respondBool(204, true, gc)
|
||||
}
|
||||
|
||||
@ -103,17 +98,12 @@ func (app *appContext) SetOmbiProfile(gc *gin.Context) {
|
||||
// @tags Ombi
|
||||
func (app *appContext) DeleteOmbiProfile(gc *gin.Context) {
|
||||
profileName := gc.Param("profile")
|
||||
profile, ok := app.storage.profiles[profileName]
|
||||
profile, ok := app.storage.GetProfileKey(profileName)
|
||||
if !ok {
|
||||
respondBool(400, false, gc)
|
||||
return
|
||||
}
|
||||
profile.Ombi = nil
|
||||
app.storage.profiles[profileName] = profile
|
||||
if err := app.storage.storeProfiles(); err != nil {
|
||||
respond(500, "Failed to store profile", gc)
|
||||
app.err.Printf("Failed to store profiles: %v", err)
|
||||
return
|
||||
}
|
||||
app.storage.SetProfileKey(profileName, profile)
|
||||
respondBool(204, true, gc)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/timshannon/badgerhold/v4"
|
||||
)
|
||||
|
||||
// @Summary Get a list of profiles
|
||||
@ -13,14 +14,13 @@ import (
|
||||
// @Security Bearer
|
||||
// @tags Profiles & Settings
|
||||
func (app *appContext) GetProfiles(gc *gin.Context) {
|
||||
app.storage.loadProfiles()
|
||||
app.debug.Println("Profiles requested")
|
||||
out := getProfilesDTO{
|
||||
DefaultProfile: app.storage.defaultProfile,
|
||||
DefaultProfile: app.storage.GetDefaultProfile().Name,
|
||||
Profiles: map[string]profileDTO{},
|
||||
}
|
||||
for name, p := range app.storage.profiles {
|
||||
out.Profiles[name] = profileDTO{
|
||||
for _, p := range app.storage.GetProfiles() {
|
||||
out.Profiles[p.Name] = profileDTO{
|
||||
Admin: p.Admin,
|
||||
LibraryAccess: p.LibraryAccess,
|
||||
FromUser: p.FromUser,
|
||||
@ -42,20 +42,20 @@ func (app *appContext) SetDefaultProfile(gc *gin.Context) {
|
||||
req := profileChangeDTO{}
|
||||
gc.BindJSON(&req)
|
||||
app.info.Printf("Setting default profile to \"%s\"", req.Name)
|
||||
if _, ok := app.storage.profiles[req.Name]; !ok {
|
||||
if _, ok := app.storage.GetProfileKey(req.Name); !ok {
|
||||
app.err.Printf("Profile not found: \"%s\"", req.Name)
|
||||
respond(500, "Profile not found", gc)
|
||||
return
|
||||
}
|
||||
for name, profile := range app.storage.profiles {
|
||||
if name == req.Name {
|
||||
profile.Admin = true
|
||||
app.storage.profiles[name] = profile
|
||||
app.storage.db.ForEach(&badgerhold.Query{}, func(profile *Profile) error {
|
||||
if profile.Name == req.Name {
|
||||
profile.Default = true
|
||||
} else {
|
||||
profile.Admin = false
|
||||
profile.Default = false
|
||||
}
|
||||
}
|
||||
app.storage.defaultProfile = req.Name
|
||||
app.storage.SetProfileKey(profile.Name, *profile)
|
||||
return nil
|
||||
})
|
||||
respondBool(200, true, gc)
|
||||
}
|
||||
|
||||
@ -92,10 +92,7 @@ func (app *appContext) CreateProfile(gc *gin.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
app.storage.loadProfiles()
|
||||
app.storage.profiles[req.Name] = profile
|
||||
app.storage.storeProfiles()
|
||||
app.storage.loadProfiles()
|
||||
app.storage.SetProfileKey(req.Name, profile)
|
||||
respondBool(200, true, gc)
|
||||
}
|
||||
|
||||
@ -110,12 +107,6 @@ func (app *appContext) DeleteProfile(gc *gin.Context) {
|
||||
req := profileChangeDTO{}
|
||||
gc.BindJSON(&req)
|
||||
name := req.Name
|
||||
if _, ok := app.storage.profiles[name]; ok {
|
||||
if app.storage.defaultProfile == name {
|
||||
app.storage.defaultProfile = ""
|
||||
}
|
||||
delete(app.storage.profiles, name)
|
||||
}
|
||||
app.storage.storeProfiles()
|
||||
app.storage.DeleteProfileKey(name)
|
||||
respondBool(200, true, gc)
|
||||
}
|
||||
|
18
api-users.go
18
api-users.go
@ -269,7 +269,6 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
||||
success = false
|
||||
return
|
||||
}
|
||||
app.storage.loadProfiles()
|
||||
invite, _ := app.storage.GetInvitesKey(req.Code)
|
||||
app.checkInvite(req.Code, true, req.Username)
|
||||
if emailEnabled && app.config.Section("notifications").Key("enabled").MustBool(false) {
|
||||
@ -301,9 +300,9 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
||||
if invite.Profile != "" {
|
||||
app.debug.Printf("Applying settings from profile \"%s\"", invite.Profile)
|
||||
var ok bool
|
||||
profile, ok = app.storage.profiles[invite.Profile]
|
||||
profile, ok = app.storage.GetProfileKey(invite.Profile)
|
||||
if !ok {
|
||||
profile = app.storage.profiles["Default"]
|
||||
profile = app.storage.GetDefaultProfile()
|
||||
}
|
||||
if profile.Policy.BlockedTags != nil {
|
||||
app.debug.Printf("Applying policy from profile \"%s\"", invite.Profile)
|
||||
@ -1008,25 +1007,24 @@ func (app *appContext) ApplySettings(gc *gin.Context) {
|
||||
var displayprefs map[string]interface{}
|
||||
var ombi map[string]interface{}
|
||||
if req.From == "profile" {
|
||||
app.storage.loadProfiles()
|
||||
// Check profile exists & isn't empty
|
||||
if _, ok := app.storage.profiles[req.Profile]; !ok || app.storage.profiles[req.Profile].Policy.BlockedTags == nil {
|
||||
profile, ok := app.storage.GetProfileKey(req.Profile)
|
||||
if !ok || profile.Policy.BlockedTags == nil {
|
||||
app.err.Printf("Couldn't find profile \"%s\" or profile was empty", req.Profile)
|
||||
respond(500, "Couldn't find profile", gc)
|
||||
return
|
||||
}
|
||||
if req.Homescreen {
|
||||
if app.storage.profiles[req.Profile].Configuration.GroupedFolders == nil || len(app.storage.profiles[req.Profile].Displayprefs) == 0 {
|
||||
if profile.Configuration.GroupedFolders == nil || len(profile.Displayprefs) == 0 {
|
||||
app.err.Printf("No homescreen saved in profile \"%s\"", req.Profile)
|
||||
respond(500, "No homescreen template available", gc)
|
||||
return
|
||||
}
|
||||
configuration = app.storage.profiles[req.Profile].Configuration
|
||||
displayprefs = app.storage.profiles[req.Profile].Displayprefs
|
||||
configuration = profile.Configuration
|
||||
displayprefs = profile.Displayprefs
|
||||
}
|
||||
policy = app.storage.profiles[req.Profile].Policy
|
||||
policy = profile.Policy
|
||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||
profile := app.storage.profiles[req.Profile]
|
||||
if profile.Ombi != nil && len(profile.Ombi) != 0 {
|
||||
ombi = profile.Ombi
|
||||
}
|
||||
|
@ -79,7 +79,7 @@
|
||||
"ombiProfile": "Ombi user profile",
|
||||
"ombiUserDefaultsDescription": "Create an Ombi user and configure it, then select it below. It's settings/permissions will be stored and applied to new Ombi users created by jfa-go when this profile is selected.",
|
||||
"userProfiles": "User Profiles",
|
||||
"userProfilesDescription": "Profiles are applied to users when they create an account. A profile include library access rights and homescreen layout.",
|
||||
"userProfilesDescription": "Profiles are applied to users when they create an account. A profile includes library access rights and homescreen layout.",
|
||||
"userProfilesIsDefault": "Default",
|
||||
"userProfilesLibraries": "Libraries",
|
||||
"addProfile": "Add Profile",
|
||||
|
@ -236,6 +236,11 @@ func migrateToBadger(app *appContext) {
|
||||
for k, v := range app.storage.deprecatedUserExpiries {
|
||||
app.storage.SetUserExpiryKey(k, UserExpiry{Expiry: v})
|
||||
}
|
||||
|
||||
app.storage.loadProfiles()
|
||||
for k, v := range app.storage.profiles {
|
||||
app.storage.SetProfileKey(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate between hyphenated & non-hyphenated user IDs. Doesn't seem to happen anymore, so disabled.
|
||||
|
60
storage.go
60
storage.go
@ -312,6 +312,63 @@ func (st *Storage) DeleteUserExpiryKey(k string) {
|
||||
st.db.Delete(k, UserExpiry{})
|
||||
}
|
||||
|
||||
// GetProfiles returns a copy of the store.
|
||||
func (st *Storage) GetProfiles() []Profile {
|
||||
result := []Profile{}
|
||||
err := st.db.Find(&result, &badgerhold.Query{})
|
||||
if err != nil {
|
||||
// fmt.Printf("Failed to find profiles: %v\n", err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// GetProfileKey returns the value stored in the store's key.
|
||||
func (st *Storage) GetProfileKey(k string) (Profile, bool) {
|
||||
result := Profile{}
|
||||
err := st.db.Get(k, &result)
|
||||
ok := true
|
||||
if err != nil {
|
||||
// fmt.Printf("Failed to find profile: %v\n", err)
|
||||
ok = false
|
||||
}
|
||||
return result, ok
|
||||
}
|
||||
|
||||
// SetProfileKey stores value v in key k.
|
||||
func (st *Storage) SetProfileKey(k string, v Profile) {
|
||||
v.Name = k
|
||||
v.Admin = v.Policy.IsAdministrator
|
||||
if v.Policy.EnabledFolders != nil {
|
||||
if len(v.Policy.EnabledFolders) == 0 {
|
||||
v.LibraryAccess = "All"
|
||||
} else {
|
||||
v.LibraryAccess = strconv.Itoa(len(v.Policy.EnabledFolders))
|
||||
}
|
||||
}
|
||||
if v.FromUser == "" {
|
||||
v.FromUser = "Unknown"
|
||||
}
|
||||
err := st.db.Upsert(k, v)
|
||||
if err != nil {
|
||||
// fmt.Printf("Failed to set profile: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteProfileKey deletes value at key k.
|
||||
func (st *Storage) DeleteProfileKey(k string) {
|
||||
st.db.Delete(k, Profile{})
|
||||
}
|
||||
|
||||
// GetDefaultProfile returns the first profile set as default, or anything available if there isn't one.
|
||||
func (st *Storage) GetDefaultProfile() Profile {
|
||||
defaultProfile := Profile{}
|
||||
err := st.db.FindOne(&defaultProfile, badgerhold.Where("Default").Eq(true))
|
||||
if err != nil {
|
||||
st.db.FindOne(&defaultProfile, &badgerhold.Query{})
|
||||
}
|
||||
return defaultProfile
|
||||
}
|
||||
|
||||
type TelegramUser struct {
|
||||
JellyfinID string `badgerhold:"key"`
|
||||
ChatID int64 `badgerhold:"index"`
|
||||
@ -366,7 +423,8 @@ type userPageContent struct {
|
||||
// timePattern: %Y-%m-%dT%H:%M:%S.%f
|
||||
|
||||
type Profile struct {
|
||||
Admin bool `json:"admin,omitempty"`
|
||||
Name string `badgerhold:"key"`
|
||||
Admin bool `json:"admin,omitempty" badgerhold:"index"`
|
||||
LibraryAccess string `json:"libraries,omitempty"`
|
||||
FromUser string `json:"fromUser,omitempty"`
|
||||
Policy mediabrowser.Policy `json:"policy,omitempty"`
|
||||
|
Loading…
Reference in New Issue
Block a user