mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-22 19:41:53 +03:00
Fast follows on 0.34 (#9034)
Co-authored-by: Weiko <corentin@twenty.com>
This commit is contained in:
parent
05cd0d1803
commit
77c2961912
@ -7,6 +7,9 @@ PG_DATABASE_HOST=db:5432
|
||||
REDIS_URL=redis://redis:6379
|
||||
|
||||
SERVER_URL=http://localhost:3000
|
||||
FRONT_DOMAIN=localhost
|
||||
FRONT_PORT=3000
|
||||
FRONT_PROTOCOL=http
|
||||
|
||||
# Use openssl rand -base64 32 for each secret
|
||||
# APP_SECRET=replace_me_with_a_random_string
|
||||
|
@ -24,7 +24,6 @@ services:
|
||||
PORT: 3000
|
||||
PG_DATABASE_URL: postgres://${PGUSER_SUPERUSER:-postgres}:${PGPASSWORD_SUPERUSER:-postgres}@${PG_DATABASE_HOST:-db:5432}/default
|
||||
SERVER_URL: ${SERVER_URL}
|
||||
FRONT_BASE_URL: ${FRONT_BASE_URL:-$SERVER_URL}
|
||||
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
|
||||
|
||||
ENABLE_DB_MIGRATIONS: "true"
|
||||
@ -54,9 +53,7 @@ services:
|
||||
environment:
|
||||
PG_DATABASE_URL: postgres://${PGUSER_SUPERUSER:-postgres}:${PGPASSWORD_SUPERUSER:-postgres}@${PG_DATABASE_HOST:-db:5432}/default
|
||||
SERVER_URL: ${SERVER_URL}
|
||||
FRONT_BASE_URL: ${FRONT_BASE_URL:-$SERVER_URL}
|
||||
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
|
||||
|
||||
ENABLE_DB_MIGRATIONS: "false" # it already runs on the server
|
||||
|
||||
STORAGE_TYPE: ${STORAGE_TYPE}
|
||||
|
@ -37,8 +37,6 @@ spec:
|
||||
value: 3000
|
||||
- name: SERVER_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: FRONT_BASE_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: "PG_DATABASE_URL"
|
||||
value: "postgres://postgres:postgres@twentycrm-db.twentycrm.svc.cluster.local/default"
|
||||
- name: "REDIS_URL"
|
||||
|
@ -28,8 +28,6 @@ spec:
|
||||
env:
|
||||
- name: SERVER_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: FRONT_BASE_URL
|
||||
value: "https://crm.example.com:443"
|
||||
- name: PG_DATABASE_URL
|
||||
value: "postgres://postgres:postgres@twentycrm-db.twentycrm.svc.cluster.local/default"
|
||||
- name: ENABLE_DB_MIGRATIONS
|
||||
|
@ -51,11 +51,6 @@ resource "kubernetes_deployment" "twentycrm_server" {
|
||||
value = var.twentycrm_app_hostname
|
||||
}
|
||||
|
||||
env {
|
||||
name = "FRONT_BASE_URL"
|
||||
value = var.twentycrm_app_hostname
|
||||
}
|
||||
|
||||
env {
|
||||
name = "PG_DATABASE_URL"
|
||||
value = "postgres://twenty:${var.twentycrm_pgdb_admin_password}@${kubernetes_service.twentycrm_db.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local/default"
|
||||
|
@ -43,11 +43,6 @@ resource "kubernetes_deployment" "twentycrm_worker" {
|
||||
value = var.twentycrm_app_hostname
|
||||
}
|
||||
|
||||
env {
|
||||
name = "FRONT_BASE_URL"
|
||||
value = var.twentycrm_app_hostname
|
||||
}
|
||||
|
||||
env {
|
||||
name = "PG_DATABASE_URL"
|
||||
value = "postgres://twenty:${var.twentycrm_pgdb_admin_password}@${kubernetes_service.twentycrm_db.metadata.0.name}.${kubernetes_namespace.twentycrm.metadata.0.name}.svc.cluster.local/default"
|
||||
|
@ -2,13 +2,15 @@
|
||||
PG_DATABASE_URL=postgres://postgres:postgres@localhost:5432/default
|
||||
REDIS_URL=redis://localhost:6379
|
||||
|
||||
FRONT_BASE_URL=http://localhost:3001
|
||||
|
||||
APP_SECRET=replace_me_with_a_random_string
|
||||
SIGN_IN_PREFILLED=true
|
||||
|
||||
ACCESS_TOKEN_SECRET=replace_me_with_a_random_string_access
|
||||
|
||||
FRONT_PROTOCOL=http
|
||||
FRONT_DOMAIN=localhost
|
||||
FRONT_PORT=3001
|
||||
|
||||
# ———————— Optional ————————
|
||||
# PORT=3000
|
||||
# DEBUG_MODE=true
|
||||
|
@ -3,7 +3,6 @@ REDIS_URL=redis://localhost:6379
|
||||
|
||||
DEBUG_MODE=true
|
||||
DEBUG_PORT=9000
|
||||
FRONT_BASE_URL=http://localhost:3001
|
||||
APP_SECRET=replace_me_with_a_random_string
|
||||
SIGN_IN_PREFILLED=true
|
||||
EXCEPTION_HANDLER_DRIVER=console
|
||||
|
@ -6,7 +6,6 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||
import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity';
|
||||
import { AppTokenService } from 'src/engine/core-modules/app-token/services/app-token.service';
|
||||
import { AuthExceptionHandlerService } from 'src/engine/core-modules/auth/auth-exception-handler.service';
|
||||
import { GoogleAPIsAuthController } from 'src/engine/core-modules/auth/controllers/google-apis-auth.controller';
|
||||
import { GoogleAuthController } from 'src/engine/core-modules/auth/controllers/google-auth.controller';
|
||||
import { MicrosoftAPIsAuthController } from 'src/engine/core-modules/auth/controllers/microsoft-apis-auth.controller';
|
||||
@ -103,7 +102,6 @@ import { JwtAuthStrategy } from './strategies/jwt.auth.strategy';
|
||||
ResetPasswordService,
|
||||
SwitchWorkspaceService,
|
||||
TransientTokenService,
|
||||
AuthExceptionHandlerService,
|
||||
ApiKeyService,
|
||||
OAuthService,
|
||||
],
|
||||
|
@ -2,16 +2,16 @@ import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
|
||||
|
||||
import { Response } from 'express';
|
||||
|
||||
import { AuthExceptionHandlerService } from 'src/engine/core-modules/auth/auth-exception-handler.service';
|
||||
import {
|
||||
AuthException,
|
||||
AuthExceptionCode,
|
||||
} from 'src/engine/core-modules/auth/auth.exception';
|
||||
import { HttpExceptionHandlerService } from 'src/engine/core-modules/exception-handler/http-exception-handler.service';
|
||||
|
||||
@Catch(AuthException)
|
||||
export class AuthRestApiExceptionFilter implements ExceptionFilter {
|
||||
constructor(
|
||||
private readonly authExceptionHandlerService: AuthExceptionHandlerService,
|
||||
private readonly httpExceptionHandlerService: HttpExceptionHandlerService,
|
||||
) {}
|
||||
|
||||
catch(exception: AuthException, host: ArgumentsHost) {
|
||||
@ -21,7 +21,7 @@ export class AuthRestApiExceptionFilter implements ExceptionFilter {
|
||||
switch (exception.code) {
|
||||
case AuthExceptionCode.USER_NOT_FOUND:
|
||||
case AuthExceptionCode.CLIENT_NOT_FOUND:
|
||||
return this.authExceptionHandlerService.handleError(
|
||||
return this.httpExceptionHandlerService.handleError(
|
||||
exception,
|
||||
response,
|
||||
404,
|
||||
@ -29,13 +29,13 @@ export class AuthRestApiExceptionFilter implements ExceptionFilter {
|
||||
case AuthExceptionCode.INVALID_INPUT:
|
||||
case AuthExceptionCode.INVALID_DATA:
|
||||
case AuthExceptionCode.MISSING_ENVIRONMENT_VARIABLE:
|
||||
return this.authExceptionHandlerService.handleError(
|
||||
return this.httpExceptionHandlerService.handleError(
|
||||
exception,
|
||||
response,
|
||||
400,
|
||||
);
|
||||
case AuthExceptionCode.FORBIDDEN_EXCEPTION:
|
||||
return this.authExceptionHandlerService.handleError(
|
||||
return this.httpExceptionHandlerService.handleError(
|
||||
exception,
|
||||
response,
|
||||
401,
|
||||
@ -43,14 +43,14 @@ export class AuthRestApiExceptionFilter implements ExceptionFilter {
|
||||
case AuthExceptionCode.GOOGLE_API_AUTH_DISABLED:
|
||||
case AuthExceptionCode.MICROSOFT_API_AUTH_DISABLED:
|
||||
case AuthExceptionCode.SIGNUP_DISABLED:
|
||||
return this.authExceptionHandlerService.handleError(
|
||||
return this.httpExceptionHandlerService.handleError(
|
||||
exception,
|
||||
response,
|
||||
403,
|
||||
);
|
||||
case AuthExceptionCode.INTERNAL_SERVER_ERROR:
|
||||
default:
|
||||
return this.authExceptionHandlerService.handleError(
|
||||
return this.httpExceptionHandlerService.handleError(
|
||||
exception,
|
||||
response,
|
||||
500,
|
||||
|
@ -26,6 +26,7 @@ import {
|
||||
} from 'src/engine/core-modules/auth/auth.util';
|
||||
import { AuthorizeApp } from 'src/engine/core-modules/auth/dto/authorize-app.entity';
|
||||
import { AuthorizeAppInput } from 'src/engine/core-modules/auth/dto/authorize-app.input';
|
||||
import { AvailableWorkspaceOutput } from 'src/engine/core-modules/auth/dto/available-workspaces.output';
|
||||
import { ChallengeInput } from 'src/engine/core-modules/auth/dto/challenge.input';
|
||||
import { UpdatePassword } from 'src/engine/core-modules/auth/dto/update-password.entity';
|
||||
import {
|
||||
@ -37,17 +38,16 @@ import { WorkspaceInviteHashValid } from 'src/engine/core-modules/auth/dto/works
|
||||
import { SignInUpService } from 'src/engine/core-modules/auth/services/sign-in-up.service';
|
||||
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
|
||||
import { RefreshTokenService } from 'src/engine/core-modules/auth/token/services/refresh-token.service';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
import { EmailService } from 'src/engine/core-modules/email/email.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||
import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service';
|
||||
import { AvailableWorkspaceOutput } from 'src/engine/core-modules/auth/dto/available-workspaces.output';
|
||||
import { UserService } from 'src/engine/core-modules/user/services/user.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { userValidator } from 'src/engine/core-modules/user/user.validate';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service';
|
||||
import { WorkspaceAuthProvider } from 'src/engine/core-modules/workspace/types/workspace.type';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
@Injectable()
|
||||
// eslint-disable-next-line @nx/workspace-inject-workspace-repository
|
||||
|
@ -21,10 +21,10 @@ import { EmailPasswordResetLink } from 'src/engine/core-modules/auth/dto/email-p
|
||||
import { InvalidatePassword } from 'src/engine/core-modules/auth/dto/invalidate-password.entity';
|
||||
import { PasswordResetToken } from 'src/engine/core-modules/auth/dto/token.entity';
|
||||
import { ValidatePasswordResetToken } from 'src/engine/core-modules/auth/dto/validate-password-reset-token.entity';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
import { EmailService } from 'src/engine/core-modules/email/email.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
|
||||
@Injectable()
|
||||
export class ResetPasswordService {
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
RawBodyRequest,
|
||||
Req,
|
||||
Res,
|
||||
UseFilters,
|
||||
} from '@nestjs/common';
|
||||
|
||||
import { Response } from 'express';
|
||||
@ -15,11 +16,13 @@ import {
|
||||
BillingExceptionCode,
|
||||
} from 'src/engine/core-modules/billing/billing.exception';
|
||||
import { WebhookEvent } from 'src/engine/core-modules/billing/enums/billing-webhook-events.enum';
|
||||
import { BillingRestApiExceptionFilter } from 'src/engine/core-modules/billing/filters/billing-api-exception.filter';
|
||||
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
|
||||
import { BillingWebhookEntitlementService } from 'src/engine/core-modules/billing/services/billing-webhook-entitlement.service';
|
||||
import { BillingWebhookSubscriptionService } from 'src/engine/core-modules/billing/services/billing-webhook-subscription.service';
|
||||
import { StripeService } from 'src/engine/core-modules/billing/stripe/stripe.service';
|
||||
@Controller('billing')
|
||||
@UseFilters(BillingRestApiExceptionFilter)
|
||||
export class BillingController {
|
||||
protected readonly logger = new Logger(BillingController.name);
|
||||
|
||||
|
@ -10,6 +10,7 @@ import { BillingPrice } from 'src/engine/core-modules/billing/entities/billing-p
|
||||
import { BillingProduct } from 'src/engine/core-modules/billing/entities/billing-product.entity';
|
||||
import { BillingSubscriptionItem } from 'src/engine/core-modules/billing/entities/billing-subscription-item.entity';
|
||||
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||
import { BillingRestApiExceptionFilter } from 'src/engine/core-modules/billing/filters/billing-api-exception.filter';
|
||||
import { BillingWorkspaceMemberListener } from 'src/engine/core-modules/billing/listeners/billing-workspace-member.listener';
|
||||
import { BillingPortalWorkspaceService } from 'src/engine/core-modules/billing/services/billing-portal.workspace-service';
|
||||
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
|
||||
@ -53,6 +54,7 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
BillingResolver,
|
||||
BillingWorkspaceMemberListener,
|
||||
BillingService,
|
||||
BillingRestApiExceptionFilter,
|
||||
],
|
||||
exports: [
|
||||
BillingSubscriptionService,
|
||||
|
@ -0,0 +1,37 @@
|
||||
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
|
||||
|
||||
import { Response } from 'express';
|
||||
import Stripe from 'stripe';
|
||||
|
||||
import {
|
||||
BillingException,
|
||||
BillingExceptionCode,
|
||||
} from 'src/engine/core-modules/billing/billing.exception';
|
||||
import { HttpExceptionHandlerService } from 'src/engine/core-modules/exception-handler/http-exception-handler.service';
|
||||
|
||||
@Catch(BillingException, Stripe.errors.StripeError)
|
||||
export class BillingRestApiExceptionFilter implements ExceptionFilter {
|
||||
constructor(
|
||||
private readonly httpExceptionHandlerService: HttpExceptionHandlerService,
|
||||
) {}
|
||||
|
||||
catch(exception: BillingException, host: ArgumentsHost) {
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse<Response>();
|
||||
|
||||
switch (exception.code) {
|
||||
case BillingExceptionCode.BILLING_CUSTOMER_NOT_FOUND:
|
||||
return this.httpExceptionHandlerService.handleError(
|
||||
exception,
|
||||
response,
|
||||
404,
|
||||
);
|
||||
default:
|
||||
return this.httpExceptionHandlerService.handleError(
|
||||
exception,
|
||||
response,
|
||||
500,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -31,10 +31,13 @@ export class BillingPortalWorkspaceService {
|
||||
priceId: string,
|
||||
successUrlPath?: string,
|
||||
): Promise<string> {
|
||||
const frontBaseUrl = this.domainManagerService.getBaseUrl().toString();
|
||||
const successUrl = successUrlPath
|
||||
? frontBaseUrl + successUrlPath
|
||||
: frontBaseUrl;
|
||||
const frontBaseUrl = this.domainManagerService.getBaseUrl();
|
||||
const cancelUrl = frontBaseUrl.toString();
|
||||
|
||||
if (successUrlPath) {
|
||||
frontBaseUrl.pathname = successUrlPath;
|
||||
}
|
||||
const successUrl = frontBaseUrl.toString();
|
||||
|
||||
const quantity = await this.userWorkspaceRepository.countBy({
|
||||
workspaceId: workspace.id,
|
||||
@ -51,7 +54,7 @@ export class BillingPortalWorkspaceService {
|
||||
priceId,
|
||||
quantity,
|
||||
successUrl,
|
||||
frontBaseUrl,
|
||||
cancelUrl,
|
||||
stripeCustomerId,
|
||||
);
|
||||
|
||||
@ -81,10 +84,12 @@ export class BillingPortalWorkspaceService {
|
||||
throw new Error('Error: missing stripeCustomerId');
|
||||
}
|
||||
|
||||
const frontBaseUrl = this.domainManagerService.getBaseUrl().toString();
|
||||
const returnUrl = returnUrlPath
|
||||
? frontBaseUrl + returnUrlPath
|
||||
: frontBaseUrl;
|
||||
const frontBaseUrl = this.domainManagerService.getBaseUrl();
|
||||
|
||||
if (returnUrlPath) {
|
||||
frontBaseUrl.pathname = returnUrlPath;
|
||||
}
|
||||
const returnUrl = frontBaseUrl.toString();
|
||||
|
||||
const session = await this.stripeService.createBillingPortalSession(
|
||||
stripeCustomerId,
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { DomainManagerModule } from 'src/engine/core-modules/domain-manager/domain-manager.module';
|
||||
|
||||
import { ClientConfigResolver } from './client-config.resolver';
|
||||
|
||||
@Module({
|
||||
imports: [DomainManagerModule],
|
||||
providers: [ClientConfigResolver],
|
||||
})
|
||||
export class ClientConfigModule {}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
|
||||
import { ClientConfigResolver } from './client-config.resolver';
|
||||
@ -15,6 +16,10 @@ describe('ClientConfigResolver', () => {
|
||||
provide: EnvironmentService,
|
||||
useValue: {},
|
||||
},
|
||||
{
|
||||
provide: DomainManagerService,
|
||||
useValue: {},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
@ -1,12 +1,16 @@
|
||||
import { Query, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
|
||||
import { ClientConfig } from './client-config.entity';
|
||||
|
||||
@Resolver()
|
||||
export class ClientConfigResolver {
|
||||
constructor(private environmentService: EnvironmentService) {}
|
||||
constructor(
|
||||
private environmentService: EnvironmentService,
|
||||
private domainManagerService: DomainManagerService,
|
||||
) {}
|
||||
|
||||
@Query(() => ClientConfig)
|
||||
async clientConfig(): Promise<ClientConfig> {
|
||||
@ -24,7 +28,7 @@ export class ClientConfigResolver {
|
||||
'IS_MULTIWORKSPACE_ENABLED',
|
||||
),
|
||||
defaultSubdomain: this.environmentService.get('DEFAULT_SUBDOMAIN'),
|
||||
frontDomain: this.environmentService.get('FRONT_DOMAIN'),
|
||||
frontDomain: this.domainManagerService.getFrontUrl().hostname,
|
||||
debugMode: this.environmentService.get('DEBUG_MODE'),
|
||||
support: {
|
||||
supportDriver: this.environmentService.get('SUPPORT_DRIVER'),
|
||||
|
@ -1,12 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/service/domain-manager.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
@Module({
|
||||
imports: [NestjsQueryTypeOrmModule.forFeature([Workspace], 'core')],
|
||||
imports: [TypeOrmModule.forFeature([Workspace], 'core')],
|
||||
providers: [DomainManagerService],
|
||||
exports: [DomainManagerService],
|
||||
})
|
||||
|
@ -21,10 +21,28 @@ export class DomainManagerService {
|
||||
private readonly environmentService: EnvironmentService,
|
||||
) {}
|
||||
|
||||
getBaseUrl() {
|
||||
const baseUrl = new URL(
|
||||
`${this.environmentService.get('FRONT_PROTOCOL')}://${this.environmentService.get('FRONT_DOMAIN')}`,
|
||||
);
|
||||
getFrontUrl() {
|
||||
let baseUrl: URL;
|
||||
|
||||
if (!this.environmentService.get('FRONT_DOMAIN')) {
|
||||
baseUrl = new URL(this.environmentService.get('SERVER_URL'));
|
||||
} else {
|
||||
baseUrl = new URL(
|
||||
`${this.environmentService.get('FRONT_PROTOCOL')}://${this.environmentService.get('FRONT_DOMAIN')}`,
|
||||
);
|
||||
|
||||
const port = this.environmentService.get('FRONT_PORT');
|
||||
|
||||
if (port) {
|
||||
baseUrl.port = port.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
getBaseUrl(): URL {
|
||||
const baseUrl = this.getFrontUrl();
|
||||
|
||||
if (
|
||||
this.environmentService.get('IS_MULTIWORKSPACE_ENABLED') &&
|
||||
@ -33,10 +51,6 @@ export class DomainManagerService {
|
||||
baseUrl.hostname = `${this.environmentService.get('DEFAULT_SUBDOMAIN')}.${baseUrl.hostname}`;
|
||||
}
|
||||
|
||||
if (this.environmentService.get('FRONT_PORT')) {
|
||||
baseUrl.port = this.environmentService.get('FRONT_PORT').toString();
|
||||
}
|
||||
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
@ -87,10 +101,9 @@ export class DomainManagerService {
|
||||
getWorkspaceSubdomainByOrigin = (origin: string) => {
|
||||
const { hostname: originHostname } = new URL(origin);
|
||||
|
||||
const subdomain = originHostname.replace(
|
||||
`.${this.environmentService.get('FRONT_DOMAIN')}`,
|
||||
'',
|
||||
);
|
||||
const frontDomain = this.getFrontUrl().hostname;
|
||||
|
||||
const subdomain = originHostname.replace(`.${frontDomain}`, '');
|
||||
|
||||
if (this.isDefaultSubdomain(subdomain)) {
|
||||
return;
|
||||
|
@ -129,7 +129,7 @@ export class EnvironmentVariables {
|
||||
// Frontend URL
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
FRONT_DOMAIN = 'localhost';
|
||||
FRONT_DOMAIN?: string;
|
||||
|
||||
@IsString()
|
||||
@ValidateIf((env) => env.IS_MULTIWORKSPACE_ENABLED)
|
||||
@ -137,12 +137,12 @@ export class EnvironmentVariables {
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
FRONT_PROTOCOL: 'http' | 'https' = 'http';
|
||||
FRONT_PROTOCOL?: 'http' | 'https' = 'http';
|
||||
|
||||
@CastToPositiveNumber()
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
FRONT_PORT = 3001;
|
||||
FRONT_PORT?: number;
|
||||
|
||||
@IsUrl({ require_tld: false, require_protocol: true })
|
||||
@IsOptional()
|
||||
|
@ -9,12 +9,13 @@ import {
|
||||
OPTIONS_TYPE,
|
||||
} from 'src/engine/core-modules/exception-handler/exception-handler.module-definition';
|
||||
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
|
||||
import { HttpExceptionHandlerService } from 'src/engine/core-modules/exception-handler/http-exception-handler.service';
|
||||
import { ExceptionHandlerDriver } from 'src/engine/core-modules/exception-handler/interfaces';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [ExceptionHandlerService],
|
||||
exports: [ExceptionHandlerService],
|
||||
providers: [ExceptionHandlerService, HttpExceptionHandlerService],
|
||||
exports: [ExceptionHandlerService, HttpExceptionHandlerService],
|
||||
})
|
||||
export class ExceptionHandlerModule extends ConfigurableModuleClass {
|
||||
static forRoot(options: typeof OPTIONS_TYPE): DynamicModule {
|
||||
|
@ -6,11 +6,11 @@ import { Response } from 'express';
|
||||
import { ExceptionHandlerUser } from 'src/engine/core-modules/exception-handler/interfaces/exception-handler-user.interface';
|
||||
import { ExceptionHandlerWorkspace } from 'src/engine/core-modules/exception-handler/interfaces/exception-handler-workspace.interface';
|
||||
|
||||
import { AuthException } from 'src/engine/core-modules/auth/auth.exception';
|
||||
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
|
||||
import { CustomException } from 'src/utils/custom-exception';
|
||||
|
||||
export const handleException = (
|
||||
exception: AuthException,
|
||||
exception: CustomException,
|
||||
exceptionHandlerService: ExceptionHandlerService,
|
||||
user?: ExceptionHandlerUser,
|
||||
workspace?: ExceptionHandlerWorkspace,
|
||||
@ -24,7 +24,7 @@ interface RequestAndParams {
|
||||
}
|
||||
|
||||
@Injectable({ scope: Scope.REQUEST })
|
||||
export class AuthExceptionHandlerService {
|
||||
export class HttpExceptionHandlerService {
|
||||
constructor(
|
||||
private readonly exceptionHandlerService: ExceptionHandlerService,
|
||||
@Inject(REQUEST)
|
||||
@ -32,7 +32,7 @@ export class AuthExceptionHandlerService {
|
||||
) {}
|
||||
|
||||
handleError = (
|
||||
exception: AuthException,
|
||||
exception: CustomException,
|
||||
response: Response<any, Record<string, any>>,
|
||||
errorCode?: number,
|
||||
user?: ExceptionHandlerUser,
|
@ -4,15 +4,15 @@ import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
|
||||
import fs from 'fs';
|
||||
|
||||
import session from 'express-session';
|
||||
import bytes from 'bytes';
|
||||
import { useContainer } from 'class-validator';
|
||||
import session from 'express-session';
|
||||
import { graphqlUploadExpress } from 'graphql-upload';
|
||||
|
||||
import { LoggerService } from 'src/engine/core-modules/logger/logger.service';
|
||||
import { ApplyCorsToExceptions } from 'src/utils/apply-cors-to-exceptions';
|
||||
import { getSessionStorageOptions } from 'src/engine/core-modules/session-storage/session-storage.module-factory';
|
||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||
import { LoggerService } from 'src/engine/core-modules/logger/logger.service';
|
||||
import { getSessionStorageOptions } from 'src/engine/core-modules/session-storage/session-storage.module-factory';
|
||||
import { UnhandledExceptionFilter } from 'src/utils/apply-cors-to-exceptions';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
import './instrument';
|
||||
@ -48,7 +48,7 @@ const bootstrap = async () => {
|
||||
// Use our logger
|
||||
app.useLogger(logger);
|
||||
|
||||
app.useGlobalFilters(new ApplyCorsToExceptions());
|
||||
app.useGlobalFilters(new UnhandledExceptionFilter());
|
||||
|
||||
// Apply validation pipes globally
|
||||
app.useGlobalPipes(
|
||||
|
@ -11,7 +11,7 @@ import { Response } from 'express';
|
||||
// the CORS headers are missing in the response.
|
||||
// This class add CORS headers to exception response to avoid misleading CORS error
|
||||
@Catch()
|
||||
export class ApplyCorsToExceptions implements ExceptionFilter {
|
||||
export class UnhandledExceptionFilter implements ExceptionFilter {
|
||||
catch(exception: any, host: ArgumentsHost) {
|
||||
const ctx = host.switchToHttp();
|
||||
const response = ctx.getResponse<Response>();
|
||||
@ -20,6 +20,7 @@ export class ApplyCorsToExceptions implements ExceptionFilter {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Check if needed, remove otherwise.
|
||||
response.header('Access-Control-Allow-Origin', '*');
|
||||
response.header(
|
||||
'Access-Control-Allow-Methods',
|
||||
|
@ -32,7 +32,14 @@ yarn command:prod upgrade-0.34
|
||||
The `yarn database:migrate:prod` command will apply the migrations to the database structure (core and metadata schemas)
|
||||
The `yarn command:prod upgrade-0.34` takes care of the data migration of all workspaces.
|
||||
|
||||
**Environment Variables**
|
||||
|
||||
- Removed: `FRONT_BASE_URL`
|
||||
- Added: `FRONT_DOMAIN`, `FRONT_PROTOCOL`, `FRONT_PORT`
|
||||
|
||||
We have updated the way we handle the frontend URL.
|
||||
You can now set the frontend URL using the `FRONT_DOMAIN`, `FRONT_PROTOCOL` and `FRONT_PORT` variables.
|
||||
If FRONT_DOMAIN is not set, the frontend URL will fallback to `SERVER_URL`.
|
||||
|
||||
### v0.32.0 to v0.33.0
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user