feat(realtime): доставлять клиентам события жизненного цикла альбома и изменения состава фото
Публиковать album.created/updated/deleted и изменения состава фото в личный поток SSE, а также photo.created при загрузке, чтобы списки альбомов, счётчики и открытые страницы альбома обновлялись без перезагрузки. - members.Repository получил Audience (владелец + участники) для дешёвого веера - albums.Service рассылает события в личные потоки получателей, перечитывая альбом через GetByID и attachCover, чтобы payload совпадал с GET /api/albums - members.Service публикует при принятии инвайта, смене роли и исключении - photos.Service публикует photo.created при загрузке и album.updated при добавлении/копировании/перемещении/восстановлении/корзине/окончательном удалении - photos_count теперь считает фото вне корзины - web-клиент подписывается на /api/sse/me один раз на уровне layout'а (app) и применяет события к стору альбомов; страница альбома уходит при потере доступа
This commit is contained in:
@@ -60,6 +60,31 @@ func (s *SQLiteStore) List(ctx context.Context, albumID string) ([]models.AlbumM
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
// Audience returns the owner id plus every member id for the album. It reads
|
||||
// both from their own tables (no join with users) because the fan-out only
|
||||
// needs identifiers.
|
||||
func (s *SQLiteStore) Audience(ctx context.Context, albumID string) ([]string, error) {
|
||||
rows, err := s.db.QueryContext(ctx,
|
||||
`SELECT owner_id FROM albums WHERE id = $1
|
||||
UNION
|
||||
SELECT user_id FROM album_members WHERE album_id = $1
|
||||
ORDER BY 1`, albumID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
out := []string{}
|
||||
for rows.Next() {
|
||||
var id string
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, id)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) Add(ctx context.Context, albumID, userID, role string, invitedBy *string) error {
|
||||
_, err := s.db.ExecContext(ctx,
|
||||
`INSERT INTO album_members (album_id, user_id, role, invited_by)
|
||||
|
||||
Reference in New Issue
Block a user