Skip to content

Commit

Permalink
fix(api): make typeorm work with 'ng serve api'
Browse files Browse the repository at this point in the history
  • Loading branch information
xmlking committed Nov 14, 2018
1 parent df7260b commit f561428
Show file tree
Hide file tree
Showing 25 changed files with 210 additions and 251 deletions.
1 change: 1 addition & 0 deletions PLAYBOOK.md
Expand Up @@ -301,6 +301,7 @@ ng g lib Notifications --prefix=ngx --tags=public-module --publishable=true --un
ng g component notifications --project=notifications --flat --dry-run
ng g class notification --type=model --project=notifications --dry-run
ng g service notifications --project=notifications --dry-run
ng g service PushNotification --project=notifications --dry-run

# generate components for `Quickpanel` Module
ng g lib Quickpanel --prefix=ngx --tags=private-module --unit-test-runner=jest
Expand Down
6 changes: 3 additions & 3 deletions apps/api/README.md
Expand Up @@ -46,10 +46,10 @@ docker rm 82be5234c94a
#### Run Dev Mode
```bash
# start in watch mode
npm run api:start:dev
ng serve api
# to turn on logging for `request`
NODE_DEBUG=request npm run api:start:dev
DEBUG=typeorm:* npm run api:start:dev
NODE_DEBUG=request ng serve api
DEBUG=typeorm:* ng serve api

# start
npm run api:start
Expand Down
3 changes: 1 addition & 2 deletions apps/api/src/auth/passport/jwt.strategy.ts
Expand Up @@ -5,11 +5,10 @@ import { passportJwtSecret, SigningKeyNotFoundError } from '@xmlking/jwks-rsa';

import { AuthService } from '../auth.service';
import { JwtToken } from '../interfaces/jwt-token.interface';
import { ConfigService } from '../../config';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly config: ConfigService, private readonly authService: AuthService) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
// secretOrKey: process.env.OIDC_PUBLIC_KEY,
Expand Down
3 changes: 1 addition & 2 deletions apps/api/src/auth/passport/ws-jwt.strategy.ts
Expand Up @@ -5,7 +5,6 @@ import { passportJwtSecret, SigningKeyNotFoundError } from '@xmlking/jwks-rsa';

import { AuthService } from '../auth.service';
import { JwtToken } from '../interfaces/jwt-token.interface';
import { ConfigService } from '../../config';
import { WsException } from '@nestjs/websockets';

const extractJwtFromWsQuery = req => {
Expand All @@ -20,7 +19,7 @@ const extractJwtFromWsQuery = req => {

@Injectable()
export class WsJwtStrategy extends PassportStrategy(Strategy, 'ws-jwt') {
constructor(private readonly config: ConfigService, private readonly authService: AuthService) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: extractJwtFromWsQuery, // ExtractJwt.fromUrlQueryParameter('token'),
// secretOrKey: process.env.OIDC_PUBLIC_KEY,
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/auth/user.entity.ts
@@ -1,7 +1,7 @@
import { Column, CreateDateColumn, Entity, Index, OneToMany, UpdateDateColumn, VersionColumn } from 'typeorm';
import { ApiModelProperty } from '@nestjs/swagger';
import { IsAscii, IsEmail, IsNotEmpty, IsString, MaxLength, MinLength } from 'class-validator';
import { Base } from '../core';
import { Base } from '../core/entities/base.entity';

export enum AccountSourceType {
msId,
Expand Down
22 changes: 6 additions & 16 deletions apps/api/src/config/config.module.ts
@@ -1,20 +1,10 @@
import { DynamicModule, Global, Module } from '@nestjs/common';
import { Global, Module } from '@nestjs/common';

import { ConfigService } from './config.service';

@Global()
@Module({})
export class ConfigModule {
static forRoot(filePath?: string): DynamicModule {
return {
module: ConfigModule,
providers: [
{
provide: ConfigService,
useValue: new ConfigService(filePath || `${process.env.NODE_ENV || 'development'}.env`),
},
],
exports: [ConfigService],
};
}
}
@Module({
providers: [ConfigService],
exports: [ConfigService],
})
export class ConfigModule {}
31 changes: 9 additions & 22 deletions apps/api/src/config/config.service.ts
@@ -1,28 +1,20 @@
import { parse, config } from 'dotenv';
import * as fs from 'fs';
import { Injectable } from '@nestjs/common';
import { environment } from '@env-api/environment';

// tslint:disable-next-line
const packageJson = require('../../../../package.json');

@Injectable()
export class ConfigService {
private readonly envConfig: { [prop: string]: string };

constructor(filePath: string) {
this.envConfig = parse(fs.readFileSync(filePath));
config({ path: filePath });
}
private readonly config;

get(key: string, defaultVal?: any): string {
return process.env[key] || this.envConfig[key] || defaultVal;
constructor() {
this.config = environment;
console.log('is prod? ', environment.production);
}

has(key: string): boolean {
return this.get(key) !== undefined;
}

public getNumber(key: string): number {
return parseInt(this.get(key), 10);
get(key: string): any {
return this.config.get(key);
}

public getVersion(): string {
Expand All @@ -37,11 +29,6 @@ export class ConfigService {
}

public getAllowWhitelist(): string[] {
const allowWhitelist = this.get('ALLOW_WHITE_LIST');
if (allowWhitelist) {
return allowWhitelist.split(',');
} else {
return [];
}
return this.config.ALLOW_WHITE_LIST ? this.config.ALLOW_WHITE_LIST : [];
}
}
37 changes: 14 additions & 23 deletions apps/api/src/core/core.module.ts
Expand Up @@ -5,32 +5,23 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor, TransformInterceptor } from './interceptors';
import { RequestContextMiddleware } from './context';
import { ConfigService } from '../config';
import { ConnectionOptions } from 'typeorm';
import { Notification } from '../notifications/notification.entity';
import { User } from '../auth/user.entity';
import { environment as env } from '@env-api/environment';

@Module({
imports: [
ConfigModule.forRoot(),
EmailModule.forRoot({
transport: {
host: process.env.EMAIL_HOST,
port: process.env.EMAIL_PORT ? Number(process.env.EMAIL_PORT) : 25,
secure: process.env.EMAIL_SECURE ? JSON.parse(process.env.EMAIL_SECURE) : false,
},
defaults: {
from: process.env.EMAIL_FROM,
},
templateDir: process.env.EMAIL_TEMPLATE_DIR,
}),
TypeOrmModule.forRoot({
type: 'postgres',
host: process.env.TYPEORM_HOST,
port: Number(process.env.TYPEORM_PORT),
database: process.env.TYPEORM_DATABASE,
username: process.env.TYPEORM_USERNAME,
password: process.env.TYPEORM_PASSWORD,
entities: [process.env.TYPEORM_ENTITIES],
keepConnectionAlive: true,
logging: process.env.TYPEORM_LOGGING ? JSON.parse(process.env.TYPEORM_LOGGING) : false,
synchronize: process.env.TYPEORM_SYNCHRONIZE ? JSON.parse(process.env.TYPEORM_SYNCHRONIZE) : false,
ConfigModule,
EmailModule.forRoot(env.email),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (config: ConfigService) => ({
...env.database,
entities: [Notification, User],
} as ConnectionOptions),
inject: [ConfigService],
}),
],
controllers: [],
Expand Down
1 change: 0 additions & 1 deletion apps/api/src/core/index.ts
@@ -1,6 +1,5 @@
export * from './core.module';
export * from './services/base-remote.service';
export * from './entities/base.entity';
export * from './entities/audit-base.entity';
export * from './crud/crud.service';
export * from './crud/crud.controller';
63 changes: 43 additions & 20 deletions apps/api/src/environments/environment.prod.ts
Expand Up @@ -2,29 +2,52 @@ export const environment = {
production: true,

NODE_ENV: 'production',
DOMAIN_URL: 'http://localhost:3000',
PORT: 3000,
GLOBAL_PREFIX: '/api',
NODE_TLS_REJECT_UNAUTHORIZED: 0,

TYPEORM_CONNECTION: 'postgres',
TYPEORM_HOST: 'postgres',
TYPEORM_PORT: 5432,
TYPEORM_DATABASE: 'cockpit',
TYPEORM_USERNAME: 'cockpit',
TYPEORM_PASSWORD: 'cockpit123',
server: {
host: 'localhost',
domainUrl: 'http://localhost:3000',
port: 3000,
globalPrefix: '/api',
},

TYPEORM_SYNCHRONIZE: false,
TYPEORM_LOGGING: false,
TYPEORM_ENTITIES: './dist/**/**.entity.js',
database: {
type: 'postgres',
host: process.env.TYPEORM_HOST || 'postgres',
port: process.env.TYPEORM_PORT ? Number(process.env.TYPEORM_PORT) : 5432,
database: process.env.TYPEORM_DATABASE || 'cockpit',
username: process.env.TYPEORM_USERNAME || 'cockpit',
password: process.env.TYPEORM_PASSWORD || 'cockpit123',
keepConnectionAlive: true,
logging: process.env.TYPEORM_LOGGING ? JSON.parse(process.env.TYPEORM_LOGGING) : false,
synchronize: false,
},

// OIDC_ISSUER_URL: 'https://myroute-is360.a3c1.starter-us-west-1.openshiftapps.com/auth/realms/kubernetes',
// OIDC_CLIENT: 'cockpit',
OIDC_ISSUER_URL: 'https://myroute-is360.a3c1.starter-us-west-1.openshiftapps.com/auth/realms/is360',
OIDC_CLIENT: 'is360ui',
oidc: {
// issuerUrl: 'https://myroute-is360.a3c1.starter-us-west-1.openshiftapps.com/auth/realms/kubernetes',
// client: 'cockpit',
issuerUrl: process.env.OIDC_ISSUER_URL || 'https://myroute-is360.a3c1.starter-us-west-1.openshiftapps.com/auth/realms/is360',
client: process.env.OIDC_CLIENT || 'is360ui',
},

EMAIL_HOST: 'mail.google.com',
EMAIL_PORT: 25,
EMAIL_FROM: '"sumo demo" <sumo@demo.com>',
EMAIL_TEMPLATE_DIR: 'apps/api/email-templates',
email: {
transport: {
host: process.env.EMAIL_HOST || 'mail.google.com',
port: process.env.EMAIL_PORT ? Number(process.env.EMAIL_PORT) : 25,
secure: process.env.EMAIL_SECURE ? JSON.parse(process.env.EMAIL_SECURE) : false,
auth: {
user: process.env.EMAIL_AUTH_USER || 'auth_user',
pass: process.env.EMAIL_AUTH_PASS || 'auth_pass',
},
},
defaults: {
from: process.env.EMAIL_FROM ? process.env.EMAIL_FROM : '"sumo demo" <sumo@demo.com>',
},
templateDir: process.env.EMAIL_TEMPLATE_DIR || 'apps/api/email-templates',
},

webPush: {
publicVapidKey: 'BAJq-yHlSNjUqKW9iMY0hG96X9WdVwetUFDa5rQIGRPqOHKAL_fkKUe_gUTAKnn9IPAltqmlNO2OkJrjdQ_MXNg',
privateVapidKey: 'cwh2CYK5h_B_Gobnv8Ym9x61B3qFE2nTeb9BeiZbtMI',
},
};
62 changes: 40 additions & 22 deletions apps/api/src/environments/environment.ts
Expand Up @@ -4,33 +4,51 @@

export const environment = {
production: false,

NODE_ENV: 'development',
DOMAIN_URL: 'http://localhost:3000',
PORT: 3000,
GLOBAL_PREFIX: '/api',
NODE_TLS_REJECT_UNAUTHORIZED: 0,
ALLOW_WHITE_LIST: '::ffff:127.0.0.1,::1',

ALLOW_WHITE_LIST: ['::ffff:127.0.0.1', '::1'],
LOG_LEVEL: 'debug',

TYPEORM_CONNECTION: 'postgres',
TYPEORM_HOST: 'localhost',
TYPEORM_PORT: 5432,
TYPEORM_DATABASE: 'cockpit',
TYPEORM_USERNAME: 'cockpit',
TYPEORM_PASSWORD: 'cockpit123',
server: {
host: 'localhost',
domainUrl: 'http://localhost:3000',
port: 3000,
globalPrefix: '/api',
},

database: {
type: 'postgres',
host: 'localhost',
port: 5432,
database: 'cockpit',
username: 'cockpit',
password: 'cockpit123',
keepConnectionAlive: true,
logging: true,
synchronize: true,
},

TYPEORM_SYNCHRONIZE: true,
TYPEORM_LOGGING: true,
TYPEORM_ENTITIES: './**/**.entity{.ts,.js}',
oidc: {
// issuerUrl: 'https://myroute-is360.a3c1.starter-us-west-1.openshiftapps.com/auth/realms/kubernetes',
// client: 'cockpit',
issuerUrl: process.env.OIDC_ISSUER_URL || 'https://myroute-is360.a3c1.starter-us-west-1.openshiftapps.com/auth/realms/is360',
client: process.env.OIDC_CLIENT || 'is360ui',
},

// OIDC_ISSUER_URL: 'https://myroute-is360.a3c1.starter-us-west-1.openshiftapps.com/auth/realms/kubernetes',
// OIDC_CLIENT: 'cockpit',
OIDC_ISSUER_URL: 'https://myroute-is360.a3c1.starter-us-west-1.openshiftapps.com/auth/realms/is360',
OIDC_CLIENT: 'is360ui',
email: {
transport: {
host: 'mail.google.com',
port: 25,
},
defaults: {
from: '"sumo demo" <sumo@demo.com>',
},
templateDir: 'apps/api/email-templates',
},

EMAIL_HOST: 'mail.google.com',
EMAIL_PORT: 25,
EMAIL_FROM: '"sumo demo" <sumo@demo.com>',
EMAIL_TEMPLATE_DIR: 'apps/api/email-templates',
webPush: {
publicVapidKey: 'BAJq-yHlSNjUqKW9iMY0hG96X9WdVwetUFDa5rQIGRPqOHKAL_fkKUe_gUTAKnn9IPAltqmlNO2OkJrjdQ_MXNg',
privateVapidKey: 'cwh2CYK5h_B_Gobnv8Ym9x61B3qFE2nTeb9BeiZbtMI',
},
};
15 changes: 8 additions & 7 deletions apps/api/src/main.hmr.ts
Expand Up @@ -4,6 +4,7 @@ import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { ConfigService } from './config';
import * as helmet from 'helmet';
import { environment as env } from '@env-api/environment';

declare const module: any;

Expand All @@ -17,37 +18,37 @@ async function bootstrap() {
transform: true,
whitelist: true,
forbidNonWhitelisted: true,
skipMissingProperties: true,
skipMissingProperties: false,
forbidUnknownValues: true,
}),
);

const options = new DocumentBuilder()
.setTitle('Sumo API Docs')
.setDescription('Sumo API for Multi-tenant kubernetes')
.setDescription('Sumo API for Ngx Starter Kit')
.setExternalDoc('Github Repo', 'https://github.com/xmlking/ngx-starter-kit/tree/master/apps/api')
.setVersion(config.getVersion())
.addTag('Sumo')
.addTag('External')
.setSchemes(config.isProd() ? 'https' : 'http')
.addOAuth2(
'implicit',
`${config.get('OIDC_ISSUER_URL')}/protocol/openid-connect/auth`,
`${config.get('OIDC_ISSUER_URL')}/protocol/openid-connect/token`,
`${env.oidc.issuerUrl}/protocol/openid-connect/auth`,
`${env.oidc.issuerUrl}/protocol/openid-connect/token`,
)
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('docs', app, document, {
swaggerOptions: {
oauth2RedirectUrl: `${config.get('DOMAIN_URL')}/docs/oauth2-redirect.html`,
oauth2RedirectUrl: `${env.server.domainUrl})}/docs/oauth2-redirect.html`,
oauth: {
clientId: config.get('OIDC_CLIENT'),
clientId: env.oidc.client,
appName: 'Sumo API',
},
},
});

await app.listen(config.getNumber('PORT') || 3000, '0.0.0.0');
await app.listen(env.server.port || 3000, '0.0.0.0');

if (module.hot) {
module.hot.accept();
Expand Down

0 comments on commit f561428

Please sign in to comment.