Skip to content

Commit

Permalink
Albums: Remove photo from review when adding it to an album #4229
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Mayer <[email protected]>
  • Loading branch information
lastzero committed May 9, 2024
1 parent fa3a0d1 commit 1325569
Show file tree
Hide file tree
Showing 38 changed files with 370 additions and 162 deletions.
48 changes: 39 additions & 9 deletions internal/api/albums.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,22 +384,22 @@ func CloneAlbums(router *gin.RouterGroup) {

var added []entity.PhotoAlbum

for _, uid := range f.Albums {
cloneAlbum, err := query.AlbumByUID(uid)
for _, albumUid := range f.Albums {
cloneAlbum, queryErr := query.AlbumByUID(albumUid)

if err != nil {
log.Errorf("album: %s", err)
if queryErr != nil {
log.Errorf("album: %s", queryErr)
continue
}

photos, err := search.AlbumPhotos(cloneAlbum, 10000, false)
photos, queryErr := search.AlbumPhotos(cloneAlbum, 100000, false)

if err != nil {
log.Errorf("album: %s", err)
if queryErr != nil {
log.Errorf("album: %s", queryErr)
continue
}

added = append(added, a.AddPhotos(photos.UIDs())...)
added = append(added, a.AddPhotos(photos)...)
}

if len(added) > 0 {
Expand Down Expand Up @@ -466,7 +466,9 @@ func AddPhotosToAlbum(router *gin.RouterGroup) {
return
}

added := a.AddPhotos(photos.UIDs())
conf := get.Config()

added := a.AddPhotos(photos)

if len(added) > 0 {
if len(added) == 1 {
Expand All @@ -481,6 +483,34 @@ func AddPhotosToAlbum(router *gin.RouterGroup) {

// Update album YAML backup.
SaveAlbumAsYaml(a)

// Auto-approve photos that have been added to an album,
// see https://github.com/photoprism/photoprism/issues/4229
if conf.Settings().Features.Review {
var approved entity.Photos

for _, p := range photos {
// Skip photos that are not in review.
if p.Approved() {
continue
}

// Approve photo and update YAML backup file.
if err = p.Approve(); err != nil {
log.Errorf("approve: %s", err)
} else {
approved = append(approved, p)
SavePhotoAsYaml(&p)
}
}

// Update client UI and counts if photos has been approved.
if len(approved) > 0 {
UpdateClientConfig()

event.EntitiesUpdated("photos", approved)
}
}
}

c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": i18n.Msg(i18n.MsgChangesSaved), "album": a, "photos": photos.UIDs(), "added": added})
Expand Down
20 changes: 10 additions & 10 deletions internal/api/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ func BatchPhotosArchive(router *gin.RouterGroup) {
}

for _, p := range photos {
if err := p.Archive(); err != nil {
log.Errorf("archive: %s", err)
if archiveErr := p.Archive(); archiveErr != nil {
log.Errorf("archive: %s", archiveErr)
} else {
SavePhotoAsYaml(p)
SavePhotoAsYaml(&p)
}
}
} else if err := entity.Db().Where("photo_uid IN (?)", f.Photos).Delete(&entity.Photo{}).Error; err != nil {
Expand Down Expand Up @@ -120,10 +120,10 @@ func BatchPhotosRestore(router *gin.RouterGroup) {
}

for _, p := range photos {
if err := p.Restore(); err != nil {
if err = p.Restore(); err != nil {
log.Errorf("restore: %s", err)
} else {
SavePhotoAsYaml(p)
SavePhotoAsYaml(&p)
}
}
} else if err := entity.Db().Unscoped().Model(&entity.Photo{}).Where("photo_uid IN (?)", f.Photos).
Expand Down Expand Up @@ -187,7 +187,7 @@ func BatchPhotosApprove(router *gin.RouterGroup) {
log.Errorf("approve: %s", err)
} else {
approved = append(approved, p)
SavePhotoAsYaml(p)
SavePhotoAsYaml(&p)
}
}

Expand Down Expand Up @@ -278,7 +278,7 @@ func BatchPhotosPrivate(router *gin.RouterGroup) {
// Fetch selection from index.
if photos, err := query.SelectedPhotos(f); err == nil {
for _, p := range photos {
SavePhotoAsYaml(p)
SavePhotoAsYaml(&p)
}

event.EntitiesUpdated("photos", photos)
Expand Down Expand Up @@ -405,12 +405,12 @@ func BatchPhotosDelete(router *gin.RouterGroup) {
event.AuditWarn([]string{ClientIP(c), s.UserName, "delete", path.Join(p.PhotoPath, p.PhotoName+"*")})

// Remove all related files from storage.
n, err := photoprism.DeletePhoto(p, true, true)
n, deleteErr := photoprism.DeletePhoto(&p, true, true)

numFiles += n

if err != nil {
log.Errorf("delete: %s", err)
if deleteErr != nil {
log.Errorf("delete: %s", deleteErr)
} else {
deleted = append(deleted, p)
}
Expand Down
11 changes: 8 additions & 3 deletions internal/api/photos.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ import (
)

// SavePhotoAsYaml saves photo data as YAML file.
func SavePhotoAsYaml(p entity.Photo) {
func SavePhotoAsYaml(p *entity.Photo) {
if p == nil {
log.Debugf("api: photo is nil (update yaml)")
return
}

c := get.Config()

// Write YAML sidecar file (optional).
Expand Down Expand Up @@ -114,7 +119,7 @@ func UpdatePhoto(router *gin.RouterGroup) {
return
}

SavePhotoAsYaml(p)
SavePhotoAsYaml(&p)

UpdateClientConfig()

Expand Down Expand Up @@ -225,7 +230,7 @@ func ApprovePhoto(router *gin.RouterGroup) {
return
}

SavePhotoAsYaml(m)
SavePhotoAsYaml(&m)

PublishPhotoEvent(StatusUpdated, id, c)

Expand Down
4 changes: 2 additions & 2 deletions internal/api/reactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func LikePhoto(router *gin.RouterGroup) {
return
}

SavePhotoAsYaml(m)
SavePhotoAsYaml(&m)
PublishPhotoEvent(StatusUpdated, id, c)
}

Expand Down Expand Up @@ -84,7 +84,7 @@ func DislikePhoto(router *gin.RouterGroup) {
return
}

SavePhotoAsYaml(m)
SavePhotoAsYaml(&m)
PublishPhotoEvent(StatusUpdated, id, c)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/api/users_passcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func CreateUserPasscode(router *gin.RouterGroup) {
event.AuditErr([]string{ClientIP(c), "session %s", authn.Users, user.UserName, authn.ErrPasscodeGenerateFailed.Error(), clean.Error(err)}, s.RefID)
Abort(c, http.StatusInternalServerError, i18n.ErrUnexpected)
return
} else if passcode, err = entity.NewPasscode(user.UID(), key.String(), rnd.RecoveryCode()); err != nil {
} else if passcode, err = entity.NewPasscode(user.GetUID(), key.String(), rnd.RecoveryCode()); err != nil {
event.AuditErr([]string{ClientIP(c), "session %s", authn.Users, user.UserName, authn.ErrPasscodeCreateFailed.Error(), clean.Error(err)}, s.RefID)
Abort(c, http.StatusInternalServerError, i18n.ErrUnexpected)
return
Expand Down
2 changes: 1 addition & 1 deletion internal/api/users_password.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func UpdateUserPassword(router *gin.RouterGroup) {
}

// Update tokens if user matches with session.
if s.User().UserUID == u.UID() {
if s.User().UserUID == u.GetUID() {
s.SetPreviewToken(u.PreviewToken)
s.SetDownloadToken(u.DownloadToken)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/api/websocket_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func wsWriter(ws *websocket.Conn, writeMutex *sync.Mutex, connId string) {
}
case 4:
ev = strings.Join(ch[2:4], ".")
if acl.ChannelUser.Equal(ch[0]) && ch[1] == user.UID() || acl.Events.AllowAll(acl.Resource(ch[2]), user.AclRole(), wsSubscribePerms) {
if acl.ChannelUser.Equal(ch[0]) && ch[1] == user.GetUID() || acl.Events.AllowAll(acl.Resource(ch[2]), user.AclRole(), wsSubscribePerms) {
// Send to matching user uid.
wsSendMessage(ev, msg.Fields, ws, writeMutex)
} else if acl.ChannelSession.Equal(ch[0]) && ch[1] == sid {
Expand Down
2 changes: 1 addition & 1 deletion internal/commands/clients_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func clientsAddAction(ctx *cli.Context) error {
}

rows[0] = []string{
client.UID(),
client.GetUID(),
client.Name(),
client.AuthInfo(),
client.UserInfo(),
Expand Down
2 changes: 1 addition & 1 deletion internal/commands/clients_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func clientsListAction(ctx *cli.Context) error {
}

rows[i] = []string{
client.UID(),
client.GetUID(),
client.Name(),
client.AuthInfo(),
client.UserInfo(),
Expand Down
6 changes: 3 additions & 3 deletions internal/commands/clients_remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ func clientsRemoveAction(ctx *cli.Context) error {

if !ctx.Bool("force") {
actionPrompt := promptui.Prompt{
Label: fmt.Sprintf("Delete client %s?", m.UID()),
Label: fmt.Sprintf("Delete client %s?", m.GetUID()),
IsConfirm: true,
}

if _, err := actionPrompt.Run(); err != nil {
log.Infof("client %s was not deleted", m.UID())
log.Infof("client %s was not deleted", m.GetUID())
return nil
}
}
Expand All @@ -65,7 +65,7 @@ func clientsRemoveAction(ctx *cli.Context) error {
return err
}

log.Infof("client %s has been deleted", m.UID())
log.Infof("client %s has been deleted", m.GetUID())

return nil
})
Expand Down
2 changes: 1 addition & 1 deletion internal/commands/users_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func usersListAction(ctx *cli.Context) error {
// Display report.
for i, user := range users {
rows[i] = []string{
user.UID(),
user.GetUID(),
user.Username(),
user.AclRole().Pretty(),
user.AuthInfo(),
Expand Down
10 changes: 6 additions & 4 deletions internal/entity/album.go
Original file line number Diff line number Diff line change
Expand Up @@ -783,19 +783,21 @@ func (m *Album) ZipName() string {
}

// AddPhotos adds photos to an existing album.
func (m *Album) AddPhotos(UIDs []string) (added PhotoAlbums) {
func (m *Album) AddPhotos(photos PhotosInterface) (added PhotoAlbums) {
if !m.HasID() {
return added
}

// Add album entries.
for _, uid := range UIDs {
if !rnd.IsUID(uid, PhotoUID) {
for _, photoUid := range photos.UIDs() {
if !rnd.IsUID(photoUid, PhotoUID) {
continue
}

entry := PhotoAlbum{AlbumUID: m.AlbumUID, PhotoUID: uid, Hidden: false}
// Add photo to album.
entry := PhotoAlbum{AlbumUID: m.AlbumUID, PhotoUID: photoUid, Hidden: false}

// Save album entry.
if err := entry.Save(); err != nil {
log.Errorf("album: %s (add to album %s)", err.Error(), m)
} else {
Expand Down
19 changes: 12 additions & 7 deletions internal/entity/album_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,12 @@ func TestAlbum_AddPhotos(t *testing.T) {
AlbumType: AlbumManual,
AlbumTitle: "Test Title",
}
added := album.AddPhotos([]string{"ps6sg6be2lvl0yh7", "ps6sg6be2lvl0yh8"})

photo1 := PhotoFixtures.Get("19800101_000002_D640C559")
photo2 := PhotoFixtures.Get("Photo01")
photos := Photos{photo1, photo2}

added := album.AddPhotos(photos)

var entries PhotoAlbums

Expand All @@ -532,7 +537,7 @@ func TestAlbum_AddPhotos(t *testing.T) {
}

if len(entries) < 2 {
t.Error("at least one album entry expected")
t.Fatal("at least one album entry expected")
}

var a Album
Expand All @@ -542,17 +547,17 @@ func TestAlbum_AddPhotos(t *testing.T) {
t.Fatal(err)
}

first_photo_updatedAt := strings.Split(entries[0].UpdatedAt.String(), ".")[0]
second_photo_updatedAt := strings.Split(entries[1].UpdatedAt.String(), ".")[0]
album_updatedAt := strings.Split(a.UpdatedAt.String(), ".")[0]
firstUpdatedAt := strings.Split(entries[0].UpdatedAt.String(), ".")[0]
secondUpdatedAt := strings.Split(entries[1].UpdatedAt.String(), ".")[0]
albumUpdatedAt := strings.Split(a.UpdatedAt.String(), ".")[0]

assert.Truef(
t, first_photo_updatedAt <= album_updatedAt,
t, firstUpdatedAt <= albumUpdatedAt,
"Expected the UpdatedAt field of an album to be updated when"+
" new photos are added",
)
assert.Truef(
t, second_photo_updatedAt <= album_updatedAt,
t, secondUpdatedAt <= albumUpdatedAt,
"Expected the UpdatedAt field of an album to be updated when"+
" new photos are added",
)
Expand Down
6 changes: 3 additions & 3 deletions internal/entity/auth_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ func FindClientByUID(uid string) *Client {
return m
}

// UID returns the client uid string.
func (m *Client) UID() string {
// GetUID returns the client uid string.
func (m *Client) GetUID() string {
return m.ClientUID
}

Expand Down Expand Up @@ -135,7 +135,7 @@ func (m *Client) String() string {
if m == nil {
return report.NotAssigned
} else if m.HasUID() {
return m.UID()
return m.GetUID()
} else if m.HasName() {
return m.Name()
}
Expand Down

0 comments on commit 1325569

Please sign in to comment.