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

feat: add yearly option to billing plan DTO and fix validation issue #1355

Closed
wants to merge 4 commits into from
Closed
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
6 changes: 3 additions & 3 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged
npm test
36 changes: 36 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
services:
postgres:
container_name: postgres-boiler
image: postgres:latest
ports:
- '5432:5432'
environment:
- POSTGRES_USER=${DB_USERNAME}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=${DB_DATABASE}
volumes:
- ./data/db:/var/lib/postgresql/data
restart: always

adminer:
image: adminer
container_name: adminer-boiler
ports:
- '8080:8080'
restart: always
depends_on:
- postgres

redis:
image: redis:latest
container_name: redis-boiler
ports:
- '6379:6379'
command: ['redis-server', '--appendonly', 'yes']
volumes:
- redis_data:/data
restart: always

volumes:
data:
redis_data:
Empty file added [email protected]
Empty file.
Empty file added npx
Empty file.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"joi": "^17.13.3",
"module-alias": "^2.2.3",
"multer": "^1.4.5-lts.1",
"nest": "^0.1.6",
"nestjs-form-data": "^1.9.93",
"nestjs-pino": "^4.3.1",
"nodemailer": "^6.10.0",
Expand Down Expand Up @@ -105,7 +106,7 @@
"eslint-import-resolver-typescript": "^3.8.3",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-prettier": "^5.2.3",
"husky": "^9.1.7",
"husky": "^8.0.0",
"jest": "^29.7.0",
"lint-staged": "^15.4.3",
"prettier": "^3.5.2",
Expand All @@ -124,7 +125,7 @@
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"testRegex": ".*\\.(spec|e2e-spec)\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
Expand Down
14 changes: 14 additions & 0 deletions pg_hba.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
nections using Unix sockets
local all all md5

# IPv4 local connections
host all all 127.0.0.1/32 md5

# IPv6 local connections
host all all ::1/128 md5

# Allow replication connections from localhost, by a user with the replication privilege
local replication all md5
host replication all 127.0.0.1/32 md5
host replication all ::1/128 md5

6 changes: 3 additions & 3 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import s3Config from '@config/s3.config';
useClass: LanguageGuard,
},
{
provide: 'CONFIG',
provide: 'CONFIG',
useClass: ConfigService,
},
{
Expand All @@ -67,10 +67,10 @@ import s3Config from '@config/s3.config';
forbidNonWhitelisted: true,
}),
},
{
{
provide: 'APP_GUARD',
useClass: AuthGuard,
},
},
],
imports: [
ConfigModule.forRoot({
Expand Down
18 changes: 9 additions & 9 deletions src/database/data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ dotenv.config();
const isDevelopment = process.env.NODE_ENV === 'development';

const dataSource = new DataSource({
type: process.env.DB_TYPE as 'postgres',
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
host: process.env.DB_HOST,
port: +process.env.DB_PORT,
database: process.env.DB_NAME,
entities: [process.env.DB_ENTITIES],
migrations: [process.env.DB_MIGRATIONS],
synchronize: isDevelopment,
type: (process.env.DB_TYPE as 'postgres') || 'postgres', // Default to 'postgres'
username: process.env.DB_USERNAME || 'andre',
password: process.env.DB_PASSWORD || 'Damilare12345',
host: process.env.DB_HOST || 'localhost',
port: Number(process.env.DB_PORT) || 5432,
database: process.env.DB_NAME || 'mydatabase',
entities: [process.env.DB_ENTITIES || 'dist/**/*.entity{.ts,.js}'], // Ensure default value
migrations: [process.env.DB_MIGRATIONS || 'dist/migrations/*{.ts,.js}'],
synchronize: false,
migrationsTableName: 'migrations',
ssl: process.env.DB_SSL === 'true',
});
Expand Down
67 changes: 67 additions & 0 deletions src/dto/billing-plan.dto.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { validate } from 'class-validator';
import { BillingPlanDto } from'../../src/modules/billing-plans/dto/billing-plan.dto';


describe('BillingPlanDto Validation', () => {
it('✅ should pass with valid data', async () => {
const dto = new BillingPlanDto();
dto.name = 'Premium Plan';
dto.description = 'Best plan for yearly subscribers';
dto.frequency = 'yearly';
dto.amount = 1200;
dto.is_active = true;

const errors = await validate(dto);
expect(errors.length).toBe(0);
});

it('❌ should fail if frequency is not "monthly" or "yearly"', async () => {
const dto = new BillingPlanDto();
dto.name = 'Basic Plan';
dto.frequency = 'weekly'; // ❌ Invalid frequency
dto.amount = 100;
dto.is_active = true;

const errors = await validate(dto);
expect(errors.length).toBeGreaterThan(0);
expect(errors[0].constraints).toHaveProperty(
'isIn',
'frequency must be one of the following values: monthly, yearly',
);
});

it('❌ should fail if amount is not a number', async () => {
const dto = new BillingPlanDto();
dto.name = 'Basic Plan';
dto.frequency = 'monthly';
dto.amount = 'not-a-number' as any; // ❌ Invalid amount
dto.is_active = true;

const errors = await validate(dto);
expect(errors.length).toBeGreaterThan(0);
expect(errors[0].constraints).toHaveProperty('isNumber');
});

it('✅ should allow optional description', async () => {
const dto = new BillingPlanDto();
dto.name = 'Basic Plan';
dto.frequency = 'monthly';
dto.amount = 100;
dto.is_active = true; // No description provided

const errors = await validate(dto);
expect(errors.length).toBe(0);
});

it('❌ should fail if is_active is not a boolean', async () => {
const dto = new BillingPlanDto();
dto.name = 'Basic Plan';
dto.frequency = 'monthly';
dto.amount = 100;
dto.is_active = 'yes' as any; // ❌ Invalid boolean

const errors = await validate(dto);
expect(errors.length).toBeGreaterThan(0);
expect(errors[0].constraints).toHaveProperty('isBoolean');
});
});
Loading
Loading