mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-23 03:51:36 +03:00
WIP
This commit is contained in:
parent
2ceb1c87b3
commit
f807021208
@ -30,6 +30,7 @@
|
|||||||
"cache-manager": "^5.4.0",
|
"cache-manager": "^5.4.0",
|
||||||
"cache-manager-redis-yet": "^4.1.2",
|
"cache-manager-redis-yet": "^4.1.2",
|
||||||
"class-validator": "patch:class-validator@0.14.0#./patches/class-validator+0.14.0.patch",
|
"class-validator": "patch:class-validator@0.14.0#./patches/class-validator+0.14.0.patch",
|
||||||
|
"cloudflare": "^3.5.0",
|
||||||
"connect-redis": "^7.1.1",
|
"connect-redis": "^7.1.1",
|
||||||
"express-session": "^1.18.1",
|
"express-session": "^1.18.1",
|
||||||
"graphql-middleware": "^6.1.35",
|
"graphql-middleware": "^6.1.35",
|
||||||
|
@ -246,6 +246,14 @@ export class EnvironmentVariables {
|
|||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
IS_MULTIWORKSPACE_ENABLED = false;
|
IS_MULTIWORKSPACE_ENABLED = false;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@ValidateIf((env) => env.CLOUDFLARE_ZONE_ID)
|
||||||
|
CLOUDFLARE_USER_SERVICE_KEY: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@ValidateIf((env) => env.CLOUDFLARE_USER_SERVICE_KEY)
|
||||||
|
CLOUDFLARE_ZONE_ID: string;
|
||||||
|
|
||||||
// Custom Code Engine
|
// Custom Code Engine
|
||||||
@IsEnum(ServerlessDriverType)
|
@IsEnum(ServerlessDriverType)
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ -18,6 +18,14 @@ export class UpdateWorkspaceInput {
|
|||||||
@ForbiddenWords(['demo'])
|
@ForbiddenWords(['demo'])
|
||||||
subdomain?: string;
|
subdomain?: string;
|
||||||
|
|
||||||
|
@Field({ nullable: true })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@Matches(
|
||||||
|
/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/,
|
||||||
|
)
|
||||||
|
domain?: string;
|
||||||
|
|
||||||
@Field({ nullable: true })
|
@Field({ nullable: true })
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ -3,6 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
|||||||
|
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
|
||||||
|
import Cloudflare from 'cloudflare';
|
||||||
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
@ -46,6 +47,48 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
|||||||
super(workspaceRepository);
|
super(workspaceRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async validateSubdomainUpdate(newSubdomain: string) {
|
||||||
|
const subdomainAvailable = await this.isSubdomainAvailable(newSubdomain);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!subdomainAvailable ||
|
||||||
|
this.environmentService.get('DEFAULT_SUBDOMAIN') === newSubdomain
|
||||||
|
) {
|
||||||
|
throw new WorkspaceException(
|
||||||
|
'Subdomain already taken',
|
||||||
|
WorkspaceExceptionCode.SUBDOMAIN_ALREADY_TAKEN,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async validateDomain(newDomain: string, workspaceId: string) {
|
||||||
|
const existingWorkspace = await this.isDomainAvailable(newDomain);
|
||||||
|
|
||||||
|
if (existingWorkspace) {
|
||||||
|
throw new WorkspaceException(
|
||||||
|
'Domain already taken',
|
||||||
|
WorkspaceExceptionCode.DOMAIN_ALREADY_TAKEN,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = new Cloudflare({
|
||||||
|
userServiceKey: this.environmentService.get(
|
||||||
|
'CLOUDFLARE_USER_SERVICE_KEY',
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const customHostname = await client.customHostnames.create({
|
||||||
|
zone_id: this.environmentService.get('CLOUDFLARE_ZONE_ID'),
|
||||||
|
hostname: newDomain,
|
||||||
|
ssl: {},
|
||||||
|
custom_metadata: {
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('>>>>>>>>>>>>>>', customHostname);
|
||||||
|
}
|
||||||
|
|
||||||
async updateWorkspaceById(payload: Partial<Workspace> & { id: string }) {
|
async updateWorkspaceById(payload: Partial<Workspace> & { id: string }) {
|
||||||
const workspace = await this.workspaceRepository.findOneBy({
|
const workspace = await this.workspaceRepository.findOneBy({
|
||||||
id: payload.id,
|
id: payload.id,
|
||||||
@ -60,19 +103,11 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (payload.subdomain && workspace.subdomain !== payload.subdomain) {
|
if (payload.subdomain && workspace.subdomain !== payload.subdomain) {
|
||||||
const subdomainAvailable = await this.isSubdomainAvailable(
|
await this.validateSubdomainUpdate(payload.subdomain);
|
||||||
payload.subdomain,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
!subdomainAvailable ||
|
|
||||||
this.environmentService.get('DEFAULT_SUBDOMAIN') === payload.subdomain
|
|
||||||
) {
|
|
||||||
throw new WorkspaceException(
|
|
||||||
'Subdomain already taken',
|
|
||||||
WorkspaceExceptionCode.SUBDOMAIN_ALREADY_TAKEN,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (payload.domain && workspace.domain !== payload.domain) {
|
||||||
|
await this.validateDomain(payload.domain, workspace.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.workspaceRepository.save({
|
return this.workspaceRepository.save({
|
||||||
@ -214,4 +249,12 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
|
|||||||
|
|
||||||
return !existingWorkspace;
|
return !existingWorkspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isDomainAvailable(domain: string) {
|
||||||
|
const existingWorkspace = await this.workspaceRepository.findOne({
|
||||||
|
where: { domain },
|
||||||
|
});
|
||||||
|
|
||||||
|
return !existingWorkspace;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ export class Workspace {
|
|||||||
@PrimaryGeneratedColumn('uuid')
|
@PrimaryGeneratedColumn('uuid')
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
|
// @deprecated. Use domain field
|
||||||
@Field({ nullable: true })
|
@Field({ nullable: true })
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
domainName?: string;
|
domainName?: string;
|
||||||
@ -147,6 +148,10 @@ export class Workspace {
|
|||||||
@Column()
|
@Column()
|
||||||
subdomain: string;
|
subdomain: string;
|
||||||
|
|
||||||
|
@Field()
|
||||||
|
@Column({ unique: true })
|
||||||
|
domain: string;
|
||||||
|
|
||||||
@Field()
|
@Field()
|
||||||
@Column({ default: true })
|
@Column({ default: true })
|
||||||
isGoogleAuthEnabled: boolean;
|
isGoogleAuthEnabled: boolean;
|
||||||
|
@ -9,5 +9,6 @@ export class WorkspaceException extends CustomException {
|
|||||||
export enum WorkspaceExceptionCode {
|
export enum WorkspaceExceptionCode {
|
||||||
SUBDOMAIN_NOT_FOUND = 'SUBDOMAIN_NOT_FOUND',
|
SUBDOMAIN_NOT_FOUND = 'SUBDOMAIN_NOT_FOUND',
|
||||||
SUBDOMAIN_ALREADY_TAKEN = 'SUBDOMAIN_ALREADY_TAKEN',
|
SUBDOMAIN_ALREADY_TAKEN = 'SUBDOMAIN_ALREADY_TAKEN',
|
||||||
|
DOMAIN_ALREADY_TAKEN = 'DOMAIN_ALREADY_TAKEN',
|
||||||
WORKSPACE_NOT_FOUND = 'WORKSPACE_NOT_FOUND',
|
WORKSPACE_NOT_FOUND = 'WORKSPACE_NOT_FOUND',
|
||||||
}
|
}
|
||||||
|
35
yarn.lock
35
yarn.lock
@ -16596,6 +16596,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/qs@npm:^6.9.7":
|
||||||
|
version: 6.9.17
|
||||||
|
resolution: "@types/qs@npm:6.9.17"
|
||||||
|
checksum: 10c0/a183fa0b3464267f8f421e2d66d960815080e8aab12b9aadab60479ba84183b1cdba8f4eff3c06f76675a8e42fe6a3b1313ea76c74f2885c3e25d32499c17d1b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/range-parser@npm:*":
|
"@types/range-parser@npm:*":
|
||||||
version: 1.2.7
|
version: 1.2.7
|
||||||
resolution: "@types/range-parser@npm:1.2.7"
|
resolution: "@types/range-parser@npm:1.2.7"
|
||||||
@ -22020,6 +22027,24 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"cloudflare@npm:^3.5.0":
|
||||||
|
version: 3.5.0
|
||||||
|
resolution: "cloudflare@npm:3.5.0"
|
||||||
|
dependencies:
|
||||||
|
"@types/node": "npm:^18.11.18"
|
||||||
|
"@types/node-fetch": "npm:^2.6.4"
|
||||||
|
"@types/qs": "npm:^6.9.7"
|
||||||
|
abort-controller: "npm:^3.0.0"
|
||||||
|
agentkeepalive: "npm:^4.2.1"
|
||||||
|
form-data-encoder: "npm:1.7.2"
|
||||||
|
formdata-node: "npm:^4.3.2"
|
||||||
|
node-fetch: "npm:^2.6.7"
|
||||||
|
qs: "npm:^6.10.3"
|
||||||
|
web-streams-polyfill: "npm:^3.2.1"
|
||||||
|
checksum: 10c0/bb48ff68a4f5b7e945ceec570e7e17251ad167d8d2dadf8099fd74df46582356382b8cd3f62a9da74cd3a208f8f5181a40c561bc5873592d6a4930458c0e7b86
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"clsx@npm:^1.1.1, clsx@npm:^1.2.1":
|
"clsx@npm:^1.1.1, clsx@npm:^1.2.1":
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
resolution: "clsx@npm:1.2.1"
|
resolution: "clsx@npm:1.2.1"
|
||||||
@ -38872,6 +38897,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"qs@npm:^6.10.3":
|
||||||
|
version: 6.13.1
|
||||||
|
resolution: "qs@npm:6.13.1"
|
||||||
|
dependencies:
|
||||||
|
side-channel: "npm:^1.0.6"
|
||||||
|
checksum: 10c0/5ef527c0d62ffca5501322f0832d800ddc78eeb00da3b906f1b260ca0492721f8cdc13ee4b8fd8ac314a6ec37b948798c7b603ccc167e954088df392092f160c
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"qs@npm:~6.5.2":
|
"qs@npm:~6.5.2":
|
||||||
version: 6.5.3
|
version: 6.5.3
|
||||||
resolution: "qs@npm:6.5.3"
|
resolution: "qs@npm:6.5.3"
|
||||||
@ -43990,6 +44024,7 @@ __metadata:
|
|||||||
cache-manager: "npm:^5.4.0"
|
cache-manager: "npm:^5.4.0"
|
||||||
cache-manager-redis-yet: "npm:^4.1.2"
|
cache-manager-redis-yet: "npm:^4.1.2"
|
||||||
class-validator: "patch:class-validator@0.14.0#./patches/class-validator+0.14.0.patch"
|
class-validator: "patch:class-validator@0.14.0#./patches/class-validator+0.14.0.patch"
|
||||||
|
cloudflare: "npm:^3.5.0"
|
||||||
connect-redis: "npm:^7.1.1"
|
connect-redis: "npm:^7.1.1"
|
||||||
express-session: "npm:^1.18.1"
|
express-session: "npm:^1.18.1"
|
||||||
graphql-middleware: "npm:^6.1.35"
|
graphql-middleware: "npm:^6.1.35"
|
||||||
|
Loading…
Reference in New Issue
Block a user