Skip to content

Commit 463be58

Browse files
committed
fix(sim-links): hand off a departing member's links to the successor
1 parent 395a394 commit 463be58

2 files changed

Lines changed: 75 additions & 0 deletions

File tree

‎apps/sim/lib/billing/organizations/resource-handoff.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
knowledgeBase,
33
member,
44
permissionGroup,
5+
simLink,
56
ssoProvider,
67
user,
78
workspaceFiles,
@@ -103,6 +104,10 @@ export async function reassignOrganizationSharedResourcesTx(
103104
eq(permissionGroup.createdBy, departingUserId)
104105
)
105106
)
107+
await tx
108+
.update(simLink)
109+
.set({ createdBy: userId, updatedAt })
110+
.where(and(eq(simLink.organizationId, organizationId), eq(simLink.createdBy, departingUserId)))
106111
await tx
107112
.update(ssoProvider)
108113
.set({ userId })

‎apps/sim/lib/workspaces/access/shared-resource-handoff.integration.ts‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
permissionGroup,
1414
permissions,
1515
project,
16+
simLink,
1617
ssoProvider,
1718
user,
1819
userStats,
@@ -1264,6 +1265,75 @@ describe('shared resource retention across workspace departure and account erasu
12641265
await assertRetained(fixture)
12651266
})
12661267

1268+
it("hands a removed member's Sim links to the owner and leaves another organization's links", async () => {
1269+
const fixture = await seedResources(false, false)
1270+
const [organizationId, otherOrganizationId] = [generateId(), generateId()]
1271+
const memberId = generateId()
1272+
const [linkId, otherLinkId] = [generateId(), generateId()]
1273+
organizationIds.push(organizationId, otherOrganizationId)
1274+
await db.insert(organization).values(
1275+
[organizationId, otherOrganizationId].map((id) => ({
1276+
id,
1277+
name: 'Sim link organization',
1278+
slug: id,
1279+
createdAt: new Date(),
1280+
}))
1281+
)
1282+
await db.insert(member).values([
1283+
{
1284+
id: generateId(),
1285+
organizationId,
1286+
userId: fixture.ownerId,
1287+
role: 'owner',
1288+
createdAt: new Date(),
1289+
},
1290+
{
1291+
id: memberId,
1292+
organizationId,
1293+
userId: fixture.departingId,
1294+
role: 'member',
1295+
createdAt: new Date(),
1296+
},
1297+
])
1298+
await db.insert(simLink).values(
1299+
[
1300+
{ id: linkId, organizationId },
1301+
{ id: otherLinkId, organizationId: otherOrganizationId },
1302+
].map(({ id, organizationId: linkOrganizationId }) => ({
1303+
id,
1304+
organizationId: linkOrganizationId,
1305+
name: 'docs',
1306+
normalizedName: 'docs',
1307+
url: 'https://example.test/docs',
1308+
unlisted: true,
1309+
restrictEdit: true,
1310+
createdBy: fixture.departingId,
1311+
}))
1312+
)
1313+
expect(
1314+
(
1315+
await removeUserFromOrganization({
1316+
organizationId,
1317+
userId: fixture.departingId,
1318+
memberId,
1319+
skipBillingLogic: true,
1320+
onError: 'throw',
1321+
})
1322+
).success
1323+
).toBe(true)
1324+
expect(
1325+
await db
1326+
.select({ id: simLink.id, createdBy: simLink.createdBy })
1327+
.from(simLink)
1328+
.where(inArray(simLink.id, [linkId, otherLinkId]))
1329+
).toEqual(
1330+
expect.arrayContaining([
1331+
{ id: linkId, createdBy: fixture.ownerId },
1332+
{ id: otherLinkId, createdBy: fixture.departingId },
1333+
])
1334+
)
1335+
})
1336+
12671337
it('refuses organization-only retention without an owner successor', async () => {
12681338
const fixture = await seedResources(false, false)
12691339
const organizationId = generateId()

0 commit comments

Comments
 (0)