[permissions] Prepare for roll-out (#10676)
Closes https://github.com/twentyhq/core-team-issues/issues/469 and https://github.com/twentyhq/core-team-issues/issues/500 In this PR 1. stop conditioning permission initialization for a workspace to env variable value. Instead we want to create and assign permissions and roles in all new workspaces. For now that will be totally silent. 2. temporarily, the default role is set to the admin role for new workspaces. it will also be the case for existing workspaces through the backfill command. Member role is still being created though. (when we will do the final roll-out we will update this so that future workspaces have the member role as default role. our goal here is not to break any current behaviour for users, that today have all have the equivalent of admin rights).
This commit is contained in:
@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import chalk from 'chalk';
|
||||
import { Command } from 'nest-commander';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
ActiveOrSuspendedWorkspacesMigrationCommandOptions,
|
||||
@ -62,36 +62,28 @@ export class InitializePermissionsCommand extends ActiveOrSuspendedWorkspacesMig
|
||||
});
|
||||
}
|
||||
|
||||
await this.assignAdminRole({
|
||||
await this.assignAdminRoleToMembers({
|
||||
workspaceId,
|
||||
adminRoleId,
|
||||
options,
|
||||
});
|
||||
|
||||
let memberRoleId: string | undefined;
|
||||
await this.setAdminRoleAsDefaultRole({
|
||||
workspaceId,
|
||||
adminRoleId,
|
||||
options,
|
||||
});
|
||||
|
||||
memberRoleId = workspaceRoles.find(
|
||||
const memberRole = workspaceRoles.find(
|
||||
(role) => role.label === MEMBER_ROLE_LABEL,
|
||||
)?.id;
|
||||
);
|
||||
|
||||
if (!isDefined(memberRoleId)) {
|
||||
memberRoleId = await this.createMemberRole({
|
||||
if (!isDefined(memberRole)) {
|
||||
await this.createMemberRole({
|
||||
workspaceId,
|
||||
options,
|
||||
});
|
||||
}
|
||||
|
||||
await this.setMemberRoleAsDefaultRole({
|
||||
workspaceId,
|
||||
memberRoleId,
|
||||
options,
|
||||
});
|
||||
|
||||
await this.assignMemberRoleToUserWorkspacesWithoutRole({
|
||||
workspaceId,
|
||||
memberRoleId,
|
||||
options,
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.log(
|
||||
chalk.red(`Error in workspace ${workspaceId} - ${error.message}`),
|
||||
@ -143,39 +135,7 @@ export class InitializePermissionsCommand extends ActiveOrSuspendedWorkspacesMig
|
||||
return memberRole.id;
|
||||
}
|
||||
|
||||
private async setMemberRoleAsDefaultRole({
|
||||
workspaceId,
|
||||
memberRoleId,
|
||||
options,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
memberRoleId: string;
|
||||
options: ActiveOrSuspendedWorkspacesMigrationCommandOptions;
|
||||
}) {
|
||||
const workspaceDefaultRole = await this.workspaceRepository.findOne({
|
||||
where: {
|
||||
id: workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!isDefined(workspaceDefaultRole?.defaultRoleId)) {
|
||||
this.logger.log(
|
||||
chalk.green(
|
||||
`Setting member role as default role ${options.dryRun ? '(dry run)' : ''}`,
|
||||
),
|
||||
);
|
||||
|
||||
if (options.dryRun) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.workspaceRepository.update(workspaceId, {
|
||||
defaultRoleId: memberRoleId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async assignAdminRole({
|
||||
private async setAdminRoleAsDefaultRole({
|
||||
workspaceId,
|
||||
adminRoleId,
|
||||
options,
|
||||
@ -184,28 +144,25 @@ export class InitializePermissionsCommand extends ActiveOrSuspendedWorkspacesMig
|
||||
adminRoleId: string;
|
||||
options: ActiveOrSuspendedWorkspacesMigrationCommandOptions;
|
||||
}) {
|
||||
const oldestUserWorkspace = await this.userWorkspaceRepository.findOne({
|
||||
const workspaceDefaultRole = await this.workspaceRepository.findOne({
|
||||
where: {
|
||||
workspaceId,
|
||||
deletedAt: IsNull(),
|
||||
},
|
||||
relations: {
|
||||
user: true,
|
||||
},
|
||||
order: {
|
||||
user: {
|
||||
createdAt: 'ASC',
|
||||
},
|
||||
id: workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!oldestUserWorkspace) {
|
||||
throw new Error('No user workspace found');
|
||||
if (isDefined(workspaceDefaultRole?.defaultRoleId)) {
|
||||
this.logger.log(
|
||||
chalk.green(
|
||||
'Workspace already has a default role. Skipping setting admin role as default role',
|
||||
),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
chalk.green(
|
||||
`Assigning admin role to user ${oldestUserWorkspace.id} ${options.dryRun ? '(dry run)' : ''}`,
|
||||
`Setting admin role as default role ${options.dryRun ? '(dry run)' : ''}`,
|
||||
),
|
||||
);
|
||||
|
||||
@ -213,29 +170,24 @@ export class InitializePermissionsCommand extends ActiveOrSuspendedWorkspacesMig
|
||||
return;
|
||||
}
|
||||
|
||||
await this.userRoleService.assignRoleToUserWorkspace({
|
||||
roleId: adminRoleId,
|
||||
userWorkspaceId: oldestUserWorkspace.id,
|
||||
workspaceId,
|
||||
await this.workspaceRepository.update(workspaceId, {
|
||||
defaultRoleId: adminRoleId,
|
||||
});
|
||||
}
|
||||
|
||||
private async assignMemberRoleToUserWorkspacesWithoutRole({
|
||||
private async assignAdminRoleToMembers({
|
||||
workspaceId,
|
||||
memberRoleId,
|
||||
adminRoleId,
|
||||
options,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
memberRoleId: string;
|
||||
adminRoleId: string;
|
||||
options: ActiveOrSuspendedWorkspacesMigrationCommandOptions;
|
||||
}) {
|
||||
const userWorkspaces = await this.userWorkspaceRepository.find({
|
||||
where: {
|
||||
workspaceId,
|
||||
},
|
||||
relations: {
|
||||
user: true,
|
||||
},
|
||||
});
|
||||
|
||||
const rolesByUserWorkspace =
|
||||
@ -247,7 +199,6 @@ export class InitializePermissionsCommand extends ActiveOrSuspendedWorkspacesMig
|
||||
});
|
||||
|
||||
for (const userWorkspace of userWorkspaces) {
|
||||
// If userWorkspace has a role, do nothing
|
||||
if (
|
||||
rolesByUserWorkspace
|
||||
.get(userWorkspace.id)
|
||||
@ -255,7 +206,7 @@ export class InitializePermissionsCommand extends ActiveOrSuspendedWorkspacesMig
|
||||
) {
|
||||
this.logger.log(
|
||||
chalk.green(
|
||||
`User workspace ${userWorkspace.id} already has a role. Skipping member role assignation`,
|
||||
`User workspace ${userWorkspace.id} already has a role. Skipping role assignation`,
|
||||
),
|
||||
);
|
||||
continue;
|
||||
@ -263,7 +214,7 @@ export class InitializePermissionsCommand extends ActiveOrSuspendedWorkspacesMig
|
||||
|
||||
this.logger.log(
|
||||
chalk.green(
|
||||
`Assigning member role to user workspace ${userWorkspace.id} ${options.dryRun ? '(dry run)' : ''}`,
|
||||
`Assigning admin role to workspace member ${userWorkspace.id} ${options.dryRun ? '(dry run)' : ''}`,
|
||||
),
|
||||
);
|
||||
|
||||
@ -271,9 +222,8 @@ export class InitializePermissionsCommand extends ActiveOrSuspendedWorkspacesMig
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, assign member role to userWorkspace
|
||||
await this.userRoleService.assignRoleToUserWorkspace({
|
||||
roleId: memberRoleId,
|
||||
roleId: adminRoleId,
|
||||
userWorkspaceId: userWorkspace.id,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
@ -31,7 +31,6 @@ import {
|
||||
} from 'src/engine/core-modules/auth/types/signInUp.type';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
||||
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||
@ -273,12 +272,7 @@ export class SignInUpService {
|
||||
await this.activateOnboardingForUser(user, params.workspace);
|
||||
}
|
||||
|
||||
const isPermissionsEnabled = await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IsPermissionsEnabled,
|
||||
params.workspace.id,
|
||||
);
|
||||
|
||||
if (isPermissionsEnabled && params.workspace.defaultRoleId) {
|
||||
if (params.workspace.defaultRoleId) {
|
||||
await this.userRoleService.assignRoleToUserWorkspace({
|
||||
workspaceId: params.workspace.id,
|
||||
userWorkspaceId: userWorkspace.id,
|
||||
|
||||
@ -860,16 +860,6 @@ export class EnvironmentVariables {
|
||||
@IsBoolean()
|
||||
IS_MULTIWORKSPACE_ENABLED = false;
|
||||
|
||||
@EnvironmentVariablesMetadata({
|
||||
group: EnvironmentVariablesGroup.Other,
|
||||
description:
|
||||
'Use as a feature flag for the new permission feature we are working on.',
|
||||
})
|
||||
@CastToBoolean()
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
PERMISSIONS_ENABLED = false;
|
||||
|
||||
@EnvironmentVariablesMetadata({
|
||||
group: EnvironmentVariablesGroup.Other,
|
||||
description:
|
||||
|
||||
@ -145,10 +145,6 @@ export class PermissionsService {
|
||||
return roleOfUserWorkspace?.[roleColumn] === true;
|
||||
}
|
||||
|
||||
public async isPermissionsEnabled(): Promise<boolean> {
|
||||
return this.environmentService.get('PERMISSIONS_ENABLED') === true;
|
||||
}
|
||||
|
||||
private getRoleColumnForRequiredPermission(
|
||||
requiredPermission: PermissionsOnAllObjectRecords,
|
||||
): keyof RoleEntity {
|
||||
|
||||
@ -99,12 +99,8 @@ export class WorkspaceManagerService {
|
||||
);
|
||||
|
||||
const permissionsEnabledStart = performance.now();
|
||||
const permissionsEnabled =
|
||||
await this.permissionsService.isPermissionsEnabled();
|
||||
|
||||
if (permissionsEnabled === true) {
|
||||
await this.initPermissions({ workspaceId, userId });
|
||||
}
|
||||
await this.initPermissions({ workspaceId, userId });
|
||||
|
||||
const permissionsEnabledEnd = performance.now();
|
||||
|
||||
@ -168,12 +164,7 @@ export class WorkspaceManagerService {
|
||||
dataSourceId: dataSourceMetadata.id,
|
||||
});
|
||||
|
||||
const permissionsEnabled =
|
||||
await this.permissionsService.isPermissionsEnabled();
|
||||
|
||||
if (permissionsEnabled === true) {
|
||||
await this.initPermissionsDev(workspaceId);
|
||||
}
|
||||
await this.initPermissionsDev(workspaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -296,12 +287,13 @@ export class WorkspaceManagerService {
|
||||
roleId: adminRole.id,
|
||||
});
|
||||
|
||||
const memberRole = await this.roleService.createMemberRole({
|
||||
await this.roleService.createMemberRole({
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
// Temporary - after permissions are rolled-out we will set member role as the default role
|
||||
await this.workspaceRepository.update(workspaceId, {
|
||||
defaultRoleId: memberRole.id,
|
||||
defaultRoleId: adminRole.id,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user