fix: deduplicate shared hosts (#1098)

This commit is contained in:
ZacharyZcR
2026-07-28 01:47:46 +08:00
committed by GitHub
parent 5c30c5862f
commit 9c61ae1ac4
2 changed files with 40 additions and 7 deletions
@@ -26,6 +26,28 @@ export interface HostListAccessEntry {
permissionLevel: string;
expiresAt: string | null;
}
const HOST_PERMISSION_RANK: Record<string, number> = {
connect: 1,
view: 2,
edit: 3,
manage: 4,
};
function preferHostAccess(
current: HostListAccessEntry,
candidate: HostListAccessEntry,
): HostListAccessEntry {
const currentRank = HOST_PERMISSION_RANK[current.permissionLevel] ?? 0;
const candidateRank = HOST_PERMISSION_RANK[candidate.permissionLevel] ?? 0;
if (candidateRank !== currentRank) {
return candidateRank > currentRank ? candidate : current;
}
if (current.expiresAt === null) return current;
if (candidate.expiresAt === null) return candidate;
return candidate.expiresAt > current.expiresAt ? candidate : current;
}
export type HostListRow = HostResolutionHostRecord & {
ownerId: string;
isShared: boolean;
@@ -103,9 +125,15 @@ export class HostResolutionRepository {
.from(hosts)
.where(eq(hosts.userId, userId));
const sharedHostIds = Array.from(
new Set(accessEntries.map((access) => access.hostId)),
);
const accessByHostId = new Map<number, HostListAccessEntry>();
for (const access of accessEntries) {
const current = accessByHostId.get(access.hostId);
accessByHostId.set(
access.hostId,
current ? preferHostAccess(current, access) : access,
);
}
const sharedHostIds = Array.from(accessByHostId.keys());
const sharedHostRows =
sharedHostIds.length > 0
? await this.context.drizzle
@@ -125,7 +153,7 @@ export class HostResolutionRepository {
permissionLevel: undefined,
expiresAt: undefined,
})),
...accessEntries.flatMap((access) => {
...Array.from(accessByHostId.values()).flatMap((access) => {
const host = sharedHostsById.get(access.hostId);
if (!host || host.userId === userId) {
return [];
@@ -297,7 +297,12 @@ describe("HostResolutionRepository", () => {
const repository = await createRepository();
const rows = await repository.listHostRowsForAccessList("user-2", [
{ hostId: 1, permissionLevel: "execute", expiresAt: null },
{ hostId: 1, permissionLevel: "view", expiresAt: null },
{
hostId: 1,
permissionLevel: "manage",
expiresAt: "2026-07-01T00:00:00.000Z",
},
{ hostId: 3, permissionLevel: "view", expiresAt: null },
{ hostId: 999, permissionLevel: "view", expiresAt: null },
]);
@@ -316,8 +321,8 @@ describe("HostResolutionRepository", () => {
userId: "user-1",
ownerId: "user-1",
isShared: true,
permissionLevel: "execute",
expiresAt: null,
permissionLevel: "manage",
expiresAt: "2026-07-01T00:00:00.000Z",
});
expect(DataCrypto.decryptRecord).not.toHaveBeenCalled();
});