[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:
@ -97,7 +97,7 @@ export const mockedTimelineActivities: Array<TimelineActivity> = [
|
|||||||
createdAt: '2023-04-26T10:12:42.33625+00:00',
|
createdAt: '2023-04-26T10:12:42.33625+00:00',
|
||||||
workspaceMember: {
|
workspaceMember: {
|
||||||
__typename: 'WorkspaceMember',
|
__typename: 'WorkspaceMember',
|
||||||
id: '20202020-1553-45c6-a028-5a9064cce07f',
|
id: '20202020-463f-435b-828c-107e007a2711',
|
||||||
avatarUrl: '',
|
avatarUrl: '',
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
name: {
|
name: {
|
||||||
@ -108,7 +108,7 @@ export const mockedTimelineActivities: Array<TimelineActivity> = [
|
|||||||
userEmail: 'jane@doe.com',
|
userEmail: 'jane@doe.com',
|
||||||
colorScheme: 'Light',
|
colorScheme: 'Light',
|
||||||
},
|
},
|
||||||
workspaceMemberId: '20202020-1553-45c6-a028-5a9064cce07f',
|
workspaceMemberId: '20202020-463f-435b-828c-107e007a2711',
|
||||||
deletedAt: null,
|
deletedAt: null,
|
||||||
__typename: 'TimelineActivity',
|
__typename: 'TimelineActivity',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
|||||||
|
|
||||||
export const mockWorkspaceMembers: WorkspaceMember[] = [
|
export const mockWorkspaceMembers: WorkspaceMember[] = [
|
||||||
{
|
{
|
||||||
id: '20202020-1553-45c6-a028-5a9064cce07f',
|
id: '20202020-463f-435b-828c-107e007a2711',
|
||||||
name: {
|
name: {
|
||||||
firstName: 'Jane',
|
firstName: 'Jane',
|
||||||
lastName: 'Doe',
|
lastName: 'Doe',
|
||||||
|
|||||||
@ -75,7 +75,7 @@ const jestConfig: JestConfigWithTsJest = {
|
|||||||
APP_PORT: 4000,
|
APP_PORT: 4000,
|
||||||
NODE_ENV: NodeEnvironment.TEST,
|
NODE_ENV: NodeEnvironment.TEST,
|
||||||
ADMIN_ACCESS_TOKEN:
|
ADMIN_ACCESS_TOKEN:
|
||||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtMDY4Ny00YzQxLWI3MDctZWQxYmZjYTk3MmE3IiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtOWUzYi00NmQ0LWE1NTYtODhiOWRkYzJiMDM1IiwiaWF0IjoxNzM5NTQ3NjYxLCJleHAiOjMzMjk3MTQ3NjYxfQ.fbOM9yhr3jWDicPZ1n771usUURiPGmNdeFApsgrbxOw',
|
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ1c2VySWQiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtNDYzZi00MzViLTgyOGMtMTA3ZTAwN2EyNzExIiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWU3Yy00M2Q5LWE1ZGItNjg1YjUwNjlkODE2IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUwNDEyODczLCJleHAiOjE3NTEyNzY4NzN9.cUq9Q_ugJWzP_REUVq5XYpYz9y_yPI-yRIPo5PjvT1k',
|
||||||
EXPIRED_ACCESS_TOKEN:
|
EXPIRED_ACCESS_TOKEN:
|
||||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtMDY4Ny00YzQxLWI3MDctZWQxYmZjYTk3MmE3IiwiaWF0IjoxNzM4MzIzODc5LCJleHAiOjE3MzgzMjU2Nzl9.m73hHVpnw5uGNGrSuKxn6XtKEUK3Wqkp4HsQdYfZiHo',
|
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtMDY4Ny00YzQxLWI3MDctZWQxYmZjYTk3MmE3IiwiaWF0IjoxNzM4MzIzODc5LCJleHAiOjE3MzgzMjU2Nzl9.m73hHVpnw5uGNGrSuKxn6XtKEUK3Wqkp4HsQdYfZiHo',
|
||||||
INVALID_ACCESS_TOKEN:
|
INVALID_ACCESS_TOKEN:
|
||||||
|
|||||||
@ -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> {
|
async deleteUser(userId: string): Promise<User> {
|
||||||
const user = await this.userRepository.findOne({
|
const user = await this.userRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
@ -167,29 +102,97 @@ export class UserService extends TypeOrmQueryService<User> {
|
|||||||
|
|
||||||
userValidator.assertIsDefinedOrThrow(user);
|
userValidator.assertIsDefinedOrThrow(user);
|
||||||
|
|
||||||
await Promise.all(
|
const prepareForUserDeletionInWorkspaces = await Promise.all(
|
||||||
user.workspaces.map(async (userWorkspace) => {
|
user.workspaces.map(async (userWorkspace) => {
|
||||||
try {
|
const { workspaceId } = userWorkspace;
|
||||||
await this.deleteUserFromWorkspace({
|
|
||||||
userId,
|
const workspaceMemberRepository =
|
||||||
workspaceId: userWorkspace.workspaceId,
|
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
|
||||||
});
|
workspaceId,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
'workspaceMember',
|
||||||
} catch (error: any) {
|
);
|
||||||
if (
|
|
||||||
error instanceof PermissionsException &&
|
const workspaceMembers = await workspaceMemberRepository.find();
|
||||||
error.code === PermissionsExceptionCode.CANNOT_UNASSIGN_LAST_ADMIN
|
|
||||||
) {
|
if (workspaceMembers.length > 1) {
|
||||||
throw new PermissionsException(
|
try {
|
||||||
PermissionsExceptionMessage.CANNOT_DELETE_LAST_ADMIN_USER,
|
await this.userRoleService.validateUserWorkspaceIsNotUniqueAdminOrThrow(
|
||||||
PermissionsExceptionCode.CANNOT_DELETE_LAST_ADMIN_USER,
|
{
|
||||||
|
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;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
|
|||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
|
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||||
|
import { ObjectPermissionService } from 'src/engine/metadata-modules/object-permission/object-permission.service';
|
||||||
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
|
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
|
||||||
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
|
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
|
||||||
import { USER_WORKSPACE_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-user-workspaces.util';
|
import { USER_WORKSPACE_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-user-workspaces.util';
|
||||||
@ -22,6 +24,9 @@ export class DevSeederPermissionsService {
|
|||||||
private readonly userRoleService: UserRoleService,
|
private readonly userRoleService: UserRoleService,
|
||||||
@InjectRepository(Workspace, 'core')
|
@InjectRepository(Workspace, 'core')
|
||||||
private readonly workspaceRepository: Repository<Workspace>,
|
private readonly workspaceRepository: Repository<Workspace>,
|
||||||
|
private readonly objectPermissionService: ObjectPermissionService,
|
||||||
|
@InjectRepository(ObjectMetadataEntity, 'core')
|
||||||
|
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public async initPermissions(workspaceId: string) {
|
public async initPermissions(workspaceId: string) {
|
||||||
@ -30,11 +35,15 @@ export class DevSeederPermissionsService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let adminUserWorkspaceId: string | undefined;
|
let adminUserWorkspaceId: string | undefined;
|
||||||
let memberUserWorkspaceId: string | undefined;
|
let memberUserWorkspaceIds: string[] = [];
|
||||||
|
let limitedUserWorkspaceId: string | undefined;
|
||||||
|
let guestUserWorkspaceId: string | undefined;
|
||||||
|
|
||||||
if (workspaceId === SEED_APPLE_WORKSPACE_ID) {
|
if (workspaceId === SEED_APPLE_WORKSPACE_ID) {
|
||||||
adminUserWorkspaceId = USER_WORKSPACE_DATA_SEED_IDS.TIM;
|
adminUserWorkspaceId = USER_WORKSPACE_DATA_SEED_IDS.JANE;
|
||||||
memberUserWorkspaceId = USER_WORKSPACE_DATA_SEED_IDS.JONY;
|
limitedUserWorkspaceId = USER_WORKSPACE_DATA_SEED_IDS.TIM;
|
||||||
|
memberUserWorkspaceIds = [USER_WORKSPACE_DATA_SEED_IDS.JONY];
|
||||||
|
guestUserWorkspaceId = USER_WORKSPACE_DATA_SEED_IDS.PHIL;
|
||||||
|
|
||||||
// Create guest role only in this workspace
|
// Create guest role only in this workspace
|
||||||
const guestRole = await this.roleService.createGuestRole({
|
const guestRole = await this.roleService.createGuestRole({
|
||||||
@ -43,11 +52,25 @@ export class DevSeederPermissionsService {
|
|||||||
|
|
||||||
await this.userRoleService.assignRoleToUserWorkspace({
|
await this.userRoleService.assignRoleToUserWorkspace({
|
||||||
workspaceId,
|
workspaceId,
|
||||||
userWorkspaceId: USER_WORKSPACE_DATA_SEED_IDS.PHIL,
|
userWorkspaceId: guestUserWorkspaceId,
|
||||||
roleId: guestRole.id,
|
roleId: guestRole.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const limitedRole =
|
||||||
|
await this.createLimitedRoleForSeedWorkspace(workspaceId);
|
||||||
|
|
||||||
|
await this.userRoleService.assignRoleToUserWorkspace({
|
||||||
|
workspaceId,
|
||||||
|
userWorkspaceId: limitedUserWorkspaceId,
|
||||||
|
roleId: limitedRole.id,
|
||||||
|
});
|
||||||
} else if (workspaceId === SEED_YCOMBINATOR_WORKSPACE_ID) {
|
} else if (workspaceId === SEED_YCOMBINATOR_WORKSPACE_ID) {
|
||||||
adminUserWorkspaceId = USER_WORKSPACE_DATA_SEED_IDS.TIM_ACME;
|
adminUserWorkspaceId = USER_WORKSPACE_DATA_SEED_IDS.TIM_ACME;
|
||||||
|
memberUserWorkspaceIds = [
|
||||||
|
USER_WORKSPACE_DATA_SEED_IDS.JONY_ACME,
|
||||||
|
USER_WORKSPACE_DATA_SEED_IDS.JANE_ACME,
|
||||||
|
USER_WORKSPACE_DATA_SEED_IDS.PHIL_ACME,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adminUserWorkspaceId) {
|
if (adminUserWorkspaceId) {
|
||||||
@ -67,12 +90,73 @@ export class DevSeederPermissionsService {
|
|||||||
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (memberUserWorkspaceId) {
|
if (memberUserWorkspaceIds) {
|
||||||
await this.userRoleService.assignRoleToUserWorkspace({
|
for (const memberUserWorkspaceId of memberUserWorkspaceIds) {
|
||||||
workspaceId,
|
await this.userRoleService.assignRoleToUserWorkspace({
|
||||||
userWorkspaceId: memberUserWorkspaceId,
|
workspaceId,
|
||||||
roleId: memberRole.id,
|
userWorkspaceId: memberUserWorkspaceId,
|
||||||
});
|
roleId: memberRole.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async createLimitedRoleForSeedWorkspace(workspaceId: string) {
|
||||||
|
const customRole = await this.roleService.createRole({
|
||||||
|
workspaceId,
|
||||||
|
input: {
|
||||||
|
label: 'Object-restricted',
|
||||||
|
description:
|
||||||
|
'All permissions except read on Rockets and update on Pets',
|
||||||
|
icon: 'custom',
|
||||||
|
canUpdateAllSettings: true,
|
||||||
|
canReadAllObjectRecords: true,
|
||||||
|
canUpdateAllObjectRecords: true,
|
||||||
|
canSoftDeleteAllObjectRecords: true,
|
||||||
|
canDestroyAllObjectRecords: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const petObjectMetadata = await this.objectMetadataRepository.findOneOrFail(
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
nameSingular: 'pet',
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const rocketObjectMetadata =
|
||||||
|
await this.objectMetadataRepository.findOneOrFail({
|
||||||
|
where: {
|
||||||
|
nameSingular: 'rocket',
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.objectPermissionService.upsertObjectPermissions({
|
||||||
|
workspaceId,
|
||||||
|
input: {
|
||||||
|
roleId: customRole.id,
|
||||||
|
objectPermissions: [
|
||||||
|
{
|
||||||
|
objectMetadataId: petObjectMetadata.id,
|
||||||
|
canReadObjectRecords: true,
|
||||||
|
canUpdateObjectRecords: false,
|
||||||
|
canSoftDeleteObjectRecords: false,
|
||||||
|
canDestroyObjectRecords: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
objectMetadataId: rocketObjectMetadata.id,
|
||||||
|
canReadObjectRecords: false,
|
||||||
|
canUpdateObjectRecords: false,
|
||||||
|
canSoftDeleteObjectRecords: false,
|
||||||
|
canDestroyObjectRecords: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return customRole;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,9 +10,11 @@ import {
|
|||||||
const tableName = 'userWorkspace';
|
const tableName = 'userWorkspace';
|
||||||
|
|
||||||
export const USER_WORKSPACE_DATA_SEED_IDS = {
|
export const USER_WORKSPACE_DATA_SEED_IDS = {
|
||||||
|
JANE: '20202020-1e7c-43d9-a5db-685b5069d816',
|
||||||
TIM: '20202020-9e3b-46d4-a556-88b9ddc2b035',
|
TIM: '20202020-9e3b-46d4-a556-88b9ddc2b035',
|
||||||
JONY: '20202020-3957-4908-9c36-2929a23f8353',
|
JONY: '20202020-3957-4908-9c36-2929a23f8353',
|
||||||
PHIL: '20202020-7169-42cf-bc47-1cfef15264b1',
|
PHIL: '20202020-7169-42cf-bc47-1cfef15264b1',
|
||||||
|
JANE_ACME: '20202020-ae8d-41ea-9469-f74f5d4b002e',
|
||||||
TIM_ACME: '20202020-e10a-4c27-a90b-b08c57b02d44',
|
TIM_ACME: '20202020-e10a-4c27-a90b-b08c57b02d44',
|
||||||
JONY_ACME: '20202020-e10a-4c27-a90b-b08c57b02d45',
|
JONY_ACME: '20202020-e10a-4c27-a90b-b08c57b02d45',
|
||||||
PHIL_ACME: '20202020-e10a-4c27-a90b-b08c57b02d46',
|
PHIL_ACME: '20202020-e10a-4c27-a90b-b08c57b02d46',
|
||||||
@ -33,6 +35,11 @@ export const seedUserWorkspaces = async (
|
|||||||
userId: USER_DATA_SEED_IDS.TIM,
|
userId: USER_DATA_SEED_IDS.TIM,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: USER_WORKSPACE_DATA_SEED_IDS.JANE,
|
||||||
|
userId: USER_DATA_SEED_IDS.JANE,
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: USER_WORKSPACE_DATA_SEED_IDS.JONY,
|
id: USER_WORKSPACE_DATA_SEED_IDS.JONY,
|
||||||
userId: USER_DATA_SEED_IDS.JONY,
|
userId: USER_DATA_SEED_IDS.JONY,
|
||||||
@ -63,6 +70,11 @@ export const seedUserWorkspaces = async (
|
|||||||
userId: USER_DATA_SEED_IDS.PHIL,
|
userId: USER_DATA_SEED_IDS.PHIL,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: USER_WORKSPACE_DATA_SEED_IDS.JANE_ACME,
|
||||||
|
userId: USER_DATA_SEED_IDS.JANE,
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
await dataSource
|
await dataSource
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { DataSource } from 'typeorm';
|
|||||||
const tableName = 'user';
|
const tableName = 'user';
|
||||||
|
|
||||||
export const USER_DATA_SEED_IDS = {
|
export const USER_DATA_SEED_IDS = {
|
||||||
|
JANE: '20202020-e6b5-4680-8a32-b8209737156b',
|
||||||
TIM: '20202020-9e3b-46d4-a556-88b9ddc2b034',
|
TIM: '20202020-9e3b-46d4-a556-88b9ddc2b034',
|
||||||
JONY: '20202020-3957-4908-9c36-2929a23f8357',
|
JONY: '20202020-3957-4908-9c36-2929a23f8357',
|
||||||
PHIL: '20202020-7169-42cf-bc47-1cfef15264b8',
|
PHIL: '20202020-7169-42cf-bc47-1cfef15264b8',
|
||||||
@ -57,6 +58,17 @@ export const seedUsers = async (dataSource: DataSource, schemaName: string) => {
|
|||||||
canAccessFullAdminPanel: true,
|
canAccessFullAdminPanel: true,
|
||||||
isEmailVerified: true,
|
isEmailVerified: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: USER_DATA_SEED_IDS.JANE,
|
||||||
|
firstName: 'Jane',
|
||||||
|
lastName: 'Austen',
|
||||||
|
email: 'jane.austen@apple.dev',
|
||||||
|
passwordHash:
|
||||||
|
'$2b$10$3LwXjJRtLsfx4hLuuXhxt.3mWgismTiZFCZSG3z9kDrSfsrBl0fT6', // tim@apple.dev
|
||||||
|
canImpersonate: true,
|
||||||
|
canAccessFullAdminPanel: true,
|
||||||
|
isEmailVerified: true,
|
||||||
|
},
|
||||||
])
|
])
|
||||||
.execute();
|
.execute();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -25,6 +25,7 @@ export const WORKSPACE_MEMBER_DATA_SEED_IDS = {
|
|||||||
TIM: '20202020-0687-4c41-b707-ed1bfca972a7',
|
TIM: '20202020-0687-4c41-b707-ed1bfca972a7',
|
||||||
JONY: '20202020-77d5-4cb6-b60a-f4a835a85d61',
|
JONY: '20202020-77d5-4cb6-b60a-f4a835a85d61',
|
||||||
PHIL: '20202020-1553-45c6-a028-5a9064cce07f',
|
PHIL: '20202020-1553-45c6-a028-5a9064cce07f',
|
||||||
|
JANE: '20202020-463f-435b-828c-107e007a2711',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WORKSPACE_MEMBER_DATA_SEEDS: WorkspaceMemberDataSeed[] = [
|
export const WORKSPACE_MEMBER_DATA_SEEDS: WorkspaceMemberDataSeed[] = [
|
||||||
@ -55,4 +56,13 @@ export const WORKSPACE_MEMBER_DATA_SEEDS: WorkspaceMemberDataSeed[] = [
|
|||||||
userEmail: 'phil.schiler@apple.dev',
|
userEmail: 'phil.schiler@apple.dev',
|
||||||
userId: USER_DATA_SEED_IDS.PHIL,
|
userId: USER_DATA_SEED_IDS.PHIL,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: WORKSPACE_MEMBER_DATA_SEED_IDS.JANE,
|
||||||
|
nameFirstName: 'Jane',
|
||||||
|
nameLastName: 'Austen',
|
||||||
|
locale: 'en',
|
||||||
|
colorScheme: 'Light',
|
||||||
|
userEmail: 'jane.austen@apple.dev',
|
||||||
|
userId: USER_DATA_SEED_IDS.JANE,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@ -6,7 +6,9 @@ import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-
|
|||||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||||
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
|
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
|
||||||
|
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||||
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
||||||
|
import { ObjectPermissionModule } from 'src/engine/metadata-modules/object-permission/object-permission.module';
|
||||||
import { RoleModule } from 'src/engine/metadata-modules/role/role.module';
|
import { RoleModule } from 'src/engine/metadata-modules/role/role.module';
|
||||||
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
|
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
|
||||||
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
||||||
@ -30,7 +32,8 @@ import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/worksp
|
|||||||
UserRoleModule,
|
UserRoleModule,
|
||||||
FeatureFlagModule,
|
FeatureFlagModule,
|
||||||
WorkspaceSyncMetadataModule,
|
WorkspaceSyncMetadataModule,
|
||||||
TypeOrmModule.forFeature([Workspace], 'core'),
|
TypeOrmModule.forFeature([Workspace, ObjectMetadataEntity], 'core'),
|
||||||
|
ObjectPermissionModule,
|
||||||
],
|
],
|
||||||
exports: [DevSeederService],
|
exports: [DevSeederService],
|
||||||
providers: [
|
providers: [
|
||||||
|
|||||||
@ -88,7 +88,7 @@ describe('roles permissions', () => {
|
|||||||
|
|
||||||
expect(resp.status).toBe(200);
|
expect(resp.status).toBe(200);
|
||||||
expect(resp.body.errors).toBeUndefined();
|
expect(resp.body.errors).toBeUndefined();
|
||||||
expect(resp.body.data.getRoles).toHaveLength(3);
|
expect(resp.body.data.getRoles).toHaveLength(4);
|
||||||
expect(resp.body.data.getRoles).toEqual(
|
expect(resp.body.data.getRoles).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{
|
{
|
||||||
@ -107,10 +107,10 @@ describe('roles permissions', () => {
|
|||||||
label: 'Admin',
|
label: 'Admin',
|
||||||
workspaceMembers: [
|
workspaceMembers: [
|
||||||
{
|
{
|
||||||
id: '20202020-0687-4c41-b707-ed1bfca972a7',
|
id: '20202020-463f-435b-828c-107e007a2711',
|
||||||
name: {
|
name: {
|
||||||
firstName: 'Tim',
|
firstName: 'Jane',
|
||||||
lastName: 'Apple',
|
lastName: 'Austen',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -127,6 +127,18 @@ describe('roles permissions', () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Object-restricted',
|
||||||
|
workspaceMembers: [
|
||||||
|
{
|
||||||
|
id: '20202020-0687-4c41-b707-ed1bfca972a7',
|
||||||
|
name: {
|
||||||
|
firstName: 'Tim',
|
||||||
|
lastName: 'Apple',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -171,7 +183,7 @@ describe('roles permissions', () => {
|
|||||||
const query = {
|
const query = {
|
||||||
query: `
|
query: `
|
||||||
mutation UpdateWorkspaceMemberRole {
|
mutation UpdateWorkspaceMemberRole {
|
||||||
updateWorkspaceMemberRole(workspaceMemberId: "${WORKSPACE_MEMBER_DATA_SEED_IDS.TIM}", roleId: "test-role-id") {
|
updateWorkspaceMemberRole(workspaceMemberId: "${WORKSPACE_MEMBER_DATA_SEED_IDS.JANE}", roleId: "test-role-id") {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
|
import { TEST_COMPANY_1_ID } from 'test/integration/constants/test-company-ids.constants';
|
||||||
import {
|
import {
|
||||||
TEST_PERSON_1_ID,
|
TEST_PERSON_1_ID,
|
||||||
TEST_PERSON_2_ID,
|
TEST_PERSON_2_ID,
|
||||||
} from 'test/integration/constants/test-person-ids.constants';
|
} from 'test/integration/constants/test-person-ids.constants';
|
||||||
|
import { TEST_PRIMARY_LINK_URL } from 'test/integration/constants/test-primary-link-url.constant';
|
||||||
import { makeRestAPIRequest } from 'test/integration/rest/utils/make-rest-api-request.util';
|
import { makeRestAPIRequest } from 'test/integration/rest/utils/make-rest-api-request.util';
|
||||||
import { deleteAllRecords } from 'test/integration/utils/delete-all-records';
|
import { deleteAllRecords } from 'test/integration/utils/delete-all-records';
|
||||||
import { TEST_COMPANY_1_ID } from 'test/integration/constants/test-company-ids.constants';
|
|
||||||
import { TEST_PRIMARY_LINK_URL } from 'test/integration/constants/test-primary-link-url.constant';
|
|
||||||
import { TIM_ACCOUNT_ID } from 'test/integration/graphql/integration.constants';
|
|
||||||
|
|
||||||
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
|
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
|
||||||
|
import { WORKSPACE_MEMBER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant';
|
||||||
|
|
||||||
describe('Core REST API Create Many endpoint', () => {
|
describe('Core REST API Create Many endpoint', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@ -112,12 +112,12 @@ describe('Core REST API Create Many endpoint', () => {
|
|||||||
|
|
||||||
expect(createdPeople[0].createdBy.source).toBe(FieldActorSource.MANUAL);
|
expect(createdPeople[0].createdBy.source).toBe(FieldActorSource.MANUAL);
|
||||||
expect(createdPeople[0].createdBy.workspaceMemberId).toBe(
|
expect(createdPeople[0].createdBy.workspaceMemberId).toBe(
|
||||||
TIM_ACCOUNT_ID,
|
WORKSPACE_MEMBER_DATA_SEED_IDS.JANE,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(createdPeople[1].createdBy.source).toBe(FieldActorSource.MANUAL);
|
expect(createdPeople[1].createdBy.source).toBe(FieldActorSource.MANUAL);
|
||||||
expect(createdPeople[1].createdBy.workspaceMemberId).toBe(
|
expect(createdPeople[1].createdBy.workspaceMemberId).toBe(
|
||||||
TIM_ACCOUNT_ID,
|
WORKSPACE_MEMBER_DATA_SEED_IDS.JANE,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,12 +4,12 @@ import {
|
|||||||
TEST_PRIMARY_LINK_URL,
|
TEST_PRIMARY_LINK_URL,
|
||||||
TEST_PRIMARY_LINK_URL_WIITHOUT_TRAILING_SLASH,
|
TEST_PRIMARY_LINK_URL_WIITHOUT_TRAILING_SLASH,
|
||||||
} from 'test/integration/constants/test-primary-link-url.constant';
|
} from 'test/integration/constants/test-primary-link-url.constant';
|
||||||
import { TIM_ACCOUNT_ID } from 'test/integration/graphql/integration.constants';
|
|
||||||
import { makeRestAPIRequest } from 'test/integration/rest/utils/make-rest-api-request.util';
|
import { makeRestAPIRequest } from 'test/integration/rest/utils/make-rest-api-request.util';
|
||||||
import { deleteAllRecords } from 'test/integration/utils/delete-all-records';
|
import { deleteAllRecords } from 'test/integration/utils/delete-all-records';
|
||||||
import { generateRecordName } from 'test/integration/utils/generate-record-name';
|
import { generateRecordName } from 'test/integration/utils/generate-record-name';
|
||||||
|
|
||||||
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
|
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
|
||||||
|
import { WORKSPACE_MEMBER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant';
|
||||||
|
|
||||||
describe('Core REST API Create One endpoint', () => {
|
describe('Core REST API Create One endpoint', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@ -94,7 +94,9 @@ describe('Core REST API Create One endpoint', () => {
|
|||||||
const createdPerson = res.body.data.createPerson;
|
const createdPerson = res.body.data.createPerson;
|
||||||
|
|
||||||
expect(createdPerson.createdBy.source).toBe(FieldActorSource.MANUAL);
|
expect(createdPerson.createdBy.source).toBe(FieldActorSource.MANUAL);
|
||||||
expect(createdPerson.createdBy.workspaceMemberId).toBe(TIM_ACCOUNT_ID);
|
expect(createdPerson.createdBy.workspaceMemberId).toBe(
|
||||||
|
WORKSPACE_MEMBER_DATA_SEED_IDS.JANE,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user