Ungroup files #356
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
b12f916e69
commit
15a5fd3c37
|
@ -48,7 +48,7 @@
|
|||
</td>
|
||||
<td>
|
||||
<v-btn small depressed dark color="secondary-dark" class="ma-0 action-primary"
|
||||
@click.stop.prevent="setPrimary(file)">
|
||||
@click.stop.prevent="primary(file)">
|
||||
<translate>Primary</translate>
|
||||
</v-btn>
|
||||
<v-btn small depressed dark color="secondary-dark" class="ma-0 action-ungroup"
|
||||
|
@ -173,10 +173,10 @@
|
|||
this.$viewer.show([Thumb.fromFile(this.model, file)], 0);
|
||||
},
|
||||
ungroup(file) {
|
||||
|
||||
this.model.ungroupFile(file.UID);
|
||||
},
|
||||
setPrimary(file) {
|
||||
this.model.setPrimary(file.UID);
|
||||
primary(file) {
|
||||
this.model.primaryFile(file.UID);
|
||||
},
|
||||
formatTime(s) {
|
||||
return DateTime.fromISO(s).toHTTP();
|
||||
|
|
|
@ -510,8 +510,12 @@ export class Photo extends RestModel {
|
|||
return Api.put(this.getEntityResource(), {Private: this.Private});
|
||||
}
|
||||
|
||||
setPrimary(uid) {
|
||||
return Api.post(this.getEntityResource() + "/primary/" + uid).then((r) => Promise.resolve(this.setValues(r.data)));
|
||||
primaryFile(fileUID) {
|
||||
return Api.post(`${this.getEntityResource()}/files/${fileUID}/primary`).then((r) => Promise.resolve(this.setValues(r.data)));
|
||||
}
|
||||
|
||||
ungroupFile(fileUID) {
|
||||
return Api.post(`${this.getEntityResource()}/files/${fileUID}/ungroup`).then((r) => Promise.resolve(this.setValues(r.data)));
|
||||
}
|
||||
|
||||
like() {
|
||||
|
|
|
@ -294,12 +294,13 @@ func DislikePhoto(router *gin.RouterGroup) {
|
|||
})
|
||||
}
|
||||
|
||||
// POST /api/v1/photos/:uid/primary/:file_uid
|
||||
// POST /api/v1/photos/:uid/files/:file_uid/primary
|
||||
//
|
||||
// Parameters:
|
||||
// uid: string PhotoUID as returned by the API
|
||||
func SetPhotoPrimary(router *gin.RouterGroup) {
|
||||
router.POST("/photos/:uid/primary/:file_uid", func(c *gin.Context) {
|
||||
// file_uid: string File UID as returned by the API
|
||||
func PhotoFilePrimary(router *gin.RouterGroup) {
|
||||
router.POST("/photos/:uid/files/:file_uid/primary", func(c *gin.Context) {
|
||||
s := Auth(SessionID(c), acl.ResourcePhotos, acl.ActionUpdate)
|
||||
|
||||
if s.Invalid() {
|
||||
|
@ -330,3 +331,85 @@ func SetPhotoPrimary(router *gin.RouterGroup) {
|
|||
c.JSON(http.StatusOK, p)
|
||||
})
|
||||
}
|
||||
|
||||
// POST /api/v1/photos/:uid/files/:file_uid/ungroup
|
||||
//
|
||||
// Parameters:
|
||||
// uid: string Photo UID as returned by the API
|
||||
// file_uid: string File UID as returned by the API
|
||||
func PhotoFileUngroup(router *gin.RouterGroup) {
|
||||
router.POST("/photos/:uid/files/:file_uid/ungroup", func(c *gin.Context) {
|
||||
s := Auth(SessionID(c), acl.ResourcePhotos, acl.ActionUpdate)
|
||||
|
||||
if s.Invalid() {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
photoUID := c.Param("uid")
|
||||
fileUID := c.Param("file_uid")
|
||||
|
||||
file, err := query.FileByUID(fileUID)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("photo: %s (ungroup)", err)
|
||||
c.AbortWithStatusJSON(http.StatusNotFound, ErrFileNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if file.FilePrimary {
|
||||
log.Errorf("photo: can't ungroup primary files")
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, ErrFormInvalid)
|
||||
return
|
||||
}
|
||||
|
||||
existingPhoto := *file.Photo
|
||||
newPhoto := entity.NewPhoto()
|
||||
|
||||
if err := entity.UnscopedDb().Create(&newPhoto).Error; err != nil {
|
||||
log.Errorf("photo: %s", err.Error())
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed)
|
||||
return
|
||||
}
|
||||
|
||||
file.Photo = &newPhoto
|
||||
file.PhotoID = newPhoto.ID
|
||||
file.PhotoUID = newPhoto.PhotoUID
|
||||
|
||||
if err := file.Save(); err != nil {
|
||||
log.Errorf("photo: %s", err.Error())
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed)
|
||||
return
|
||||
}
|
||||
|
||||
fileName := photoprism.FileName(file.FileRoot, file.FileName)
|
||||
|
||||
f, err := photoprism.NewMediaFile(fileName)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("photo: %s (ungroup)", err)
|
||||
c.AbortWithStatusJSON(http.StatusNotFound, ErrFileNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.Index().MediaFile(f, photoprism.IndexOptions{Rescan: true}, existingPhoto.OriginalName).Error; err != nil {
|
||||
log.Errorf("photo: %s", err)
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, ErrSaveFailed)
|
||||
return
|
||||
}
|
||||
|
||||
PublishPhotoEvent(EntityCreated, file.PhotoUID, c)
|
||||
PublishPhotoEvent(EntityUpdated, photoUID, c)
|
||||
|
||||
event.Success("file ungrouped")
|
||||
|
||||
p, err := query.PhotoPreloadByUID(photoUID)
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusNotFound, ErrPhotoNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, p)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -114,8 +114,8 @@ func TestDislikePhoto(t *testing.T) {
|
|||
func TestSetPhotoPrimary(t *testing.T) {
|
||||
t.Run("existing photo", func(t *testing.T) {
|
||||
app, router, _ := NewApiTest()
|
||||
SetPhotoPrimary(router)
|
||||
r := PerformRequest(app, "POST", "/api/v1/photos/pt9jtdre2lvl0yh8/primary/ft1es39w45bnlqdw")
|
||||
PhotoFilePrimary(router)
|
||||
r := PerformRequest(app, "POST", "/api/v1/photos/pt9jtdre2lvl0yh8/files/ft1es39w45bnlqdw/primary")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
GetFile(router)
|
||||
r2 := PerformRequest(app, "GET", "/api/v1/files/ocad9168fa6acc5c5c2965ddf6ec465ca42fd818")
|
||||
|
@ -128,8 +128,8 @@ func TestSetPhotoPrimary(t *testing.T) {
|
|||
|
||||
t.Run("wrong photo uid", func(t *testing.T) {
|
||||
app, router, _ := NewApiTest()
|
||||
SetPhotoPrimary(router)
|
||||
r := PerformRequest(app, "POST", "/api/v1/photos/xxx/primary/ft1es39w45bnlqdw")
|
||||
PhotoFilePrimary(router)
|
||||
r := PerformRequest(app, "POST", "/api/v1/photos/xxx/files/ft1es39w45bnlqdw/primary")
|
||||
val := gjson.Get(r.Body.String(), "error")
|
||||
assert.Equal(t, "Photo not found", val.String())
|
||||
assert.Equal(t, http.StatusNotFound, r.Code)
|
||||
|
|
|
@ -55,7 +55,8 @@ func registerRoutes(router *gin.Engine, conf *config.Config) {
|
|||
api.UpdatePhotoLabel(v1)
|
||||
api.GetMomentsTime(v1)
|
||||
api.GetFile(v1)
|
||||
api.SetPhotoPrimary(v1)
|
||||
api.PhotoFilePrimary(v1)
|
||||
api.PhotoFileUngroup(v1)
|
||||
|
||||
api.GetLabels(v1)
|
||||
api.UpdateLabel(v1)
|
||||
|
|
Loading…
Reference in a new issue