Disable account page in public mode
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
56cf8e95e0
commit
0e426a547b
9 changed files with 42 additions and 16 deletions
|
@ -17,7 +17,7 @@
|
||||||
<translate key="Sync">Sync</translate>
|
<translate key="Sync">Sync</translate>
|
||||||
</v-tab>
|
</v-tab>
|
||||||
|
|
||||||
<v-tab id="tab-settings-account" ripple @click="changePath('/settings/account')">
|
<v-tab id="tab-settings-account" ripple @click="changePath('/settings/account')" v-if="!public">
|
||||||
<translate key="Account">Account</translate>
|
<translate key="Account">Account</translate>
|
||||||
</v-tab>
|
</v-tab>
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
<v-tab-item lazy>
|
<v-tab-item lazy>
|
||||||
<p-settings-sync></p-settings-sync>
|
<p-settings-sync></p-settings-sync>
|
||||||
</v-tab-item>
|
</v-tab-item>
|
||||||
<v-tab-item lazy>
|
<v-tab-item lazy v-if="!public">
|
||||||
<p-settings-account></p-settings-account>
|
<p-settings-account></p-settings-account>
|
||||||
</v-tab-item>
|
</v-tab-item>
|
||||||
</v-tabs-items>
|
</v-tabs-items>
|
||||||
|
@ -53,6 +53,7 @@
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
public: this.$config.get("public"),
|
||||||
readonly: this.$config.get("readonly"),
|
readonly: this.$config.get("readonly"),
|
||||||
active: this.tab,
|
active: this.tab,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<v-layout wrap align-top>
|
<v-layout wrap align-top>
|
||||||
<v-flex xs12 class="px-2 pt-2 pb-4">
|
<v-flex xs12 class="px-2 pt-2 pb-4">
|
||||||
<v-text-field
|
<v-text-field
|
||||||
hide-details
|
hide-details required
|
||||||
:disabled="busy"
|
:disabled="busy"
|
||||||
browser-autocomplete="off"
|
browser-autocomplete="off"
|
||||||
label="Current Password"
|
label="Current Password"
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
<v-flex xs12 class="pa-2">
|
<v-flex xs12 class="pa-2">
|
||||||
<v-text-field
|
<v-text-field
|
||||||
hide-details
|
hide-details required
|
||||||
:disabled="busy"
|
:disabled="busy"
|
||||||
browser-autocomplete="off"
|
browser-autocomplete="off"
|
||||||
label="New Password"
|
label="New Password"
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
<v-flex xs12 class="pa-2">
|
<v-flex xs12 class="pa-2">
|
||||||
<v-text-field
|
<v-text-field
|
||||||
hide-details
|
hide-details required
|
||||||
:disabled="busy"
|
:disabled="busy"
|
||||||
browser-autocomplete="off"
|
browser-autocomplete="off"
|
||||||
label="Confirm Password"
|
label="Confirm Password"
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
</v-flex>
|
</v-flex>
|
||||||
<v-flex xs12 text-xs-left class="px-2 pt-4 pb-2">
|
<v-flex xs12 text-xs-left class="px-2 pt-4 pb-2">
|
||||||
<v-btn depressed dark color="secondary-dark" @click.stop="confirm"
|
<v-btn depressed dark color="secondary-dark" @click.stop="confirm"
|
||||||
class="action-confirm ma-0">
|
class="action-confirm ma-0" :disabled="busy">
|
||||||
<translate>Change Password</translate>
|
<translate>Change Password</translate>
|
||||||
<v-icon right dark>vpn_key</v-icon>
|
<v-icon right dark>vpn_key</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
@ -70,6 +70,9 @@
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
disabled() {
|
||||||
|
return (this.oldPassword === "" || this.newPassword === "" || (this.newPassword !== this.confirmPassword));
|
||||||
|
},
|
||||||
confirm() {
|
confirm() {
|
||||||
this.busy = true;
|
this.busy = true;
|
||||||
this.$session.getUser().changePassword(this.oldPassword, this.newPassword).then(() => {
|
this.$session.getUser().changePassword(this.oldPassword, this.newPassword).then(() => {
|
||||||
|
|
|
@ -12,6 +12,7 @@ var (
|
||||||
ErrUnauthorized = gin.H{"code": http.StatusUnauthorized, "error": txt.UcFirst(config.ErrUnauthorized.Error())}
|
ErrUnauthorized = gin.H{"code": http.StatusUnauthorized, "error": txt.UcFirst(config.ErrUnauthorized.Error())}
|
||||||
ErrReadOnly = gin.H{"code": http.StatusForbidden, "error": txt.UcFirst(config.ErrReadOnly.Error())}
|
ErrReadOnly = gin.H{"code": http.StatusForbidden, "error": txt.UcFirst(config.ErrReadOnly.Error())}
|
||||||
ErrUploadNSFW = gin.H{"code": http.StatusForbidden, "error": txt.UcFirst(config.ErrUploadNSFW.Error())}
|
ErrUploadNSFW = gin.H{"code": http.StatusForbidden, "error": txt.UcFirst(config.ErrUploadNSFW.Error())}
|
||||||
|
ErrPublic = gin.H{"code": http.StatusForbidden, "error": "Not available in public mode"}
|
||||||
ErrAccountNotFound = gin.H{"code": http.StatusNotFound, "error": "Account not found"}
|
ErrAccountNotFound = gin.H{"code": http.StatusNotFound, "error": "Account not found"}
|
||||||
ErrConnectionFailed = gin.H{"code": http.StatusConflict, "error": "Failed to connect"}
|
ErrConnectionFailed = gin.H{"code": http.StatusConflict, "error": "Failed to connect"}
|
||||||
ErrAlbumNotFound = gin.H{"code": http.StatusNotFound, "error": "Album not found"}
|
ErrAlbumNotFound = gin.H{"code": http.StatusNotFound, "error": "Album not found"}
|
||||||
|
@ -25,4 +26,5 @@ var (
|
||||||
ErrFormInvalid = gin.H{"code": http.StatusBadRequest, "error": "Changes could not be saved"}
|
ErrFormInvalid = gin.H{"code": http.StatusBadRequest, "error": "Changes could not be saved"}
|
||||||
ErrFeatureDisabled = gin.H{"code": http.StatusForbidden, "error": "Feature disabled"}
|
ErrFeatureDisabled = gin.H{"code": http.StatusForbidden, "error": "Feature disabled"}
|
||||||
ErrNotFound = gin.H{"code": http.StatusNotFound, "error": "Not found"}
|
ErrNotFound = gin.H{"code": http.StatusNotFound, "error": "Not found"}
|
||||||
|
ErrInvalidPassword = gin.H{"code": http.StatusBadRequest, "error": "Invalid password"}
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,11 +7,19 @@ import (
|
||||||
"github.com/photoprism/photoprism/internal/acl"
|
"github.com/photoprism/photoprism/internal/acl"
|
||||||
"github.com/photoprism/photoprism/internal/entity"
|
"github.com/photoprism/photoprism/internal/entity"
|
||||||
"github.com/photoprism/photoprism/internal/form"
|
"github.com/photoprism/photoprism/internal/form"
|
||||||
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PUT /api/v1/users/:uid/password
|
// PUT /api/v1/users/:uid/password
|
||||||
func ChangePassword(router *gin.RouterGroup) {
|
func ChangePassword(router *gin.RouterGroup) {
|
||||||
router.PUT("/users/:uid/password", func(c *gin.Context) {
|
router.PUT("/users/:uid/password", func(c *gin.Context) {
|
||||||
|
conf := service.Config()
|
||||||
|
|
||||||
|
if conf.Public() {
|
||||||
|
c.AbortWithStatusJSON(http.StatusForbidden, ErrPublic)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s := Auth(SessionID(c), acl.ResourcePeople, acl.ActionUpdateSelf)
|
s := Auth(SessionID(c), acl.ResourcePeople, acl.ActionUpdateSelf)
|
||||||
|
|
||||||
if s.Invalid() {
|
if s.Invalid() {
|
||||||
|
@ -23,24 +31,27 @@ func ChangePassword(router *gin.RouterGroup) {
|
||||||
m := entity.FindPersonByUID(uid)
|
m := entity.FindPersonByUID(uid)
|
||||||
|
|
||||||
if m == nil {
|
if m == nil {
|
||||||
c.AbortWithStatusJSON(http.StatusNotFound, ErrPhotoNotFound)
|
log.Errorf("change password: user not found")
|
||||||
|
c.AbortWithStatusJSON(http.StatusNotFound, ErrInvalidPassword)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f := form.ChangePassword{}
|
f := form.ChangePassword{}
|
||||||
|
|
||||||
if err := c.BindJSON(&f); err != nil {
|
if err := c.BindJSON(&f); err != nil {
|
||||||
log.Errorf("user: %s", err.Error())
|
log.Errorf("change password: %s", err)
|
||||||
c.AbortWithStatusJSON(http.StatusBadRequest, ErrFormInvalid)
|
c.AbortWithStatusJSON(http.StatusBadRequest, ErrInvalidPassword)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.InvalidPassword(f.OldPassword) {
|
if m.InvalidPassword(f.OldPassword) {
|
||||||
c.AbortWithStatusJSON(http.StatusBadRequest, ErrFormInvalid)
|
log.Errorf("change password: invalid password")
|
||||||
|
c.AbortWithStatusJSON(http.StatusBadRequest, ErrInvalidPassword)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := m.SetPassword(f.NewPassword); err != nil {
|
if err := m.SetPassword(f.NewPassword); err != nil {
|
||||||
|
log.Errorf("change password: %s", err)
|
||||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": err.Error()})
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,10 +180,6 @@ func (c *Config) UploadNSFW() bool {
|
||||||
|
|
||||||
// AdminPassword returns the initial admin password.
|
// AdminPassword returns the initial admin password.
|
||||||
func (c *Config) AdminPassword() string {
|
func (c *Config) AdminPassword() string {
|
||||||
if c.params.AdminPassword == "" {
|
|
||||||
return "photoprism"
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.params.AdminPassword
|
return c.params.AdminPassword
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ var GlobalFlags = []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "admin-password",
|
Name: "admin-password",
|
||||||
Usage: "initial admin password (can be changed in settings)",
|
Usage: "initial admin password (can be changed in settings)",
|
||||||
Value: "photoprism",
|
|
||||||
EnvVar: "PHOTOPRISM_ADMIN_PASSWORD",
|
EnvVar: "PHOTOPRISM_ADMIN_PASSWORD",
|
||||||
},
|
},
|
||||||
cli.IntFlag{
|
cli.IntFlag{
|
||||||
|
|
|
@ -72,6 +72,7 @@ func NewTestParams() *Params {
|
||||||
SettingsPath: testDataPath + "/settings",
|
SettingsPath: testDataPath + "/settings",
|
||||||
DatabaseDriver: dbDriver,
|
DatabaseDriver: dbDriver,
|
||||||
DatabaseDsn: dbDsn,
|
DatabaseDsn: dbDsn,
|
||||||
|
AdminPassword: "photoprism",
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
|
@ -172,6 +173,7 @@ func CliTestContext() *cli.Context {
|
||||||
globalSet.String("temp-path", config.OriginalsPath, "doc")
|
globalSet.String("temp-path", config.OriginalsPath, "doc")
|
||||||
globalSet.String("cache-path", config.OriginalsPath, "doc")
|
globalSet.String("cache-path", config.OriginalsPath, "doc")
|
||||||
globalSet.String("darktable-cli", config.DarktableBin, "doc")
|
globalSet.String("darktable-cli", config.DarktableBin, "doc")
|
||||||
|
globalSet.String("admin-password", config.DarktableBin, "doc")
|
||||||
globalSet.Bool("detect-nsfw", config.DetectNSFW, "doc")
|
globalSet.Bool("detect-nsfw", config.DetectNSFW, "doc")
|
||||||
|
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
|
@ -187,6 +189,7 @@ func CliTestContext() *cli.Context {
|
||||||
LogError(c.Set("temp-path", config.TempPath))
|
LogError(c.Set("temp-path", config.TempPath))
|
||||||
LogError(c.Set("cache-path", config.CachePath))
|
LogError(c.Set("cache-path", config.CachePath))
|
||||||
LogError(c.Set("darktable-cli", config.DarktableBin))
|
LogError(c.Set("darktable-cli", config.DarktableBin))
|
||||||
|
LogError(c.Set("admin-password", config.AdminPassword))
|
||||||
LogError(c.Set("detect-nsfw", "true"))
|
LogError(c.Set("detect-nsfw", "true"))
|
||||||
|
|
||||||
return c
|
return c
|
||||||
|
|
|
@ -2,6 +2,10 @@ package entity
|
||||||
|
|
||||||
// CreateTestFixtures inserts all known entities into the database for testing.
|
// CreateTestFixtures inserts all known entities into the database for testing.
|
||||||
func CreateTestFixtures() {
|
func CreateTestFixtures() {
|
||||||
|
if err := Admin.SetPassword("photoprism"); err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
CreateLabelFixtures()
|
CreateLabelFixtures()
|
||||||
CreateCameraFixtures()
|
CreateCameraFixtures()
|
||||||
CreateCountryFixtures()
|
CreateCountryFixtures()
|
||||||
|
|
|
@ -83,7 +83,6 @@ var Guest = Person{
|
||||||
func CreateDefaultUsers() {
|
func CreateDefaultUsers() {
|
||||||
if user := FirstOrCreatePerson(&Admin); user != nil {
|
if user := FirstOrCreatePerson(&Admin); user != nil {
|
||||||
Admin = *user
|
Admin = *user
|
||||||
Admin.InitPassword("photoprism")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if user := FirstOrCreatePerson(&UnknownPerson); user != nil {
|
if user := FirstOrCreatePerson(&UnknownPerson); user != nil {
|
||||||
|
@ -211,6 +210,10 @@ func (m *Person) InitPassword(password string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if password == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
existing := FindPassword(m.PersonUID)
|
existing := FindPassword(m.PersonUID)
|
||||||
|
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
|
@ -231,6 +234,10 @@ func (m *Person) InvalidPassword(password string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if password == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
pw := FindPassword(m.PersonUID)
|
pw := FindPassword(m.PersonUID)
|
||||||
|
|
||||||
if pw == nil {
|
if pw == nil {
|
||||||
|
|
Loading…
Reference in a new issue