mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-12 00:34:13 +01:00
Albums: Save sort order and description
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
@@ -39,7 +39,7 @@
|
||||
<v-icon>view_column</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<v-btn icon @click.stop="searchExpanded = !searchExpanded" class="p-expand-search">
|
||||
<v-btn icon @click.stop="expand" class="p-expand-search">
|
||||
<v-icon>{{ searchExpanded ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
@@ -48,7 +48,7 @@
|
||||
flat
|
||||
color="secondary-light"
|
||||
v-show="searchExpanded">
|
||||
<v-card-text>
|
||||
<v-card-text class="pb-0">
|
||||
<v-layout row wrap>
|
||||
<v-flex xs12 pa-2>
|
||||
<v-text-field flat solo hide-details
|
||||
@@ -103,6 +103,17 @@
|
||||
:items="options.sorting">
|
||||
</v-select>
|
||||
</v-flex>
|
||||
<v-flex xs12 pt-2 px-2>
|
||||
<v-textarea flat solo auto-grow autofocus
|
||||
browser-autocomplete="off"
|
||||
:label="labels.description"
|
||||
:rows="2"
|
||||
:key="growDesc"
|
||||
color="secondary-dark"
|
||||
v-model="album.AlbumDescription"
|
||||
@change="updateAlbum">
|
||||
</v-textarea>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
@@ -146,6 +157,7 @@
|
||||
],
|
||||
},
|
||||
labels: {
|
||||
description: this.$gettext("Description"),
|
||||
search: this.$gettext("Search"),
|
||||
view: this.$gettext("View"),
|
||||
country: this.$gettext("Country"),
|
||||
@@ -154,15 +166,28 @@
|
||||
name: this.$gettext("Album Name"),
|
||||
},
|
||||
titleRule: v => v.length <= 25 || this.$gettext("Title too long"),
|
||||
growDesc: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
expand() {
|
||||
this.searchExpanded = !this.searchExpanded;
|
||||
this.growDesc = !this.growDesc;
|
||||
},
|
||||
updateAlbum() {
|
||||
this.album.update()
|
||||
},
|
||||
dropdownChange() {
|
||||
this.filterChange();
|
||||
|
||||
if (window.innerWidth < 600) {
|
||||
this.searchExpanded = false;
|
||||
}
|
||||
|
||||
if (this.filter.order !== this.album.AlbumOrder) {
|
||||
this.album.AlbumOrder = this.filter.order;
|
||||
this.updateAlbum()
|
||||
}
|
||||
},
|
||||
setView(name) {
|
||||
this.settings.view = name;
|
||||
|
||||
@@ -271,9 +271,12 @@
|
||||
});
|
||||
},
|
||||
findAlbum() {
|
||||
this.model.find(this.uuid).then(m => {
|
||||
return this.model.find(this.uuid).then(m => {
|
||||
this.model = m;
|
||||
this.filter.order = m.AlbumOrder;
|
||||
window.document.title = `PhotoPrism: ${this.model.AlbumName}`;
|
||||
|
||||
return Promise.resolve(this.model)
|
||||
});
|
||||
},
|
||||
onAlbumsUpdated(ev, data) {
|
||||
@@ -347,8 +350,7 @@
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.findAlbum();
|
||||
this.search();
|
||||
this.findAlbum().then(() => this.search());
|
||||
|
||||
this.subscriptions.push(Event.subscribe("albums.updated", (ev, data) => this.onAlbumsUpdated(ev, data)));
|
||||
this.subscriptions.push(Event.subscribe("photos", (ev, data) => this.onUpdate(ev, data)));
|
||||
|
||||
@@ -214,19 +214,22 @@ func UpdateAccount(router *gin.RouterGroup, conf *config.Config) {
|
||||
f, err := form.NewAccount(m)
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": txt.UcFirst(err.Error())})
|
||||
log.Error(err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed)
|
||||
return
|
||||
}
|
||||
|
||||
// 2) Update form with values from request
|
||||
if err := c.BindJSON(&f); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": txt.UcFirst(err.Error())})
|
||||
log.Error(err)
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, ErrFormInvalid)
|
||||
return
|
||||
}
|
||||
|
||||
// 3) Save model with values from form
|
||||
if err := m.Save(f, conf.Db()); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": txt.UcFirst(err.Error())})
|
||||
log.Error(err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -117,30 +117,41 @@ func UpdateAlbum(router *gin.RouterGroup, conf *config.Config) {
|
||||
return
|
||||
}
|
||||
|
||||
var f form.Album
|
||||
db := conf.Db()
|
||||
uuid := c.Param("uuid")
|
||||
q := query.New(db)
|
||||
|
||||
if err := c.BindJSON(&f); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": txt.UcFirst(err.Error())})
|
||||
return
|
||||
}
|
||||
|
||||
id := c.Param("uuid")
|
||||
q := query.New(conf.Db())
|
||||
|
||||
m, err := q.AlbumByUUID(id)
|
||||
m, err := q.AlbumByUUID(uuid)
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusNotFound, ErrAlbumNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
m.Rename(f.AlbumName)
|
||||
conf.Db().Save(&m)
|
||||
f, err := form.NewAlbum(m)
|
||||
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed)
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.BindJSON(&f); err != nil {
|
||||
log.Error(err)
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, ErrFormInvalid)
|
||||
return
|
||||
}
|
||||
|
||||
if err := m.Save(f, conf.Db()); err != nil {
|
||||
log.Error(err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed)
|
||||
return
|
||||
}
|
||||
|
||||
event.Publish("config.updated", event.Data(conf.ClientConfig()))
|
||||
event.Success("album saved")
|
||||
|
||||
PublishAlbumEvent(EntityUpdated, id, c, q)
|
||||
PublishAlbumEvent(EntityUpdated, uuid, c, q)
|
||||
|
||||
c.JSON(http.StatusOK, m)
|
||||
})
|
||||
|
||||
@@ -18,5 +18,7 @@ var (
|
||||
ErrPhotoNotFound = gin.H{"code": http.StatusNotFound, "error": "Photo not found"}
|
||||
ErrLabelNotFound = gin.H{"code": http.StatusNotFound, "error": "Label not found"}
|
||||
ErrUnexpectedError = gin.H{"code": http.StatusInternalServerError, "error": "Unexpected error"}
|
||||
ErrSaveFailed = gin.H{"code": http.StatusInternalServerError, "error": "Save failed - database error?"}
|
||||
ErrSaveFailed = gin.H{"code": http.StatusInternalServerError, "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"}
|
||||
)
|
||||
|
||||
@@ -21,13 +21,13 @@ import (
|
||||
// POST /api/v1/import*
|
||||
func StartImport(router *gin.RouterGroup, conf *config.Config) {
|
||||
router.POST("/import/*path", func(c *gin.Context) {
|
||||
if conf.ReadOnly() || !conf.Settings().Features.Import {
|
||||
c.AbortWithStatusJSON(http.StatusForbidden, ErrReadOnly)
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if Unauthorized(c, conf) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
if conf.ReadOnly() || !conf.Settings().Features.Import {
|
||||
c.AbortWithStatusJSON(http.StatusForbidden, ErrFeatureDisabled)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/internal/query"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
// GET /api/v1/photos/:uuid
|
||||
@@ -46,8 +45,9 @@ func UpdatePhoto(router *gin.RouterGroup, conf *config.Config) {
|
||||
return
|
||||
}
|
||||
|
||||
db := conf.Db()
|
||||
uuid := c.Param("uuid")
|
||||
q := query.New(conf.Db())
|
||||
q := query.New(db)
|
||||
|
||||
m, err := q.PhotoByUUID(uuid)
|
||||
|
||||
@@ -61,19 +61,22 @@ func UpdatePhoto(router *gin.RouterGroup, conf *config.Config) {
|
||||
f, err := form.NewPhoto(m)
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": txt.UcFirst(err.Error())})
|
||||
log.Error(err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed)
|
||||
return
|
||||
}
|
||||
|
||||
// 2) Update form with values from request
|
||||
if err := c.BindJSON(&f); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": txt.UcFirst(err.Error())})
|
||||
log.Error(err)
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, ErrFormInvalid)
|
||||
return
|
||||
}
|
||||
|
||||
// 3) Save model with values from form
|
||||
if err := entity.SavePhotoForm(m, f, conf.Db(), conf.GeoCodingApi()); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": txt.UcFirst(err.Error())})
|
||||
if err := entity.SavePhotoForm(m, f, db, conf.GeoCodingApi()); err != nil {
|
||||
log.Error(err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,11 @@ func CreateZip(router *gin.RouterGroup, conf *config.Config) {
|
||||
return
|
||||
}
|
||||
|
||||
if !conf.Settings().Features.Download {
|
||||
c.AbortWithStatusJSON(http.StatusForbidden, ErrFeatureDisabled)
|
||||
return
|
||||
}
|
||||
|
||||
var f form.Selection
|
||||
start := time.Now()
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ import (
|
||||
|
||||
"github.com/gosimple/slug"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
"github.com/ulule/deepcopier"
|
||||
)
|
||||
|
||||
// Album represents a photo album
|
||||
@@ -63,3 +65,16 @@ func (m *Album) Rename(albumName string) {
|
||||
m.AlbumName = strings.TrimSpace(albumName)
|
||||
m.AlbumSlug = slug.Make(m.AlbumName)
|
||||
}
|
||||
|
||||
// Save updates the entity using form data and stores it in the database.
|
||||
func (m *Album) Save(f form.Album, db *gorm.DB) error {
|
||||
if err := deepcopier.Copy(m).From(f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.AlbumName != "" {
|
||||
m.Rename(f.AlbumName)
|
||||
}
|
||||
|
||||
return db.Save(m).Error
|
||||
}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
package form
|
||||
|
||||
import "github.com/ulule/deepcopier"
|
||||
|
||||
// Album represents an album edit form.
|
||||
type Album struct {
|
||||
AlbumName string `json:"AlbumName"`
|
||||
AlbumDescription string `json:"AlbumDescription"`
|
||||
AlbumNotes string `json:"AlbumNotes"`
|
||||
AlbumFavorite bool `json:"AlbumFavorite"`
|
||||
AlbumPublic bool `json:"AlbumPublic"`
|
||||
AlbumOrder string `json:"AlbumOrder"`
|
||||
AlbumTemplate string `json:"AlbumTemplate"`
|
||||
AlbumFavorite bool `json:"AlbumFavorite"`
|
||||
}
|
||||
|
||||
func NewAlbum(m interface{}) (f Album, err error) {
|
||||
err = deepcopier.Copy(m).To(&f)
|
||||
|
||||
return f, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user