feat: multi-workspace (frontend) (#4232)
* select workspace component * generateJWT mutation * workspaces state and hooks * requested changes * mutation fix * requested changes * user workpsace delete call * migration to drop and createt user workspace * revert select props * add DropdownMenu * seperate multi-workspace dropdown as component * Signup button displayed accurately * update seed data for multi-workspace * lint fix * lint fix * css fix * lint fix * state fix * isDefined check * refactor * add default workspace constants for logo and name * update migration * lint fix * isInviteMode check on sign-in/up * removeWorkspaceMember mutation * import fixes * prop name fix * backfill migration * handle edge cases * refactor * remove migration query * delete user on no-workspace found condition * emit workspaceMember.deleted * Fix event class and unrelated fix linked to a previously missing dependency * Edit migration (I did it in prod manually) * Revert changes * Fix tests * Fix conflicts --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
@ -15,6 +15,10 @@ import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/work
|
||||
import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service';
|
||||
import { seedCalendarEvents } from 'src/database/typeorm-seeds/workspace/calendar-events';
|
||||
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
|
||||
import {
|
||||
SeedAppleWorkspaceId,
|
||||
SeedTwentyWorkspaceId,
|
||||
} from 'src/database/typeorm-seeds/core/workspaces';
|
||||
|
||||
// TODO: implement dry-run
|
||||
@Command({
|
||||
@ -23,7 +27,7 @@ import { EnvironmentService } from 'src/engine/integrations/environment/environm
|
||||
'Seed workspace with initial data. This command is intended for development only.',
|
||||
})
|
||||
export class DataSeedWorkspaceCommand extends CommandRunner {
|
||||
workspaceId = '20202020-1c25-4d02-bf25-6aeccf7ea419';
|
||||
workspaceIds = [SeedAppleWorkspaceId, SeedTwentyWorkspaceId];
|
||||
|
||||
constructor(
|
||||
private readonly environmentService: EnvironmentService,
|
||||
@ -45,79 +49,88 @@ export class DataSeedWorkspaceCommand extends CommandRunner {
|
||||
schema: 'core',
|
||||
});
|
||||
|
||||
await dataSource.initialize();
|
||||
for (const workspaceId of this.workspaceIds) {
|
||||
await dataSource.initialize();
|
||||
|
||||
await seedCoreSchema(dataSource, this.workspaceId);
|
||||
await seedCoreSchema(dataSource, workspaceId);
|
||||
|
||||
await dataSource.destroy();
|
||||
await dataSource.destroy();
|
||||
|
||||
const schemaName =
|
||||
await this.workspaceDataSourceService.createWorkspaceDBSchema(
|
||||
this.workspaceId,
|
||||
);
|
||||
const schemaName =
|
||||
await this.workspaceDataSourceService.createWorkspaceDBSchema(
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const dataSourceMetadata =
|
||||
await this.dataSourceService.createDataSourceMetadata(
|
||||
this.workspaceId,
|
||||
schemaName,
|
||||
);
|
||||
const dataSourceMetadata =
|
||||
await this.dataSourceService.createDataSourceMetadata(
|
||||
workspaceId,
|
||||
schemaName,
|
||||
);
|
||||
|
||||
await this.workspaceSyncMetadataService.synchronize({
|
||||
workspaceId: this.workspaceId,
|
||||
dataSourceId: dataSourceMetadata.id,
|
||||
});
|
||||
await this.workspaceSyncMetadataService.synchronize({
|
||||
workspaceId: workspaceId,
|
||||
dataSourceId: dataSourceMetadata.id,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const dataSourceMetadata =
|
||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
||||
this.workspaceId,
|
||||
);
|
||||
|
||||
const workspaceDataSource =
|
||||
await this.typeORMService.connectToDataSource(dataSourceMetadata);
|
||||
|
||||
if (!workspaceDataSource) {
|
||||
throw new Error('Could not connect to workspace data source');
|
||||
}
|
||||
|
||||
try {
|
||||
const objectMetadata =
|
||||
await this.objectMetadataService.findManyWithinWorkspace(
|
||||
this.workspaceId,
|
||||
for (const workspaceId of this.workspaceIds) {
|
||||
const dataSourceMetadata =
|
||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
||||
workspaceId,
|
||||
);
|
||||
const objectMetadataMap = objectMetadata.reduce((acc, object) => {
|
||||
acc[object.nameSingular] = {
|
||||
id: object.id,
|
||||
fields: object.fields.reduce((acc, field) => {
|
||||
acc[field.name] = field.id;
|
||||
|
||||
return acc;
|
||||
}, {}),
|
||||
};
|
||||
const workspaceDataSource =
|
||||
await this.typeORMService.connectToDataSource(dataSourceMetadata);
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
if (!workspaceDataSource) {
|
||||
throw new Error('Could not connect to workspace data source');
|
||||
}
|
||||
|
||||
await seedCompanies(workspaceDataSource, dataSourceMetadata.schema);
|
||||
await seedPeople(workspaceDataSource, dataSourceMetadata.schema);
|
||||
await seedPipelineStep(workspaceDataSource, dataSourceMetadata.schema);
|
||||
await seedOpportunity(workspaceDataSource, dataSourceMetadata.schema);
|
||||
await seedCalendarEvents(workspaceDataSource, dataSourceMetadata.schema);
|
||||
try {
|
||||
const objectMetadata =
|
||||
await this.objectMetadataService.findManyWithinWorkspace(workspaceId);
|
||||
const objectMetadataMap = objectMetadata.reduce((acc, object) => {
|
||||
acc[object.nameSingular] = {
|
||||
id: object.id,
|
||||
fields: object.fields.reduce((acc, field) => {
|
||||
acc[field.name] = field.id;
|
||||
|
||||
await seedViews(
|
||||
workspaceDataSource,
|
||||
dataSourceMetadata.schema,
|
||||
objectMetadataMap,
|
||||
);
|
||||
await seedWorkspaceMember(workspaceDataSource, dataSourceMetadata.schema);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return acc;
|
||||
}, {}),
|
||||
};
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
await seedCompanies(workspaceDataSource, dataSourceMetadata.schema);
|
||||
await seedPeople(workspaceDataSource, dataSourceMetadata.schema);
|
||||
await seedPipelineStep(workspaceDataSource, dataSourceMetadata.schema);
|
||||
await seedOpportunity(workspaceDataSource, dataSourceMetadata.schema);
|
||||
await seedCalendarEvents(
|
||||
workspaceDataSource,
|
||||
dataSourceMetadata.schema,
|
||||
);
|
||||
|
||||
await seedViews(
|
||||
workspaceDataSource,
|
||||
dataSourceMetadata.schema,
|
||||
objectMetadataMap,
|
||||
);
|
||||
await seedWorkspaceMember(
|
||||
workspaceDataSource,
|
||||
dataSourceMetadata.schema,
|
||||
workspaceId,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
await this.typeORMService.disconnectFromDataSource(dataSourceMetadata.id);
|
||||
}
|
||||
|
||||
await this.typeORMService.disconnectFromDataSource(dataSourceMetadata.id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import {
|
||||
SeedAppleWorkspaceId,
|
||||
SeedTwentyWorkspaceId,
|
||||
} from 'src/database/typeorm-seeds/core/workspaces';
|
||||
import { UserWorkspace } from 'src/engine/modules/user-workspace/user-workspace.entity';
|
||||
|
||||
// import { SeedWorkspaceId } from 'src/database/typeorm-seeds/core/workspaces';
|
||||
|
||||
const tableName = 'userWorkspace';
|
||||
@ -15,12 +21,10 @@ export const seedUserWorkspaces = async (
|
||||
schemaName: string,
|
||||
workspaceId: string,
|
||||
) => {
|
||||
await workspaceDataSource
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into(`${schemaName}.${tableName}`, ['userId', 'workspaceId'])
|
||||
.orIgnore()
|
||||
.values([
|
||||
let userWorkspaces: Pick<UserWorkspace, 'userId' | 'workspaceId'>[] = [];
|
||||
|
||||
if (workspaceId === SeedAppleWorkspaceId) {
|
||||
userWorkspaces = [
|
||||
{
|
||||
userId: SeedUserIds.Tim,
|
||||
workspaceId,
|
||||
@ -33,7 +37,23 @@ export const seedUserWorkspaces = async (
|
||||
userId: SeedUserIds.Phil,
|
||||
workspaceId,
|
||||
},
|
||||
])
|
||||
];
|
||||
}
|
||||
|
||||
if (workspaceId === SeedTwentyWorkspaceId) {
|
||||
userWorkspaces = [
|
||||
{
|
||||
userId: SeedUserIds.Tim,
|
||||
workspaceId,
|
||||
},
|
||||
];
|
||||
}
|
||||
await workspaceDataSource
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into(`${schemaName}.${tableName}`, ['userId', 'workspaceId'])
|
||||
.orIgnore()
|
||||
.values(userWorkspaces)
|
||||
.execute();
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1,6 +1,11 @@
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import { SeedUserIds } from 'src/database/typeorm-seeds/core/users';
|
||||
import {
|
||||
SeedAppleWorkspaceId,
|
||||
SeedTwentyWorkspaceId,
|
||||
} from 'src/database/typeorm-seeds/core/workspaces';
|
||||
import { WorkspaceMember } from 'src/engine/modules/user/dtos/workspace-member.dto';
|
||||
|
||||
const tableName = 'workspaceMember';
|
||||
|
||||
@ -10,24 +15,25 @@ const WorkspaceMemberIds = {
|
||||
Phil: '20202020-1553-45c6-a028-5a9064cce07f',
|
||||
};
|
||||
|
||||
type WorkspaceMembers = Pick<
|
||||
WorkspaceMember,
|
||||
'id' | 'locale' | 'colorScheme'
|
||||
> & {
|
||||
nameFirstName: string;
|
||||
nameLastName: string;
|
||||
userEmail: string;
|
||||
userId: string;
|
||||
};
|
||||
|
||||
export const seedWorkspaceMember = async (
|
||||
workspaceDataSource: DataSource,
|
||||
schemaName: string,
|
||||
workspaceId: string,
|
||||
) => {
|
||||
await workspaceDataSource
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into(`${schemaName}.${tableName}`, [
|
||||
'id',
|
||||
'nameFirstName',
|
||||
'nameLastName',
|
||||
'locale',
|
||||
'colorScheme',
|
||||
'userEmail',
|
||||
'userId',
|
||||
])
|
||||
.orIgnore()
|
||||
.values([
|
||||
let workspaceMembers: WorkspaceMembers[] = [];
|
||||
|
||||
if (workspaceId === SeedAppleWorkspaceId) {
|
||||
workspaceMembers = [
|
||||
{
|
||||
id: WorkspaceMemberIds.Tim,
|
||||
nameFirstName: 'Tim',
|
||||
@ -55,6 +61,35 @@ export const seedWorkspaceMember = async (
|
||||
userEmail: 'phil.schiler@apple.dev',
|
||||
userId: SeedUserIds.Phil,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (workspaceId === SeedTwentyWorkspaceId) {
|
||||
workspaceMembers = [
|
||||
{
|
||||
id: WorkspaceMemberIds.Tim,
|
||||
nameFirstName: 'Tim',
|
||||
nameLastName: 'Apple',
|
||||
locale: 'en',
|
||||
colorScheme: 'Light',
|
||||
userEmail: 'tim@apple.dev',
|
||||
userId: SeedUserIds.Tim,
|
||||
},
|
||||
];
|
||||
}
|
||||
await workspaceDataSource
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into(`${schemaName}.${tableName}`, [
|
||||
'id',
|
||||
'nameFirstName',
|
||||
'nameLastName',
|
||||
'locale',
|
||||
'colorScheme',
|
||||
'userEmail',
|
||||
'userId',
|
||||
])
|
||||
.orIgnore()
|
||||
.values(workspaceMembers)
|
||||
.execute();
|
||||
};
|
||||
|
||||
@ -14,10 +14,6 @@ export class AddUserWorkspaces1707778127558 implements MigrationInterface {
|
||||
"deletedAt" TIMESTAMP
|
||||
)`,
|
||||
);
|
||||
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."user" DROP CONSTRAINT "FK_2ec910029395fa7655621c88908"`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {}
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class updateUserWorkspaceColumnConstraints1709680520888
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'updateUserWorkspaceColumnConstraints1709680520888';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// ----------------- WARNING ------------------------
|
||||
// Dropping constraints and adding them back is NOT a recommended and should be AVOIDED,
|
||||
// since it can affect data integrity and cause downtime and unintentional data loss.
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."userWorkspace" DROP CONSTRAINT "userWorkspace_userId_fkey"`,
|
||||
);
|
||||
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."userWorkspace" DROP CONSTRAINT "userWorkspace_workspaceId_fkey"`,
|
||||
);
|
||||
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."userWorkspace" DROP CONSTRAINT "FK_cb488f32c6a0827b938edadf221"`,
|
||||
);
|
||||
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."userWorkspace" DROP CONSTRAINT "FK_37fdc7357af701e595c5c3a9bd6"`,
|
||||
);
|
||||
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "core"."userWorkspace"
|
||||
ADD CONSTRAINT "FK_37fdc7357af701e595c5c3a9bd6"
|
||||
FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id")
|
||||
ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
`);
|
||||
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE "core"."userWorkspace"
|
||||
ADD CONSTRAINT "FK_cb488f32c6a0827b938edadf221"
|
||||
FOREIGN KEY ("userId") REFERENCES "core"."user"("id")
|
||||
ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(): Promise<void> {}
|
||||
}
|
||||
@ -20,7 +20,9 @@ describe('FieldUtils', () => {
|
||||
checkFields(objectMetadataItemMock, ['fieldNumber']),
|
||||
).not.toThrow();
|
||||
|
||||
expect(() => checkFields(objectMetadataItemMock, ['wrongField'])).toThrow();
|
||||
expect(() =>
|
||||
checkFields(objectMetadataItemMock, ['wrongField']),
|
||||
).toThrow();
|
||||
|
||||
expect(() =>
|
||||
checkFields(objectMetadataItemMock, ['fieldNumber', 'wrongField']),
|
||||
|
||||
@ -4,6 +4,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
import { User } from 'src/engine/modules/user/user.entity';
|
||||
import { DataSourceService } from 'src/engine-metadata/data-source/data-source.service';
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { UserWorkspace } from 'src/engine/modules/user-workspace/user-workspace.entity';
|
||||
|
||||
import { UserService } from './user.service';
|
||||
|
||||
@ -18,6 +19,10 @@ describe('UserService', () => {
|
||||
provide: getRepositoryToken(User, 'core'),
|
||||
useValue: {},
|
||||
},
|
||||
{
|
||||
provide: getRepositoryToken(UserWorkspace, 'core'),
|
||||
useValue: {},
|
||||
},
|
||||
{
|
||||
provide: DataSourceService,
|
||||
useValue: {},
|
||||
|
||||
@ -8,12 +8,15 @@ import { User } from 'src/engine/modules/user/user.entity';
|
||||
import { WorkspaceMember } from 'src/engine/modules/user/dtos/workspace-member.dto';
|
||||
import { DataSourceService } from 'src/engine-metadata/data-source/data-source.service';
|
||||
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { UserWorkspace } from 'src/engine/modules/user-workspace/user-workspace.entity';
|
||||
import { DataSourceEntity } from 'src/engine-metadata/data-source/data-source.entity';
|
||||
|
||||
export class UserService extends TypeOrmQueryService<User> {
|
||||
constructor(
|
||||
@InjectRepository(User, 'core')
|
||||
private readonly userRepository: Repository<User>,
|
||||
@InjectRepository(UserWorkspace, 'core')
|
||||
private readonly userWorkspaceRepository: Repository<UserWorkspace>,
|
||||
private readonly dataSourceService: DataSourceService,
|
||||
private readonly typeORMService: TypeORMService,
|
||||
) {
|
||||
@ -104,6 +107,8 @@ export class UserService extends TypeOrmQueryService<User> {
|
||||
`DELETE FROM ${dataSourceMetadata.schema}."workspaceMember" WHERE "userId" = '${userId}'`,
|
||||
);
|
||||
|
||||
await this.userWorkspaceRepository.delete({ userId });
|
||||
|
||||
await this.userRepository.delete(user.id);
|
||||
|
||||
return user;
|
||||
|
||||
@ -2,11 +2,11 @@ import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { Workspace } from 'src/engine/modules/workspace/workspace.entity';
|
||||
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
|
||||
import { UserWorkspace } from 'src/engine/modules/user-workspace/user-workspace.entity';
|
||||
import { User } from 'src/engine/modules/user/user.entity';
|
||||
import { BillingService } from 'src/engine/modules/billing/billing.service';
|
||||
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
|
||||
import { UserWorkspaceService } from 'src/engine/modules/user-workspace/user-workspace.service';
|
||||
import { BillingService } from 'src/engine/modules/billing/billing.service';
|
||||
|
||||
import { WorkspaceService } from './workspace.service';
|
||||
|
||||
|
||||
@ -6,13 +6,13 @@ import assert from 'assert';
|
||||
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
|
||||
import { Workspace } from 'src/engine/modules/workspace/workspace.entity';
|
||||
import { User } from 'src/engine/modules/user/user.entity';
|
||||
import { ActivateWorkspaceInput } from 'src/engine/modules/workspace/dtos/activate-workspace-input';
|
||||
import { UserWorkspace } from 'src/engine/modules/user-workspace/user-workspace.entity';
|
||||
import { User } from 'src/engine/modules/user/user.entity';
|
||||
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
|
||||
import { UserWorkspaceService } from 'src/engine/modules/user-workspace/user-workspace.service';
|
||||
import { BillingService } from 'src/engine/modules/billing/billing.service';
|
||||
import { ActivateWorkspaceInput } from 'src/engine/modules/workspace/dtos/activate-workspace-input';
|
||||
|
||||
export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
||||
constructor(
|
||||
@ -70,4 +70,118 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
||||
.find()
|
||||
.then((workspaces) => workspaces.map((workspace) => workspace.id));
|
||||
}
|
||||
|
||||
private async reassignDefaultWorkspace(
|
||||
currentWorkspaceId: string,
|
||||
user: User,
|
||||
worskpaces: UserWorkspace[],
|
||||
) {
|
||||
// We'll filter all user workspaces without the one which its getting removed from
|
||||
const filteredUserWorkspaces = worskpaces.filter(
|
||||
(workspace) => workspace.workspaceId !== currentWorkspaceId,
|
||||
);
|
||||
|
||||
// Loop over each workspace in the filteredUserWorkspaces array and check if it currently exists in
|
||||
// the database
|
||||
for (let index = 0; index < filteredUserWorkspaces.length; index++) {
|
||||
const userWorkspace = filteredUserWorkspaces[index];
|
||||
|
||||
const nextWorkspace = await this.workspaceRepository.findOneBy({
|
||||
id: userWorkspace.workspaceId,
|
||||
});
|
||||
|
||||
if (nextWorkspace) {
|
||||
await this.userRepository.save({
|
||||
id: user.id,
|
||||
defaultWorkspace: nextWorkspace,
|
||||
updatedAt: new Date().toISOString(),
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// if no workspaces are valid then we delete the user
|
||||
if (index === filteredUserWorkspaces.length - 1) {
|
||||
await this.userRepository.delete({ id: user.id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
async removeWorkspaceMember(workspaceId: string, memberId: string) {
|
||||
const dataSourceMetadata =
|
||||
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
const workspaceDataSource =
|
||||
await this.typeORMService.connectToDataSource(dataSourceMetadata);
|
||||
|
||||
// using "SELECT *" here because we will need the corresponding members userId later
|
||||
const [workspaceMember] = await workspaceDataSource?.query(
|
||||
`SELECT * FROM ${dataSourceMetadata.schema}."workspaceMember" WHERE "id" = '${memberId}'`,
|
||||
);
|
||||
|
||||
if (!workspaceMember) {
|
||||
throw new NotFoundException('Member not found.');
|
||||
}
|
||||
|
||||
await workspaceDataSource?.query(
|
||||
`DELETE FROM ${dataSourceMetadata.schema}."workspaceMember" WHERE "id" = '${memberId}'`,
|
||||
);
|
||||
|
||||
const workspaceMemberUser = await this.userRepository.findOne({
|
||||
where: {
|
||||
id: workspaceMember.userId,
|
||||
},
|
||||
relations: ['defaultWorkspace'],
|
||||
});
|
||||
|
||||
if (!workspaceMemberUser) {
|
||||
throw new NotFoundException('User not found');
|
||||
}
|
||||
|
||||
const userWorkspaces = await this.userWorkspaceRepository.find({
|
||||
where: { userId: workspaceMemberUser.id },
|
||||
relations: ['workspace'],
|
||||
});
|
||||
|
||||
// We want to check if we the user has signed up to more than one workspace
|
||||
if (userWorkspaces.length > 1) {
|
||||
// We neeed to check if the workspace that its getting removed from is its default workspace, if it is then
|
||||
// change the default workspace to point to the next workspace available.
|
||||
if (workspaceMemberUser.defaultWorkspace.id === workspaceId) {
|
||||
await this.reassignDefaultWorkspace(
|
||||
workspaceId,
|
||||
workspaceMemberUser,
|
||||
userWorkspaces,
|
||||
);
|
||||
}
|
||||
// if its not the default workspace then simply delete the user-workspace mapping
|
||||
await this.userWorkspaceRepository.delete({
|
||||
userId: workspaceMemberUser.id,
|
||||
workspaceId,
|
||||
});
|
||||
} else {
|
||||
await this.userWorkspaceRepository.delete({
|
||||
userId: workspaceMemberUser.id,
|
||||
});
|
||||
|
||||
// After deleting the user-workspace mapping, we have a condition where we have the users default workspace points to a
|
||||
// workspace which it doesnt have access to. So we delete the user.
|
||||
await this.userRepository.delete({ id: workspaceMemberUser.id });
|
||||
}
|
||||
|
||||
const payload =
|
||||
new ObjectRecordDeleteEvent<WorkspaceMemberObjectMetadata>();
|
||||
|
||||
payload.workspaceId = workspaceId;
|
||||
payload.details = {
|
||||
before: workspaceMember,
|
||||
};
|
||||
|
||||
this.eventEmitter.emit('workspaceMember.deleted', payload);
|
||||
|
||||
return memberId;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@ -6,15 +6,16 @@ import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
|
||||
import { WorkspaceResolver } from 'src/engine/modules/workspace/workspace.resolver';
|
||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||
import { FeatureFlagEntity } from 'src/engine/modules/feature-flag/feature-flag.entity';
|
||||
import { UserWorkspace } from 'src/engine/modules/user-workspace/user-workspace.entity';
|
||||
import { User } from 'src/engine/modules/user/user.entity';
|
||||
import { UserWorkspaceModule } from 'src/engine/modules/user-workspace/user-workspace.module';
|
||||
import { BillingModule } from 'src/engine/modules/billing/billing.module';
|
||||
import { UserWorkspace } from 'src/engine/modules/user-workspace/user-workspace.entity';
|
||||
import { FeatureFlagEntity } from 'src/engine/modules/feature-flag/feature-flag.entity';
|
||||
import { UserWorkspaceModule } from 'src/engine/modules/user-workspace/user-workspace.module';
|
||||
import { User } from 'src/engine/modules/user/user.entity';
|
||||
import { DataSourceModule } from 'src/engine-metadata/data-source/data-source.module';
|
||||
import { FileUploadModule } from 'src/engine/modules/file/file-upload/file-upload.module';
|
||||
|
||||
import { Workspace } from './workspace.entity';
|
||||
import { workspaceAutoResolverOpts } from './workspace.auto-resolver-opts';
|
||||
import { Workspace } from './workspace.entity';
|
||||
|
||||
import { WorkspaceService } from './services/workspace.service';
|
||||
|
||||
@ -31,6 +32,8 @@ import { WorkspaceService } from './services/workspace.service';
|
||||
),
|
||||
UserWorkspaceModule,
|
||||
WorkspaceManagerModule,
|
||||
DataSourceModule,
|
||||
TypeORMModule,
|
||||
],
|
||||
services: [WorkspaceService],
|
||||
resolvers: workspaceAutoResolverOpts,
|
||||
|
||||
Reference in New Issue
Block a user