fix: three code review issues — leaveGroup duplicate, as any casts, federation ownership fallback

- Remove redundant `leaveGroup` API method from client.ts (duplicated `leave`); update MessageList.tsx WelcomeHeader to call `api.dm.leave` directly
- Add optional `type` field to shared `Message` interface so `MessageWithUser` carries it; remove `(msg as any).type` casts in `isSameGroup` and the render branch in MessageList.tsx
- Fix `processOwnershipTransferEvent` in federation.ts: replace `channel.ownerId` fallbacks (pre-update, old owner) with `event.ownership.newOwner.homeUserId` in the db update, dm_owner_updated broadcast, and both system message content payloads
This commit is contained in:
Jannis Braun
2026-03-27 05:50:38 +01:00
parent c3191be4e7
commit 04c665e0f7
4 changed files with 8 additions and 10 deletions
+4 -4
View File
@@ -1965,7 +1965,7 @@ function processOwnershipTransferEvent(
db.update(schema.dmChannels) db.update(schema.dmChannels)
.set({ .set({
ownerId: newOwnerLocal?.id ?? channel.ownerId, ownerId: newOwnerLocal?.id ?? null,
ownerHomeUserId: event.ownership.newOwner.homeUserId, ownerHomeUserId: event.ownership.newOwner.homeUserId,
ownerHomeInstance: event.ownership.newOwner.homeInstance, ownerHomeInstance: event.ownership.newOwner.homeInstance,
}) })
@@ -1975,7 +1975,7 @@ function processOwnershipTransferEvent(
connectionManager.sendToDmMembers(channel.id, { connectionManager.sendToDmMembers(channel.id, {
type: 'dm_owner_updated', type: 'dm_owner_updated',
dmChannelId: channel.id, dmChannelId: channel.id,
newOwnerId: newOwnerLocal?.id ?? channel.ownerId!, newOwnerId: newOwnerLocal?.id ?? event.ownership.newOwner.homeUserId,
}); });
const prevOwnerLocal = event.ownership.previousOwner const prevOwnerLocal = event.ownership.previousOwner
@@ -1991,7 +1991,7 @@ function processOwnershipTransferEvent(
userId: prevOwnerId, userId: prevOwnerId,
content: JSON.stringify({ content: JSON.stringify({
event: 'owner_changed', event: 'owner_changed',
newOwnerId: newOwnerLocal?.id ?? channel.ownerId, newOwnerId: newOwnerLocal?.id ?? event.ownership.newOwner.homeUserId,
newOwnerDisplayName: newOwnerLocal?.displayName ?? newOwnerBaseName, newOwnerDisplayName: newOwnerLocal?.displayName ?? newOwnerBaseName,
}), }),
type: 'system', type: 'system',
@@ -2006,7 +2006,7 @@ function processOwnershipTransferEvent(
userId: prevOwnerId, userId: prevOwnerId,
content: JSON.stringify({ content: JSON.stringify({
event: 'owner_changed', event: 'owner_changed',
newOwnerId: newOwnerLocal?.id ?? channel.ownerId, newOwnerId: newOwnerLocal?.id ?? event.ownership.newOwner.homeUserId,
newOwnerDisplayName: newOwnerLocal?.displayName ?? newOwnerBaseName, newOwnerDisplayName: newOwnerLocal?.displayName ?? newOwnerBaseName,
}), }),
type: 'system', type: 'system',
+1
View File
@@ -193,6 +193,7 @@ export interface Message {
userId: string; userId: string;
replyToId: string | null; replyToId: string | null;
content: string | null; content: string | null;
type?: 'user' | 'system';
editedAt: number | null; editedAt: number | null;
createdAt: number; createdAt: number;
} }
-3
View File
@@ -145,7 +145,6 @@ export class BackspaceApiClient {
deleteMessage: (id: string) => Promise<{ success: boolean }>; deleteMessage: (id: string) => Promise<{ success: boolean }>;
addMember: (dmChannelId: string, data: { userId: string }) => Promise<DmChannel>; addMember: (dmChannelId: string, data: { userId: string }) => Promise<DmChannel>;
leave: (dmChannelId: string) => Promise<{ success: boolean }>; leave: (dmChannelId: string) => Promise<{ success: boolean }>;
leaveGroup: (dmChannelId: string) => Promise<{ success: boolean }>;
}; };
readonly social: { readonly social: {
@@ -506,8 +505,6 @@ export class BackspaceApiClient {
request<DmChannel>('POST', `/dm/${dmChannelId}/members`, data), request<DmChannel>('POST', `/dm/${dmChannelId}/members`, data),
leave: (dmChannelId: string) => leave: (dmChannelId: string) =>
request<{ success: boolean }>('DELETE', `/dm/${dmChannelId}/members`), request<{ success: boolean }>('DELETE', `/dm/${dmChannelId}/members`),
leaveGroup: (dmChannelId: string) =>
request<{ success: boolean }>('DELETE', `/dm/${dmChannelId}/members`),
}; };
this.social = { this.social = {
@@ -21,7 +21,7 @@ interface MessageListProps {
} }
function isSameGroup(prev: MessageWithUser, curr: MessageWithUser): boolean { function isSameGroup(prev: MessageWithUser, curr: MessageWithUser): boolean {
if ((prev as any).type === 'system' || (curr as any).type === 'system') return false; if (prev.type === 'system' || curr.type === 'system') return false;
if (prev.userId !== curr.userId) return false; if (prev.userId !== curr.userId) return false;
const timeDiff = curr.createdAt - prev.createdAt; const timeDiff = curr.createdAt - prev.createdAt;
return timeDiff < 5 * 60 * 1000; // 5 minutes return timeDiff < 5 * 60 * 1000; // 5 minutes
@@ -338,7 +338,7 @@ export function MessageList({ channelId, jumpToMessageId, onJumpComplete }: Mess
<div className="flex-1 h-[1px] bg-border-hard" /> <div className="flex-1 h-[1px] bg-border-hard" />
</div> </div>
)} )}
{(msg as any).type === 'system' ? ( {msg.type === 'system' ? (
<SystemMessage message={msg} /> <SystemMessage message={msg} />
) : ( ) : (
<Message <Message
@@ -438,7 +438,7 @@ function WelcomeHeader({ channelId }: { channelId: string }) {
const handleLeaveGroup = async () => { const handleLeaveGroup = async () => {
try { try {
await api.dm.leaveGroup(channelId); await api.dm.leave(channelId);
navigate('/channels/@me'); navigate('/channels/@me');
} catch (err) { } catch (err) {
console.error('Failed to leave group:', err); console.error('Failed to leave group:', err);