Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure ims nest starter template for scalability #3

Merged
merged 3 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ JWT_EXPIRATION=3600 # 1 hour in seconds
XSECURITY_ENABLED=false
XSECURITY_SECRET=your-XSecurity-secret

#throttle config
THROTTLE_TTL=10
THROTTLE_LIMIT=10


# Database Config
DB_HOST=localhost
DB_PORT=5432
Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
"username": "postgres",
"password": ""
}
]
],
"typescript.tsdk": "node_modules\\typescript\\lib"
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ nest generate --help

You can create custom CLI commands tailored to your specific needs using the [nestjs-command](https://www.npmjs.com/package/nestjs-command) package.
This project already includes integration with [nestjs-command](https://www.npmjs.com/package/nestjs-command) package.
For reference, check out the `xsecurity` command implemented in [src/commands/xsecurity.command.ts](https://github.com/Innovix-Matrix-System/ims-nest-api-starter/blob/master/src/commands/xsecurity.command.ts).
For reference, check out the `xsecurity` command implemented in [src/commands/xsecurity.command.ts](https://github.com/Innovix-Matrix-Systems/ims-nest-api-starter/blob/main/src/commands/xsecurity.command.ts).

## Authors

Expand Down
35 changes: 11 additions & 24 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/terminus": "^10.2.3",
"@nestjs/throttler": "^6.2.1",
"bcrypt": "^5.1.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
Expand All @@ -54,7 +55,6 @@
"nestjs-command": "^3.1.4",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"passport-local": "^1.0.0",
"pg": "^8.13.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
Expand All @@ -69,7 +69,6 @@
"@types/jest": "^29.5.2",
"@types/node": "^20.3.1",
"@types/passport-jwt": "^4.0.1",
"@types/passport-local": "^1.0.38",
"@types/supertest": "^6.0.0",
"@types/yargs": "^17.0.33",
"@typescript-eslint/eslint-plugin": "^8.0.0",
Expand Down
33 changes: 25 additions & 8 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { APP_GUARD } from '@nestjs/core';
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { CommandModule } from 'nestjs-command';
import { AppController } from './app.controller';
import { AuthModule } from './auth/auth.module';
import { XSecureInstallCommand } from './commands/xsecurity.command';
import mikroOrmConfig from './config/mikro-orm.config';
import { HealthModule } from './health/health.module';
import { XSecurityMiddleware } from './middlewares/xsecurity.middleware';
import { MiscModule } from './misc/misc.module';
import { PermissionModule } from './permission/permission.module';
import { RoleModule } from './role/role.module';
import { UserModule } from './user/user.module';
import { AuthModule } from './modules/auth/auth.module';
import { HealthModule } from './modules/health/health.module';
import { MiscModule } from './modules/misc/misc.module';
import { PermissionModule } from './modules/permission/permission.module';
import { RoleModule } from './modules/role/role.module';
import { UserModule } from './modules/user/user.module';

@Module({
imports: [
Expand All @@ -22,9 +24,19 @@ import { UserModule } from './user/user.module';
}),
MikroOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) =>
mikroOrmConfig(configService),
}),
ThrottlerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => [
{
ttl: configService.get<number>('THROTTLE_TTL'),
limit: configService.get<number>('THROTTLE_LIMIT'),
},
],
}),
CommandModule,
HealthModule,
Expand All @@ -35,9 +47,14 @@ import { UserModule } from './user/user.module';
AuthModule,
],
controllers: [AppController],
providers: [XSecureInstallCommand],
providers: [
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
XSecureInstallCommand,
],
})
// export class AppModule {}
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(XSecurityMiddleware).forRoutes('*');
Expand Down
32 changes: 0 additions & 32 deletions src/auth/strategies/local.strategy.ts

This file was deleted.

8 changes: 4 additions & 4 deletions src/common/controllers/base.controller.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Res } from '@nestjs/common';
import { HttpStatus, Res } from '@nestjs/common';
import { Response } from 'express';

