fix(fe2): not being able to remove member from workspace (#4468)

* fix(fe2): not being able to remove member from workspace

* minor comment

* withTransaction refactor
This commit is contained in:
Kristaps Fabians Geikins
2025-04-17 10:44:55 +03:00
committed by GitHub
parent c33052e697
commit 0cc19dbdf5
9 changed files with 326 additions and 237 deletions
@@ -711,60 +711,87 @@ export const initializeEventListenersFactory =
})
}),
eventBus.listen(WorkspaceEvents.RoleDeleted, async ({ payload }) => {
const trx = await db.transaction()
const onWorkspaceRoleDeleted = onWorkspaceRoleDeletedFactory({
queryAllWorkspaceProjects: queryAllWorkspaceProjectsFactory({ getStreams }),
deleteProjectRole: deleteProjectRoleFactory({ db: trx }),
deleteWorkspaceSeat: deleteWorkspaceSeatFactory({ db: trx })
})
await withTransaction(onWorkspaceRoleDeleted(payload.acl), trx)
await withTransaction(
async ({ db: trx }) => {
const onWorkspaceRoleDeleted = onWorkspaceRoleDeletedFactory({
queryAllWorkspaceProjects: queryAllWorkspaceProjectsFactory({
getStreams
}),
deleteProjectRole: deleteProjectRoleFactory({ db: trx }),
deleteWorkspaceSeat: deleteWorkspaceSeatFactory({ db: trx })
})
return await onWorkspaceRoleDeleted(payload.acl)
},
{ db }
)
}),
eventBus.listen(WorkspaceEvents.RoleUpdated, async ({ payload }) => {
const trx = await db.transaction()
const onWorkspaceRoleUpdated = onWorkspaceRoleUpdatedFactory({
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db }),
getWorkspaceRoleToDefaultProjectRoleMapping:
getWorkspaceRoleToDefaultProjectRoleMappingFactory({
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db })
}),
queryAllWorkspaceProjects: queryAllWorkspaceProjectsFactory({ getStreams }),
setStreamCollaborator: setStreamCollaboratorFactory({
getUser: getUserFactory({ db }),
validateStreamAccess: validateStreamAccessFactory({ authorizeResolver }),
emitEvent: eventBus.emit,
grantStreamPermissions: grantStreamPermissionsFactory({ db: trx }),
isStreamCollaborator: isStreamCollaboratorFactory({
getStream: getStreamFactory({ db })
}),
revokeStreamPermissions: revokeStreamPermissionsFactory({ db: trx })
}),
getStreamsCollaboratorCounts: getStreamsCollaboratorCountsFactory({ db })
})
await withTransaction(onWorkspaceRoleUpdated(payload), trx)
await withTransaction(
async ({ db: trx }) => {
const onWorkspaceRoleUpdated = onWorkspaceRoleUpdatedFactory({
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db }),
getWorkspaceRoleToDefaultProjectRoleMapping:
getWorkspaceRoleToDefaultProjectRoleMappingFactory({
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db })
}),
queryAllWorkspaceProjects: queryAllWorkspaceProjectsFactory({
getStreams
}),
setStreamCollaborator: setStreamCollaboratorFactory({
getUser: getUserFactory({ db }),
validateStreamAccess: validateStreamAccessFactory({
authorizeResolver
}),
emitEvent: eventBus.emit,
grantStreamPermissions: grantStreamPermissionsFactory({
db: trx
}),
isStreamCollaborator: isStreamCollaboratorFactory({
getStream: getStreamFactory({ db })
}),
revokeStreamPermissions: revokeStreamPermissionsFactory({
db: trx
})
}),
getStreamsCollaboratorCounts: getStreamsCollaboratorCountsFactory({ db })
})
return await onWorkspaceRoleUpdated(payload)
},
{ db }
)
}),
eventBus.listen(WorkspaceEvents.SeatUpdated, async (payload) => {
const trx = await db.transaction()
const onWorkspaceSeatUpdated = onWorkspaceSeatUpdatedFactory({
setStreamCollaborator: setStreamCollaboratorFactory({
getUser: getUserFactory({ db }),
validateStreamAccess: validateStreamAccessFactory({ authorizeResolver }),
emitEvent: eventBus.emit,
grantStreamPermissions: grantStreamPermissionsFactory({ db: trx }),
isStreamCollaborator: isStreamCollaboratorFactory({
getStream: getStreamFactory({ db })
}),
revokeStreamPermissions: revokeStreamPermissionsFactory({ db: trx })
}),
queryAllWorkspaceProjects: queryAllWorkspaceProjectsFactory({ getStreams }),
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db }),
getWorkspaceRoleForUser: getWorkspaceRoleForUserFactory({ db }),
getWorkspaceSeatTypeToProjectRoleMapping:
getWorkspaceSeatTypeToProjectRoleMappingFactory({
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db })
await withTransaction(
async ({ db: trx }) => {
const onWorkspaceSeatUpdated = onWorkspaceSeatUpdatedFactory({
setStreamCollaborator: setStreamCollaboratorFactory({
getUser: getUserFactory({ db }),
validateStreamAccess: validateStreamAccessFactory({
authorizeResolver
}),
emitEvent: eventBus.emit,
grantStreamPermissions: grantStreamPermissionsFactory({ db: trx }),
isStreamCollaborator: isStreamCollaboratorFactory({
getStream: getStreamFactory({ db })
}),
revokeStreamPermissions: revokeStreamPermissionsFactory({ db: trx })
}),
queryAllWorkspaceProjects: queryAllWorkspaceProjectsFactory({
getStreams
}),
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db }),
getWorkspaceRoleForUser: getWorkspaceRoleForUserFactory({ db }),
getWorkspaceSeatTypeToProjectRoleMapping:
getWorkspaceSeatTypeToProjectRoleMappingFactory({
getWorkspaceWithPlan: getWorkspaceWithPlanFactory({ db })
})
})
})
await withTransaction(onWorkspaceSeatUpdated(payload), trx)
return await onWorkspaceSeatUpdated(payload)
},
{ db }
)
}),
eventBus.listen('**', emitWorkspaceGraphqlSubscriptions),
eventBus.listen(
@@ -733,17 +733,19 @@ export = FF_WORKSPACES_MODULE_ENABLED
if (!role) {
// this is currently not working with the command factory
// TODO: include the onWorkspaceRoleDeletedFactory listener service
const trx = await db.transaction()
const deleteWorkspaceRole = deleteWorkspaceRoleFactory({
deleteWorkspaceRole: repoDeleteWorkspaceRoleFactory({ db: trx }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db: trx }),
emitWorkspaceEvent: getEventBus().emit
})
await withOperationLogging(
async () =>
await withTransaction(
deleteWorkspaceRole({ workspaceId, userId }),
trx
async ({ db: trx }) => {
const deleteWorkspaceRole = deleteWorkspaceRoleFactory({
deleteWorkspaceRole: repoDeleteWorkspaceRoleFactory({ db: trx }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db: trx }),
emitWorkspaceEvent: getEventBus().emit
})
return await deleteWorkspaceRole({ workspaceId, userId })
},
{ db }
),
{
logger,
@@ -758,18 +760,18 @@ export = FF_WORKSPACES_MODULE_ENABLED
const updateWorkspaceRole = commandFactory({
db,
eventBus,
operationFactory: ({ db, emit }) =>
operationFactory: ({ trx, emit }) =>
updateWorkspaceRoleFactory({
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db }),
getWorkspaceWithDomains: getWorkspaceWithDomainsFactory({ db }),
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db: trx }),
getWorkspaceWithDomains: getWorkspaceWithDomainsFactory({ db: trx }),
findVerifiedEmailsByUserId: findVerifiedEmailsByUserIdFactory({
db
db: trx
}),
getWorkspaceRoles: getWorkspaceRolesFactory({ db }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db: trx }),
emitWorkspaceEvent: emit,
ensureValidWorkspaceRoleSeat: ensureValidWorkspaceRoleSeatFactory({
createWorkspaceSeat: createWorkspaceSeatFactory({ db }),
getWorkspaceUserSeat: getWorkspaceUserSeatFactory({ db }),
createWorkspaceSeat: createWorkspaceSeatFactory({ db: trx }),
getWorkspaceUserSeat: getWorkspaceUserSeatFactory({ db: trx }),
eventEmit: emit
})
})
@@ -946,17 +948,22 @@ export = FF_WORKSPACES_MODULE_ENABLED
})
// this is currently not working with the command factory
// TODO: include the onWorkspaceRoleDeletedFactory listener service
const trx = await db.transaction()
const deleteWorkspaceRole = deleteWorkspaceRoleFactory({
deleteWorkspaceRole: repoDeleteWorkspaceRoleFactory({ db: trx }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db: trx }),
emitWorkspaceEvent: getEventBus().emit
})
await withOperationLogging(
async () =>
await withTransaction(
deleteWorkspaceRole({ workspaceId, userId: context.userId! }),
trx
async ({ db: trx }) => {
const deleteWorkspaceRole = deleteWorkspaceRoleFactory({
deleteWorkspaceRole: repoDeleteWorkspaceRoleFactory({ db: trx }),
getWorkspaceRoles: getWorkspaceRolesFactory({ db: trx }),
emitWorkspaceEvent: getEventBus().emit
})
return await deleteWorkspaceRole({
workspaceId,
userId: context.userId!
})
},
{ db }
),
{
logger,
+88 -76
View File
@@ -257,87 +257,99 @@ export const getSsoRouter = (): Router => {
query: oidcCallbackRequestQuery
}),
async (req, res, next) => {
const trx = await db.transaction()
const handleOidcCallback = handleOidcCallbackFactory({
getWorkspaceRoles: getWorkspaceRolesFactory({ db: trx }),
getWorkspaceBySlug: getWorkspaceBySlugFactory({ db: trx }),
createOidcProvider: createOidcProviderFactory({
getOIDCProviderValidationRequest: getOIDCProviderValidationRequestFactory({
redis: getGenericRedis(),
decrypt: getDecryptor()
}),
saveSsoProviderRegistration: saveSsoProviderRegistrationFactory({
getWorkspaceSsoProvider: getWorkspaceSsoProviderFactory({
db: trx,
decrypt: getDecryptor()
}),
storeProviderRecord: storeSsoProviderRecordFactory({
db: trx,
encrypt: getEncryptor()
}),
associateSsoProviderWithWorkspace: associateSsoProviderWithWorkspaceFactory(
{
db: trx
}
)
})
}),
getOidcProvider: getOidcProviderFactory({
getWorkspaceSsoProvider: getWorkspaceSsoProviderFactory({
db: trx,
decrypt: getDecryptor()
})
}),
getOidcProviderUserData: getOidcProviderUserDataFactory(),
tryGetSpeckleUserData: tryGetSpeckleUserDataFactory({
findEmail: findEmailFactory({ db: trx }),
getUser: getUserFactory({ db: trx }),
getUserEmails: findEmailsByUserIdFactory({ db: trx })
}),
createWorkspaceUserFromSsoProfile: createWorkspaceUserFromSsoProfileFactory({
createUser: createUserFactory({
getServerInfo: getServerInfoFactory({ db: trx }),
findEmail: findEmailFactory({ db: trx }),
storeUser: storeUserFactory({ db: trx }),
countAdminUsers: countAdminUsersFactory({ db: trx }),
storeUserAcl: storeUserAclFactory({ db: trx }),
validateAndCreateUserEmail: validateAndCreateUserEmailFactory({
createUserEmail: createUserEmailFactory({ db: trx }),
ensureNoPrimaryEmailForUser: ensureNoPrimaryEmailForUserFactory({
db: trx
try {
await withTransaction(
async ({ db: trx }) => {
const handleOidcCallback = handleOidcCallbackFactory({
getWorkspaceRoles: getWorkspaceRolesFactory({ db: trx }),
getWorkspaceBySlug: getWorkspaceBySlugFactory({ db: trx }),
createOidcProvider: createOidcProviderFactory({
getOIDCProviderValidationRequest:
getOIDCProviderValidationRequestFactory({
redis: getGenericRedis(),
decrypt: getDecryptor()
}),
saveSsoProviderRegistration: saveSsoProviderRegistrationFactory({
getWorkspaceSsoProvider: getWorkspaceSsoProviderFactory({
db: trx,
decrypt: getDecryptor()
}),
storeProviderRecord: storeSsoProviderRecordFactory({
db: trx,
encrypt: getEncryptor()
}),
associateSsoProviderWithWorkspace:
associateSsoProviderWithWorkspaceFactory({
db: trx
})
})
}),
findEmail: findEmailFactory({ db: trx }),
updateEmailInvites: finalizeInvitedServerRegistrationFactory({
deleteServerOnlyInvites: deleteServerOnlyInvitesFactory({ db: trx }),
updateAllInviteTargets: updateAllInviteTargetsFactory({ db: trx })
getOidcProvider: getOidcProviderFactory({
getWorkspaceSsoProvider: getWorkspaceSsoProviderFactory({
db: trx,
decrypt: getDecryptor()
})
}),
requestNewEmailVerification: requestNewEmailVerificationFactory({
getOidcProviderUserData: getOidcProviderUserDataFactory(),
tryGetSpeckleUserData: tryGetSpeckleUserDataFactory({
findEmail: findEmailFactory({ db: trx }),
getUser: getUserFactory({ db: trx }),
getServerInfo: getServerInfoFactory({ db: trx }),
deleteOldAndInsertNewVerification:
deleteOldAndInsertNewVerificationFactory({ db: trx }),
renderEmail,
sendEmail
})
}),
emitEvent: getEventBus().emit
}),
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db: trx }),
findInvite: findInviteFactory({ db: trx }),
deleteInvite: deleteInviteFactory({ db: trx })
}),
linkUserWithSsoProvider: linkUserWithSsoProviderFactory({
findEmailsByUserId: findEmailsByUserIdFactory({ db: trx }),
createUserEmail: createUserEmailFactory({ db: trx }),
updateUserEmail: updateUserEmailFactory({ db: trx }),
logger: req.log
}),
upsertUserSsoSession: upsertUserSsoSessionFactory({ db: trx })
})
getUserEmails: findEmailsByUserIdFactory({ db: trx })
}),
createWorkspaceUserFromSsoProfile:
createWorkspaceUserFromSsoProfileFactory({
createUser: createUserFactory({
getServerInfo: getServerInfoFactory({ db: trx }),
findEmail: findEmailFactory({ db: trx }),
storeUser: storeUserFactory({ db: trx }),
countAdminUsers: countAdminUsersFactory({ db: trx }),
storeUserAcl: storeUserAclFactory({ db: trx }),
validateAndCreateUserEmail: validateAndCreateUserEmailFactory({
createUserEmail: createUserEmailFactory({ db: trx }),
ensureNoPrimaryEmailForUser: ensureNoPrimaryEmailForUserFactory({
db: trx
}),
findEmail: findEmailFactory({ db: trx }),
updateEmailInvites: finalizeInvitedServerRegistrationFactory({
deleteServerOnlyInvites: deleteServerOnlyInvitesFactory({
db: trx
}),
updateAllInviteTargets: updateAllInviteTargetsFactory({
db: trx
})
}),
requestNewEmailVerification: requestNewEmailVerificationFactory({
findEmail: findEmailFactory({ db: trx }),
getUser: getUserFactory({ db: trx }),
getServerInfo: getServerInfoFactory({ db: trx }),
deleteOldAndInsertNewVerification:
deleteOldAndInsertNewVerificationFactory({
db: trx
}),
renderEmail,
sendEmail
})
}),
emitEvent: getEventBus().emit
}),
upsertWorkspaceRole: upsertWorkspaceRoleFactory({ db: trx }),
findInvite: findInviteFactory({ db: trx }),
deleteInvite: deleteInviteFactory({ db: trx })
}),
linkUserWithSsoProvider: linkUserWithSsoProviderFactory({
findEmailsByUserId: findEmailsByUserIdFactory({ db: trx }),
createUserEmail: createUserEmailFactory({ db: trx }),
updateUserEmail: updateUserEmailFactory({ db: trx }),
logger: req.log
}),
upsertUserSsoSession: upsertUserSsoSessionFactory({ db: trx })
})
await handleOidcCallback(req, res, next)
},
{ db }
)
try {
await withTransaction(handleOidcCallback(req, res, next), trx)
return next()
} catch (e) {
const errorMessage = getErrorMessage(e)