[permissions - seeds] Give tim@apple.dev restricted rights (#12768)
Let's introduce an object-limited role for Tim, to test and/or spot incompatibilities with restricted permissions in the future. Our main user tim@apple.dev is now assigned a role that has all settings permissions, and all object permissions except for update on Pets (to test read-only view) and read on Rockets. Since we still need an admin user for each workspace we are introducing a new member, Jane, who has the admin role --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -92,71 +92,6 @@ export class UserService extends TypeOrmQueryService<User> {
|
||||
});
|
||||
}
|
||||
|
||||
private async deleteUserFromWorkspace({
|
||||
userId,
|
||||
workspaceId,
|
||||
}: {
|
||||
userId: string;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
const workspaceMemberRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'workspaceMember',
|
||||
);
|
||||
|
||||
const workspaceMembers = await workspaceMemberRepository.find();
|
||||
|
||||
if (workspaceMembers.length > 1) {
|
||||
const userWorkspace =
|
||||
await this.userWorkspaceService.getUserWorkspaceForUserOrThrow({
|
||||
userId,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
await this.userRoleService.validateUserWorkspaceIsNotUniqueAdminOrThrow({
|
||||
workspaceId,
|
||||
userWorkspaceId: userWorkspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
const workspaceMember = workspaceMembers.filter(
|
||||
(member: WorkspaceMemberWorkspaceEntity) => member.userId === userId,
|
||||
)?.[0];
|
||||
|
||||
assert(workspaceMember, 'WorkspaceMember not found');
|
||||
|
||||
await workspaceMemberRepository.delete({ userId });
|
||||
|
||||
const objectMetadata = await this.objectMetadataRepository.findOneOrFail({
|
||||
where: {
|
||||
nameSingular: 'workspaceMember',
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (workspaceMembers.length === 1) {
|
||||
await this.workspaceService.deleteWorkspace(workspaceId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.workspaceEventEmitter.emitDatabaseBatchEvent({
|
||||
objectMetadataNameSingular: 'workspaceMember',
|
||||
action: DatabaseEventAction.DELETED,
|
||||
events: [
|
||||
{
|
||||
recordId: workspaceMember.id,
|
||||
objectMetadata,
|
||||
properties: {
|
||||
before: workspaceMember,
|
||||
},
|
||||
},
|
||||
],
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
async deleteUser(userId: string): Promise<User> {
|
||||
const user = await this.userRepository.findOne({
|
||||
where: {
|
||||
@ -167,29 +102,97 @@ export class UserService extends TypeOrmQueryService<User> {
|
||||
|
||||
userValidator.assertIsDefinedOrThrow(user);
|
||||
|
||||
await Promise.all(
|
||||
const prepareForUserDeletionInWorkspaces = await Promise.all(
|
||||
user.workspaces.map(async (userWorkspace) => {
|
||||
try {
|
||||
await this.deleteUserFromWorkspace({
|
||||
userId,
|
||||
workspaceId: userWorkspace.workspaceId,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
if (
|
||||
error instanceof PermissionsException &&
|
||||
error.code === PermissionsExceptionCode.CANNOT_UNASSIGN_LAST_ADMIN
|
||||
) {
|
||||
throw new PermissionsException(
|
||||
PermissionsExceptionMessage.CANNOT_DELETE_LAST_ADMIN_USER,
|
||||
PermissionsExceptionCode.CANNOT_DELETE_LAST_ADMIN_USER,
|
||||
const { workspaceId } = userWorkspace;
|
||||
|
||||
const workspaceMemberRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'workspaceMember',
|
||||
);
|
||||
|
||||
const workspaceMembers = await workspaceMemberRepository.find();
|
||||
|
||||
if (workspaceMembers.length > 1) {
|
||||
try {
|
||||
await this.userRoleService.validateUserWorkspaceIsNotUniqueAdminOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
userWorkspaceId: userWorkspace.id,
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
if (
|
||||
error instanceof PermissionsException &&
|
||||
error.code === PermissionsExceptionCode.CANNOT_UNASSIGN_LAST_ADMIN
|
||||
) {
|
||||
throw new PermissionsException(
|
||||
PermissionsExceptionMessage.CANNOT_DELETE_LAST_ADMIN_USER,
|
||||
PermissionsExceptionCode.CANNOT_DELETE_LAST_ADMIN_USER,
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
const workspaceMember = workspaceMembers.find(
|
||||
(member: WorkspaceMemberWorkspaceEntity) => member.userId === userId,
|
||||
);
|
||||
|
||||
assert(workspaceMember, 'WorkspaceMember not found');
|
||||
|
||||
return {
|
||||
workspaceId,
|
||||
workspaceMemberRepository,
|
||||
workspaceMembers,
|
||||
workspaceMember,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
prepareForUserDeletionInWorkspaces.map(
|
||||
async ({
|
||||
workspaceId,
|
||||
workspaceMemberRepository,
|
||||
workspaceMembers,
|
||||
workspaceMember,
|
||||
}) => {
|
||||
await workspaceMemberRepository.delete({ userId });
|
||||
|
||||
const objectMetadata =
|
||||
await this.objectMetadataRepository.findOneOrFail({
|
||||
where: {
|
||||
nameSingular: 'workspaceMember',
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (workspaceMembers.length === 1) {
|
||||
await this.workspaceService.deleteWorkspace(workspaceId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.workspaceEventEmitter.emitDatabaseBatchEvent({
|
||||
objectMetadataNameSingular: 'workspaceMember',
|
||||
action: DatabaseEventAction.DELETED,
|
||||
events: [
|
||||
{
|
||||
recordId: workspaceMember.id,
|
||||
objectMetadata,
|
||||
properties: {
|
||||
before: workspaceMember,
|
||||
},
|
||||
},
|
||||
],
|
||||
workspaceId,
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user