export class BaseController {
sendPaginatedResponse(
data: any[],
pageData: PaginatedMeta,
message = '',
statusCode = 200,
statusCode = HttpStatus.OK,
res: Response,
) {
const response = {
Expand All @@ -31,7 +31,7 @@ export class BaseController {
sendSuccessResponse(
result: any,
message = '',
statusCode = 200,
statusCode = HttpStatus.OK,
@Res() res: Response,
) {
const response = {
Expand All @@ -47,7 +47,7 @@ export class BaseController {
sendErrorResponse(
error: string,
errorMessages = [],
statusCode = 500,
statusCode = HttpStatus.INTERNAL_SERVER_ERROR,
@Res() res: Response,
) {
if (errorMessages.length === 0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { SetMetadata } from '@nestjs/common';
import { PermissionName } from '../enum/permission.enum';
import { PermissionName } from '../../enums/permission.enum';

export const Permissions = (...permissions: string[]) =>
SetMetadata(PermissionName.PERMISSIONS_KEY, permissions);
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
ValidatorConstraintInterface,
registerDecorator,
} from 'class-validator';
import { UserService } from '../user/user.service';
import { UserService } from '../../modules/user/user.service';

@Injectable()
@ValidatorConstraint({ name: 'isUserEmailUnique', async: true })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ValidatorConstraintInterface,
registerDecorator,
} from 'class-validator';
import { Permission } from '../entities/permission.entity';
import { Permission } from '../../modules/permission/entities/permission.entity';

@Injectable()
@ValidatorConstraint({ name: 'isValidPermissions', async: true })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ValidatorConstraintInterface,
registerDecorator,
} from 'class-validator';
import { Role } from '../entities/role.entity';
import { Role } from '../../modules/role/entities/role.entity';

@Injectable()
@ValidatorConstraint({ name: 'isValidRoles', async: true })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export class ValidationExceptionFilter implements ExceptionFilter {
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const exceptionResponse: any = exception.getResponse();
console.log(exceptionResponse);
if (!Array.isArray(exceptionResponse?.message)) {
response.status(status).json({
statusCode: status,
Expand Down
2 changes: 1 addition & 1 deletion src/common/guards/permission.guard.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { UserService } from '../../user/user.service';
import { UserService } from '../../modules/user/user.service';

@Injectable()
export class PermissionGuard implements CanActivate {
Expand Down
2 changes: 1 addition & 1 deletion src/database/factories/user.factory.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { faker } from '@faker-js/faker';
import { Factory } from '@mikro-orm/seeder';
import * as bcrypt from 'bcrypt';
import { User } from '../../entities/user.entity';
import { User } from '../../modules/user/entities/user.entity';

export class UserFactory extends Factory<User> {
model = User;
Expand Down
2 changes: 1 addition & 1 deletion src/database/seeders/PermissionSeeder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { EntityManager } from '@mikro-orm/core';
import { Seeder } from '@mikro-orm/seeder';
import { Permission } from '../../entities/permission.entity';
import { Permission } from '../../modules/permission/entities/permission.entity';
import { getAllPermissions } from '../../utils/permission.helper';

export class PermissionSeeder extends Seeder {
Expand Down
6 changes: 3 additions & 3 deletions src/database/seeders/RoleSeeder.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { EntityManager, EntityRepository } from '@mikro-orm/core';
import { Seeder } from '@mikro-orm/seeder';
import { Permission } from '../../entities/permission.entity';
import { Role } from '../../entities/role.entity';
import { RoleName } from '../../enum/role.enum';
import { RoleName } from '../../enums/role.enum';
import { Permission } from '../../modules/permission/entities/permission.entity';
import { Role } from '../../modules/role/entities/role.entity';

export class RoleSeeder extends Seeder {
async run(em: EntityManager): Promise<void> {
Expand Down
4 changes: 2 additions & 2 deletions src/database/seeders/UserSeeder.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { EntityManager, EntityRepository } from '@mikro-orm/core';
import { Seeder } from '@mikro-orm/seeder';
import { Role } from '../../entities/role.entity';
import { User } from '../../entities/user.entity';
import * as bcrypt from 'bcrypt';
import { User } from '../../modules/user/entities/user.entity';
import { Role } from '../../modules/role/entities/role.entity';

export class UserSeeder extends Seeder {
async run(em: EntityManager): Promise<void> {
Expand Down
File renamed without changes.
File renamed without changes.
7 changes: 5 additions & 2 deletions src/middlewares/xsecurity.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Injectable,
NestMiddleware,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as crypto from 'crypto';
import { NextFunction, Request, Response } from 'express';

Expand All @@ -16,8 +17,10 @@ export class XSecurityMiddleware implements NestMiddleware {
{ count: number; resetTime: number }
>();

constructor(private configService: ConfigService) {}

use(req: Request, res: Response, next: NextFunction) {
if (process.env.XSECURITY_ENABLED !== 'true') {
if (this.configService.get<string>('XSECURITY_ENABLED') !== 'true') {
return next();
}

Expand Down Expand Up @@ -66,7 +69,7 @@ export class XSecurityMiddleware implements NestMiddleware {
}

private isValidXSecureToken(signedToken: string): boolean {
const sharedSecretKey = process.env.XSECURITY_SECRET;
const sharedSecretKey = this.configService.get<string>('XSECURITY_SECRET');
const parts = signedToken.split('.');
if (parts.length !== 2) return false;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BadRequestException } from '@nestjs/common';
import { BadRequestException, HttpStatus } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { Response } from 'express';
import { AuthController } from './auth.controller';
Expand Down Expand Up @@ -61,11 +61,11 @@ describe('AuthController', () => {
loginDto.email,
loginDto.password,
);
expect(mockResponse.status).toHaveBeenCalledWith(200);
expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.OK);
expect(mockResponse.json).toHaveBeenCalledWith({
data: mockAuthData,
message: 'Logged in successfully',
statusCode: 200,
statusCode: HttpStatus.OK,
success: true,
});
});
Expand Down
Loading
Loading