fix(realtime): доставлять обложку альбома после готовности вариантов
Карточка альбома не получала ссылку на обложку: она появляется в объекте альбома только после генерации thumb/medium, а событие об этом шаге в персональные потоки не публиковалось — счётчик обновлялся, обложка нет. - albums.Service.NotifyCoverReady публикует album.updated получателям, когда варианты готовы у фото, являющегося текущей обложкой (иначе no-op, чтобы массовая загрузка не рассылала событие на каждый файл) - photos: порт AlbumAccess расширен, worker вызывает публикацию после photo.updated - project.md §11/§12: триггер добавлен в контракт персонального потока
This commit is contained in:
@@ -314,7 +314,57 @@ func TestNotifyAlbumChangedReachesRecipientsOnly(t *testing.T) {
|
||||
assertNoEvent(t, albumSub)
|
||||
}
|
||||
|
||||
// photos_count counts only photos outside the trash.
|
||||
// Cover readiness republishes the album only when the photo that became ready is
|
||||
// the current cover; any other photo leaves the album object unchanged.
|
||||
func TestNotifyCoverReadyPublishesOnlyForTheCover(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
st := newStack(t)
|
||||
owner := seedUser(t, st, "Owner")
|
||||
member := seedUser(t, st, "Member")
|
||||
|
||||
album, err := st.svc.Create(ctx, owner, albums.CreateInput{Title: "Cover"})
|
||||
if err != nil {
|
||||
t.Fatalf("create: %v", err)
|
||||
}
|
||||
if err := st.repos.Members.Add(ctx, album.ID, member, "member", &owner); err != nil {
|
||||
t.Fatalf("add member: %v", err)
|
||||
}
|
||||
|
||||
const coverID = "photo-cover"
|
||||
if _, err := st.db.Exec(
|
||||
`INSERT INTO photos (id, album_id, uploader_id) VALUES ($1, $2, $3)`,
|
||||
coverID, album.ID, owner,
|
||||
); err != nil {
|
||||
t.Fatalf("seed cover photo: %v", err)
|
||||
}
|
||||
if _, err := st.db.Exec(
|
||||
`UPDATE albums SET cover_photo_id = $1 WHERE id = $2`, coverID, album.ID,
|
||||
); err != nil {
|
||||
t.Fatalf("set cover: %v", err)
|
||||
}
|
||||
|
||||
ownerSub := st.hub.SubscribeUser(owner)
|
||||
defer ownerSub.Close()
|
||||
memberSub := st.hub.SubscribeUser(member)
|
||||
defer memberSub.Close()
|
||||
|
||||
// A photo that is not the cover changes nothing.
|
||||
st.svc.NotifyCoverReady(ctx, album.ID, "photo-other")
|
||||
assertNoEvent(t, ownerSub)
|
||||
assertNoEvent(t, memberSub)
|
||||
|
||||
// The cover becoming ready reaches the owner and every member.
|
||||
st.svc.NotifyCoverReady(ctx, album.ID, coverID)
|
||||
for name, sub := range map[string]*sse.Subscription{"owner": ownerSub, "member": memberSub} {
|
||||
ev := nextEvent(t, sub)
|
||||
if ev.Type != albums.EventAlbumUpdated {
|
||||
t.Fatalf("%s event = %q, want %q", name, ev.Type, albums.EventAlbumUpdated)
|
||||
}
|
||||
if a, ok := ev.Data.(*models.Album); !ok || a.ID != album.ID {
|
||||
t.Fatalf("%s payload = %#v", name, ev.Data)
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestPhotosCountExcludesTrash(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
st := newStack(t)
|
||||
|
||||
Reference in New Issue
Block a user