feat(playlists): share playlists with revocable read-only links
ci / api / api (push) Successful in 55s
release / release (версия и заметки) (push) Successful in 5s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m21s
ci / ts / ts (packages + web) (push) Successful in 2m19s
release / android (APK в релиз) (push) Successful in 4m45s
release / desktop (Linux и Windows в релиз) (push) Successful in 20m58s
release / prune (старые файлы и прогоны) (push) Successful in 9s
ci / module boundaries / boundaries (push) Successful in 7s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m35s
ci / db / db (push) Successful in 59s
ci / api / api (push) Successful in 55s
release / release (версия и заметки) (push) Successful in 5s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m21s
ci / ts / ts (packages + web) (push) Successful in 2m19s
release / android (APK в релиз) (push) Successful in 4m45s
release / desktop (Linux и Windows в релиз) (push) Successful in 20m58s
release / prune (старые файлы и прогоны) (push) Successful in 9s
ci / module boundaries / boundaries (push) Successful in 7s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m35s
ci / db / db (push) Successful in 59s
This commit is contained in:
1 parent
bfcf6e48b2
commit
0a59059738
23 files changed
+1164
-319
No files matched your search
@@ -76,6 +76,7 @@ export function fakeApi(initial: FakeUser[]) {
|
||||
let token = 0;
|
||||
const calls: { method: string; path: string; body: unknown }[] = [];
|
||||
const reactions = new Map<string, 'like' | 'dislike'>();
|
||||
const playlistOwners = new Map<string, string>();
|
||||
const playlists = new Map<string, components['schemas']['Playlist']>();
|
||||
|
||||
const me = (u: FakeUser): Me => ({
|
||||
@@ -157,20 +158,37 @@ export function fakeApi(initial: FakeUser[]) {
|
||||
|
||||
if (!user || !req.headers.get('Authorization')) return problem(401, 'auth.unauthorized');
|
||||
|
||||
if (path === '/api/v1/me/playlists' && req.method === 'GET') return json({ items: [...playlists.values()] });
|
||||
|
||||
const sharedPath = /^\/api\/v1\/shared\/playlists\/([^/]+)$/.exec(path);
|
||||
if (sharedPath && req.method === 'GET') {
|
||||
const item = [...playlists.values()].find(p => p.share_id === sharedPath[1]);
|
||||
return item ? json({ ...item, share_id: null }) : problem(404, 'playlist.not_found');
|
||||
}
|
||||
const sharePath = /^\/api\/v1\/me\/playlists\/([^/]+)\/share$/.exec(path);
|
||||
if (sharePath) {
|
||||
const item = playlists.get(sharePath[1]!);
|
||||
if (!item || playlistOwners.get(item.id) !== user.id) return problem(404, 'playlist.not_found');
|
||||
if (req.method === 'POST') {
|
||||
const share_id = item.share_id ?? `00000000-0000-4000-9001-${String(++seq).padStart(12, '0')}`;
|
||||
playlists.set(item.id, { ...item, share_id }); return json({ share_id });
|
||||
}
|
||||
if (req.method === 'DELETE') { playlists.set(item.id, { ...item, share_id: null }); return new Response(null, { status: 204 }); }
|
||||
}
|
||||
if (path === '/api/v1/me/playlists' && req.method === 'GET') return json({ items: [...playlists.values()].filter(p => !playlistOwners.has(p.id) || playlistOwners.get(p.id) === user.id) });
|
||||
const playlistPath = /^\/api\/v1\/me\/playlists\/([^/]+)$/.exec(path);
|
||||
if (path === '/api/v1/me/playlists' && req.method === 'POST' || playlistPath) {
|
||||
const id = playlistPath?.[1] ?? `00000000-0000-4000-9000-${String(++seq).padStart(12, '0')}`;
|
||||
const old = playlists.get(id);
|
||||
if (playlistPath && !old) return problem(404, 'playlist.not_found');
|
||||
if (playlistPath && (!old || (playlistOwners.has(id) && playlistOwners.get(id) !== user.id))) return problem(404, 'playlist.not_found');
|
||||
if (req.method === 'GET') return json(old);
|
||||
if (req.method === 'DELETE') { playlists.delete(id); return new Response(null, { status: 204 }); }
|
||||
if (old && body?.revision !== old.revision) return problem(409, 'playlist.conflict');
|
||||
const tracks = (body?.track_ids as string[]).map(id => albumTracks.find(t => t.id === id)!);
|
||||
const item = { id, name: body?.name as string, description: body?.description as string, tracks,
|
||||
const item = { ...old, id, name: body?.name as string, description: body?.description as string, tracks,
|
||||
track_count: tracks.length, duration_ms: tracks.reduce((sum, t) => sum + t.duration_ms, 0),
|
||||
revision: (old?.revision ?? 0) + 1, created_at: old?.created_at ?? new Date().toISOString(), updated_at: new Date().toISOString() };
|
||||
playlists.set(id, item);
|
||||
if (!old) playlistOwners.set(id, user.id);
|
||||
return json(item, old ? 200 : 201);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user