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>
|
||||||
<td>
|
<td>
|
||||||
<v-btn small depressed dark color="secondary-dark" class="ma-0 action-primary"
|
<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>
|
<translate>Primary</translate>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn small depressed dark color="secondary-dark" class="ma-0 action-ungroup"
|
<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);
|
this.$viewer.show([Thumb.fromFile(this.model, file)], 0);
|
||||||
},
|
},
|
||||||
ungroup(file) {
|
ungroup(file) {
|
||||||
|
this.model.ungroupFile(file.UID);
|
||||||
},
|
},
|
||||||
setPrimary(file) {
|
primary(file) {
|
||||||
this.model.setPrimary(file.UID);
|
this.model.primaryFile(file.UID);
|
||||||
},
|
},
|
||||||
formatTime(s) {
|
formatTime(s) {
|
||||||
return DateTime.fromISO(s).toHTTP();
|
return DateTime.fromISO(s).toHTTP();
|
||||||
|
|
|
@ -510,8 +510,12 @@ export class Photo extends RestModel {
|
||||||
return Api.put(this.getEntityResource(), {Private: this.Private});
|
return Api.put(this.getEntityResource(), {Private: this.Private});
|
||||||
}
|
}
|
||||||
|
|
||||||
setPrimary(uid) {
|
primaryFile(fileUID) {
|
||||||
return Api.post(this.getEntityResource() + "/primary/" + uid).then((r) => Promise.resolve(this.setValues(r.data)));
|
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() {
|
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:
|
// Parameters:
|
||||||
// uid: string PhotoUID as returned by the API
|
// uid: string PhotoUID as returned by the API
|
||||||
func SetPhotoPrimary(router *gin.RouterGroup) {
|
// file_uid: string File UID as returned by the API
|
||||||
router.POST("/photos/:uid/primary/:file_uid", func(c *gin.Context) {
|
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)
|
s := Auth(SessionID(c), acl.ResourcePhotos, acl.ActionUpdate)
|
||||||
|
|
||||||
if s.Invalid() {
|
if s.Invalid() {
|
||||||
|
@ -330,3 +331,85 @@ func SetPhotoPrimary(router *gin.RouterGroup) {
|
||||||
c.JSON(http.StatusOK, p)
|
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) {
|
func TestSetPhotoPrimary(t *testing.T) {
|
||||||
t.Run("existing photo", func(t *testing.T) {
|
t.Run("existing photo", func(t *testing.T) {
|
||||||
app, router, _ := NewApiTest()
|
app, router, _ := NewApiTest()
|
||||||
SetPhotoPrimary(router)
|
PhotoFilePrimary(router)
|
||||||
r := PerformRequest(app, "POST", "/api/v1/photos/pt9jtdre2lvl0yh8/primary/ft1es39w45bnlqdw")
|
r := PerformRequest(app, "POST", "/api/v1/photos/pt9jtdre2lvl0yh8/files/ft1es39w45bnlqdw/primary")
|
||||||
assert.Equal(t, http.StatusOK, r.Code)
|
assert.Equal(t, http.StatusOK, r.Code)
|
||||||
GetFile(router)
|
GetFile(router)
|
||||||
r2 := PerformRequest(app, "GET", "/api/v1/files/ocad9168fa6acc5c5c2965ddf6ec465ca42fd818")
|
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) {
|
t.Run("wrong photo uid", func(t *testing.T) {
|
||||||
app, router, _ := NewApiTest()
|
app, router, _ := NewApiTest()
|
||||||
SetPhotoPrimary(router)
|
PhotoFilePrimary(router)
|
||||||
r := PerformRequest(app, "POST", "/api/v1/photos/xxx/primary/ft1es39w45bnlqdw")
|
r := PerformRequest(app, "POST", "/api/v1/photos/xxx/files/ft1es39w45bnlqdw/primary")
|
||||||
val := gjson.Get(r.Body.String(), "error")
|
val := gjson.Get(r.Body.String(), "error")
|
||||||
assert.Equal(t, "Photo not found", val.String())
|
assert.Equal(t, "Photo not found", val.String())
|
||||||
assert.Equal(t, http.StatusNotFound, r.Code)
|
assert.Equal(t, http.StatusNotFound, r.Code)
|
||||||
|
|
|
@ -55,7 +55,8 @@ func registerRoutes(router *gin.Engine, conf *config.Config) {
|
||||||
api.UpdatePhotoLabel(v1)
|
api.UpdatePhotoLabel(v1)
|
||||||
api.GetMomentsTime(v1)
|
api.GetMomentsTime(v1)
|
||||||
api.GetFile(v1)
|
api.GetFile(v1)
|
||||||
api.SetPhotoPrimary(v1)
|
api.PhotoFilePrimary(v1)
|
||||||
|
api.PhotoFileUngroup(v1)
|
||||||
|
|
||||||
api.GetLabels(v1)
|
api.GetLabels(v1)
|
||||||
api.UpdateLabel(v1)
|
api.UpdateLabel(v1)
|
||||||
|
|
Loading…
Reference in a new issue