feat(social): show friend presence and require online listening
ci / api / api (push) Successful in 1m11s
ci / db / db (push) Failing after 23s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m29s
ci / ts / ts (packages + web) (push) Successful in 3m15s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m27s
ci / api / api (push) Successful in 1m11s
ci / db / db (push) Failing after 23s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m29s
ci / ts / ts (packages + web) (push) Successful in 3m15s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m27s
This commit is contained in:
1 parent
582c0dc3d4
commit
cd84ceecb2
26 files changed
+574
-400
No files matched your search
@@ -90,6 +90,7 @@ export function fakeApi(initial: FakeUser[]) {
|
||||
const listeningMembers = new Map<string, string>();
|
||||
const listeningRequests = new Map<string, components['schemas']['ListeningRequest'] & { guest_id: string }>();
|
||||
const typing = new Map<string, number>();
|
||||
const presence = new Map<string, number>();
|
||||
const defaultListening = { requests: 'nobody', auto_accept: 'nobody', autoplay: true } as const;
|
||||
const pair = (a: string, b: string) => [a, b].sort().join(':');
|
||||
const isBlocked = (a: string, b: string) => blocks.has(`${a}:${b}`) || blocks.has(`${b}:${a}`);
|
||||
@@ -100,6 +101,7 @@ export function fakeApi(initial: FakeUser[]) {
|
||||
return { id: p.id, username: p.username, display_name: p.display_name ?? p.username, ...(visible && activity.has(p.id) && !isBlocked(me,p.id) ? { activity: activity.get(p.id) } : {}),
|
||||
...(last ? { last_message: { id: last.id, sender_id: last.sender_id, text: last.deleted ? '' : last.text.slice(0, 160), attachment_kind: last.attachment_kind, created_at: last.created_at, deleted: last.deleted ?? false } } : {}),
|
||||
relationship: blocks.has(`${me}:${p.id}`) ? 'blocked' : f?.accepted ? 'friend' : f ? f.sender === me ? 'outgoing' : 'incoming' : 'none',
|
||||
online: !!f?.accepted && !isBlocked(me, p.id) && (presence.get(p.id) ?? 0) > Date.now() - 45_000,
|
||||
unread: messages.filter(m => m.recipient === me && m.sender_id === p.id && !m.read).length };
|
||||
};
|
||||
const notify = (recipient: string, actor: FakeUser, kind: components['schemas']['SocialNotification']['kind']) => notifications.unshift({
|
||||
@@ -244,6 +246,7 @@ export function fakeApi(initial: FakeUser[]) {
|
||||
}
|
||||
if (path === '/api/v1/me/social/listening/preferences' && body) { listeningPreferences.set(user.id,body as components['schemas']['ListeningPreferences']);return new Response(null,{status:204}); }
|
||||
if (path === '/api/v1/me/social/listening') {
|
||||
presence.set(user.id, Date.now());
|
||||
const room=listeningRooms.get(listeningMembers.get(user.id) ?? '');
|
||||
if(room)room.participants=[...listeningMembers].filter(([,id])=>id===room.id).map(([id])=>({id,name:users.get(id)?.display_name??users.get(id)?.username??id}));
|
||||
return json({preferences:listeningPreferences.get(user.id)??defaultListening,room:room??null,requests:[...listeningRequests.values()].filter(r=>r.recipient_id===user.id||r.sender_id===user.id),server_time:new Date().toISOString()});
|
||||
@@ -258,6 +261,7 @@ export function fakeApi(initial: FakeUser[]) {
|
||||
const host=op==='join'?target:user.id; const guest=op==='join'?user.id:target; const prefs=listeningPreferences.get(target)??defaultListening;
|
||||
const friend=!!friendships.get(pair(user.id,target))?.accepted;
|
||||
if(isBlocked(user.id,target)||!(prefs.requests==='everyone'||prefs.requests==='friends'&&friend))return problem(403,'social.unavailable');
|
||||
if ((presence.get(target) ?? 0) <= Date.now() - 45_000) return problem(409, 'social.person_offline');
|
||||
let room=[...listeningRooms.values()].find(r=>r.owner_id===host);
|
||||
const source=activity.get(host);if(!room){room={id:crypto.randomUUID(),owner_id:host,owner_name:users.get(host)?.username??host,device_id:String(op==='join'?source?.device_id:body.device_id),track_id:String(op==='join'?source?.track_id:body.track_id),position_ms:Number(op==='join'?source?.position_ms:body.position_ms??0),playing:true,updated_at:new Date().toISOString(),participants:[]};listeningRooms.set(room.id,room);listeningMembers.set(host,room.id);}
|
||||
if(prefs.auto_accept==='everyone'||prefs.auto_accept==='friends'&&friend)listeningMembers.set(guest,room.id);
|
||||
@@ -510,5 +514,5 @@ export function fakeApi(initial: FakeUser[]) {
|
||||
return problem(404, 'common.not_found');
|
||||
};
|
||||
|
||||
return { fetch: fetchImpl as typeof fetch, calls, users, playlists, friendships, notifications, messages, activityVisibility, activity, friendRecommendations, listeningPreferences, listeningRooms, listeningMembers, listeningRequests, signOut: () => (current = null) };
|
||||
return { presence, fetch: fetchImpl as typeof fetch, calls, users, playlists, friendships, notifications, messages, activityVisibility, activity, friendRecommendations, listeningPreferences, listeningRooms, listeningMembers, listeningRequests, signOut: () => (current = null) };
|
||||
}
|
||||
Reference in new issue
Block a user