feat(*): allow to select auth providers + add multiworkspace with subdomain management (#8656)

## Summary
Add support for multi-workspace feature and adjust configurations and
states accordingly.
- Introduced new state isMultiWorkspaceEnabledState.
- Updated ClientConfigProviderEffect component to handle
multi-workspace.
- Modified GraphQL schema and queries to include multi-workspace related
configurations.
- Adjusted server environment variables and their respective
documentation to support multi-workspace toggle.
- Updated server-side logic to handle new multi-workspace configurations
and conditions.
This commit is contained in:
Antoine Moreaux
2024-12-03 19:06:28 +01:00
committed by GitHub
parent 9a65e80566
commit 7943141d03
167 changed files with 5180 additions and 1901 deletions

View File

@ -18,6 +18,11 @@ import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/worksp
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { userValidator } from 'src/engine/core-modules/user/user.validate';
import {
AuthException,
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
// eslint-disable-next-line @nx/workspace-inject-workspace-repository
export class UserService extends TypeOrmQueryService<User> {
@ -64,9 +69,7 @@ export class UserService extends TypeOrmQueryService<User> {
'workspaceMember',
);
const workspaceMembers = workspaceMemberRepository.find();
return workspaceMembers;
return workspaceMemberRepository.find();
}
async deleteUser(userId: string): Promise<User> {
@ -131,4 +134,29 @@ export class UserService extends TypeOrmQueryService<User> {
return user;
}
async saveDefaultWorkspace(userId: string, workspaceId: string) {
const user = await this.userRepository.findOne({
where: {
id: userId,
workspaces: {
workspaceId,
},
},
relations: ['workspaces'],
});
userValidator.assertIsExist(
user,
new AuthException(
'User does not have access to this workspace',
AuthExceptionCode.FORBIDDEN_EXCEPTION,
),
);
return await this.userRepository.save({
id: userId,
defaultWorkspaceId: workspaceId,
});
}
}

View File

@ -9,7 +9,6 @@ import {
} from '@nestjs/graphql';
import { InjectRepository } from '@nestjs/typeorm';
import assert from 'assert';
import crypto from 'crypto';
import { GraphQLJSONObject } from 'graphql-type-json';
@ -40,6 +39,11 @@ import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { streamToBuffer } from 'src/utils/stream-to-buffer';
import { AccountsToReconnectKeys } from 'src/modules/connected-account/types/accounts-to-reconnect-key-value.type';
import {
AuthException,
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { userValidator } from 'src/engine/core-modules/user/user.validate';
const getHMACKey = (email?: string, key?: string | null) => {
if (!email || !key) return null;
@ -65,7 +69,17 @@ export class UserResolver {
) {}
@Query(() => User)
async currentUser(@AuthUser() { id: userId }: User): Promise<User> {
async currentUser(
@AuthUser() { id: userId }: User,
@AuthWorkspace() { id: workspaceId }: Workspace,
): Promise<User> {
if (
this.environmentService.get('IS_MULTIWORKSPACE_ENABLED') &&
workspaceId
) {
await this.userService.saveDefaultWorkspace(userId, workspaceId);
}
const user = await this.userRepository.findOne({
where: {
id: userId,
@ -73,7 +87,10 @@ export class UserResolver {
relations: ['defaultWorkspace', 'workspaces', 'workspaces.workspace'],
});
assert(user, 'User not found');
userValidator.assertIsExist(
user,
new AuthException('User not found', AuthExceptionCode.USER_NOT_FOUND),
);
return user;
}

View File

@ -0,0 +1,34 @@
import { User } from 'src/engine/core-modules/user/user.entity';
import { CustomException } from 'src/utils/custom-exception';
const assertIsExist = (
user: User | undefined | null,
exceptionToThrow: CustomException,
): asserts user is User => {
if (!user) {
throw exceptionToThrow;
}
};
const isExist = (user: User | undefined | null): user is User => {
return !!user;
};
const assertHasDefaultWorkspace = (
user: User,
exceptionToThrow?: CustomException,
): asserts user is User & { defaultWorkspaceId: string } => {
if (!user.defaultWorkspaceId) {
throw exceptionToThrow;
}
};
export const userValidator: {
assertIsExist: typeof assertIsExist;
assertHasDefaultWorkspace: typeof assertHasDefaultWorkspace;
isExist: typeof isExist;
} = {
assertIsExist,
assertHasDefaultWorkspace,
isExist,
};