@valentine-efagene/qshelter-common 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OpenApiHelper.d.ts +9 -0
- package/dist/OpenApiHelper.js +118 -0
- package/dist/OpenApiHelper.js.map +1 -0
- package/dist/decorator/index.d.ts +2 -0
- package/dist/decorator/index.js +19 -0
- package/dist/decorator/index.js.map +1 -0
- package/dist/decorator/permission.decorator.d.ts +2 -0
- package/dist/decorator/permission.decorator.js +6 -0
- package/dist/decorator/permission.decorator.js.map +1 -0
- package/dist/decorator/tenant.decorator.d.ts +2 -0
- package/dist/decorator/tenant.decorator.js +13 -0
- package/dist/decorator/tenant.decorator.js.map +1 -0
- package/dist/entities/common.entity.js +1 -1
- package/dist/entities/common.entity.js.map +1 -1
- package/dist/entities/common.pure.entity.js +3 -2
- package/dist/entities/common.pure.entity.js.map +1 -1
- package/dist/entities/mortgage.entity.js +13 -13
- package/dist/entities/mortgage.entity.js.map +1 -1
- package/dist/entities/property.entity.d.ts +1 -2
- package/dist/entities/property.entity.js +6 -12
- package/dist/entities/property.entity.js.map +1 -1
- package/dist/entities/tenant.entity.d.ts +1 -1
- package/dist/entities/tenant.entity.js +3 -3
- package/dist/entities/tenant.entity.js.map +1 -1
- package/dist/entities/user.entity.d.ts +1 -1
- package/dist/entities/user.entity.js +7 -7
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/entities/wallet.entity.js +9 -9
- package/dist/entities/wallet.entity.js.map +1 -1
- package/dist/guard/index.d.ts +2 -0
- package/dist/guard/index.js +19 -0
- package/dist/guard/index.js.map +1 -0
- package/dist/guard/permission.guard.d.ts +10 -0
- package/dist/guard/permission.guard.js +47 -0
- package/dist/guard/permission.guard.js.map +1 -0
- package/dist/guard/swagger-auth.guard.d.ts +1 -0
- package/dist/guard/swagger-auth.guard.js +9 -0
- package/dist/guard/swagger-auth.guard.js.map +1 -0
- package/dist/helpers/ArrayHelper.d.ts +2 -0
- package/dist/helpers/ArrayHelper.js +6 -0
- package/dist/helpers/ArrayHelper.js.map +1 -0
- package/dist/helpers/ConstantHelper.d.ts +36 -0
- package/{helpers/ConstantHelper.ts → dist/helpers/ConstantHelper.js} +36 -47
- package/dist/helpers/ConstantHelper.js.map +1 -0
- package/dist/helpers/CustomNamingStrategy.d.ts +7 -0
- package/dist/helpers/CustomNamingStrategy.js +22 -0
- package/dist/helpers/CustomNamingStrategy.js.map +1 -0
- package/dist/helpers/DateHelper.d.ts +3 -0
- package/dist/helpers/DateHelper.js +20 -0
- package/dist/helpers/DateHelper.js.map +1 -0
- package/dist/helpers/EmailHelper.d.ts +4 -0
- package/dist/helpers/EmailHelper.js +65 -0
- package/dist/helpers/EmailHelper.js.map +1 -0
- package/dist/helpers/FileSystemHelper.d.ts +15 -0
- package/dist/helpers/FileSystemHelper.js +112 -0
- package/dist/helpers/FileSystemHelper.js.map +1 -0
- package/dist/helpers/index.d.ts +5 -0
- package/dist/helpers/index.js +22 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/middleware/AccessLoggerMiddleware.d.ts +6 -0
- package/dist/middleware/AccessLoggerMiddleware.js +64 -0
- package/dist/middleware/AccessLoggerMiddleware.js.map +1 -0
- package/dist/middleware/AuthenticationMiddleware.d.ts +5 -0
- package/dist/middleware/AuthenticationMiddleware.js +19 -0
- package/dist/middleware/AuthenticationMiddleware.js.map +1 -0
- package/dist/middleware/TenantMiddleware.d.ts +14 -0
- package/dist/middleware/TenantMiddleware.js +49 -0
- package/dist/middleware/TenantMiddleware.js.map +1 -0
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +20 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/common.type.d.ts +15 -0
- package/dist/types/common.type.js +18 -1
- package/dist/types/common.type.js.map +1 -1
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.js +25 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/mortgage-fsm.type.d.ts +180 -0
- package/dist/types/mortgage-fsm.type.js +130 -0
- package/dist/types/mortgage-fsm.type.js.map +1 -0
- package/dist/types/permission.enums.d.ts +42 -0
- package/dist/types/permission.enums.js +47 -0
- package/dist/types/permission.enums.js.map +1 -0
- package/dist/types/permission.type.d.ts +42 -0
- package/dist/types/permission.type.js +47 -0
- package/dist/types/permission.type.js.map +1 -0
- package/{types/policy.types.ts → dist/types/policy.type.d.ts} +0 -3
- package/dist/types/policy.type.js +3 -0
- package/dist/types/policy.type.js.map +1 -0
- package/dist/types/tenant.type.d.ts +13 -0
- package/dist/types/tenant.type.js +19 -0
- package/dist/types/tenant.type.js.map +1 -0
- package/dist/types/user.type.d.ts +10 -0
- package/dist/types/user.type.js +16 -0
- package/dist/types/user.type.js.map +1 -0
- package/package.json +51 -3
- package/OpenApiHelper.ts +0 -121
- package/decorator/permission.decorator.ts +0 -4
- package/decorator/tenant.decorator.ts +0 -16
- package/entities/BaseEntity.ts +0 -34
- package/entities/TenantAwareEntity.ts +0 -34
- package/entities/TenantAwareRepository.ts +0 -100
- package/entities/amenity.entity.ts +0 -10
- package/entities/common.entity.ts +0 -46
- package/entities/common.pure.entity.ts +0 -36
- package/entities/index.ts +0 -27
- package/entities/mortgage-document.entity.ts +0 -37
- package/entities/mortgage-downpayment-installment.entity.ts +0 -40
- package/entities/mortgage-downpayment-payment.entity.ts +0 -61
- package/entities/mortgage-downpayment.entity.ts +0 -43
- package/entities/mortgage-step.entity.ts +0 -33
- package/entities/mortgage-type.entity.ts +0 -31
- package/entities/mortgage.entity.ts +0 -89
- package/entities/password_reset_tokens.entity.ts +0 -25
- package/entities/permission.entity.ts +0 -12
- package/entities/property-document.entity.ts +0 -21
- package/entities/property-media.entity.ts +0 -23
- package/entities/property.entity.ts +0 -147
- package/entities/refresh_token.entity.ts +0 -16
- package/entities/role.entity.ts +0 -20
- package/entities/settings.entity.ts +0 -56
- package/entities/social.entity.ts +0 -27
- package/entities/tenant.entity.ts +0 -65
- package/entities/transaction.entity.ts +0 -56
- package/entities/user.entity.ts +0 -89
- package/entities/user_suspensions.entity.ts +0 -24
- package/entities/wallet.entity.ts +0 -54
- package/guard/permission.guard.ts +0 -42
- package/guard/swagger-auth.guard.ts +0 -9
- package/helpers/ArrayHelper.ts +0 -1
- package/helpers/CustomNamingStrategy.ts +0 -27
- package/helpers/DateHelper.ts +0 -21
- package/helpers/EmailHelper.ts +0 -38
- package/helpers/FileSystemHelper.ts +0 -101
- package/index.ts +0 -9
- package/middleware/AccessLoggerMiddleware.ts +0 -58
- package/middleware/AuthenticationMiddleware.ts +0 -13
- package/middleware/TenantMiddleware.ts +0 -52
- package/pagination/index.ts +0 -2
- package/pagination/pagination.helper.ts +0 -57
- package/pagination/pagination.types.ts +0 -21
- package/standard-response.ts +0 -16
- package/tsconfig.json +0 -33
- package/types/common.type.ts +0 -32
- package/types/mortgage-fsm.types.ts +0 -279
- package/types/property.type.ts +0 -10
- package/types/social.enums.ts +0 -17
- package/types/tenant.enums.ts +0 -14
- package/types/transaction.type.ts +0 -9
- package/types/user.enums.ts +0 -11
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { Column, CreateDateColumn, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
|
|
2
|
-
import { Provider, TransactionType } from '../types/transaction.type';
|
|
3
|
-
import { Wallet } from './wallet.entity';
|
|
4
|
-
import { User } from './user.entity';
|
|
5
|
-
|
|
6
|
-
@Entity({ name: 'prod_transactions' })
|
|
7
|
-
export class Transaction {
|
|
8
|
-
@PrimaryGeneratedColumn()
|
|
9
|
-
id: number;
|
|
10
|
-
|
|
11
|
-
@Column({
|
|
12
|
-
type: 'enum',
|
|
13
|
-
enum: TransactionType
|
|
14
|
-
})
|
|
15
|
-
type: TransactionType
|
|
16
|
-
|
|
17
|
-
@ManyToOne(() => Wallet, wallet => wallet.transactions, {
|
|
18
|
-
onDelete: 'CASCADE',
|
|
19
|
-
onUpdate: 'CASCADE',
|
|
20
|
-
})
|
|
21
|
-
@JoinColumn({ name: 'wallet_id' })
|
|
22
|
-
wallet: Wallet;
|
|
23
|
-
|
|
24
|
-
@Column()
|
|
25
|
-
walletId: number
|
|
26
|
-
|
|
27
|
-
@ManyToOne(() => User, (user) => user.transactions)
|
|
28
|
-
@JoinColumn({ name: 'user_id' })
|
|
29
|
-
user: User;
|
|
30
|
-
|
|
31
|
-
@Column()
|
|
32
|
-
userId: number
|
|
33
|
-
|
|
34
|
-
@Column({
|
|
35
|
-
type: 'enum',
|
|
36
|
-
enum: Provider
|
|
37
|
-
})
|
|
38
|
-
provider: Provider
|
|
39
|
-
|
|
40
|
-
@Column()
|
|
41
|
-
ref: string
|
|
42
|
-
|
|
43
|
-
@Column({
|
|
44
|
-
type: 'text'
|
|
45
|
-
})
|
|
46
|
-
metadata: string
|
|
47
|
-
|
|
48
|
-
@Column({ type: 'decimal', precision: 65, scale: 2, nullable: true })
|
|
49
|
-
amount: number;
|
|
50
|
-
|
|
51
|
-
@CreateDateColumn()
|
|
52
|
-
createdAt: Date;
|
|
53
|
-
|
|
54
|
-
@UpdateDateColumn()
|
|
55
|
-
updatedAt: Date;
|
|
56
|
-
}
|
package/entities/user.entity.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { Column, Entity, JoinTable, ManyToMany, OneToMany } from 'typeorm';
|
|
2
|
-
import { TenantAwareBaseEntity } from './BaseEntity';
|
|
3
|
-
import { UserStatus } from '../types/user.enums';
|
|
4
|
-
import { Role } from './role.entity';
|
|
5
|
-
import { RefreshToken } from './refresh_token.entity';
|
|
6
|
-
import { Property } from './property.entity';
|
|
7
|
-
import { Transaction } from './transaction.entity';
|
|
8
|
-
import { Wallet } from './wallet.entity';
|
|
9
|
-
|
|
10
|
-
@Entity({ name: 'users' })
|
|
11
|
-
export class User extends TenantAwareBaseEntity {
|
|
12
|
-
@Column({ nullable: true })
|
|
13
|
-
firstName?: string;
|
|
14
|
-
|
|
15
|
-
@Column({ nullable: true })
|
|
16
|
-
lastName?: string;
|
|
17
|
-
|
|
18
|
-
@Column({ nullable: true })
|
|
19
|
-
phone?: string;
|
|
20
|
-
|
|
21
|
-
@Column({ nullable: true, type: 'text' })
|
|
22
|
-
bio?: string;
|
|
23
|
-
|
|
24
|
-
@Column({ nullable: true })
|
|
25
|
-
address?: string;
|
|
26
|
-
|
|
27
|
-
@Column({ nullable: true })
|
|
28
|
-
email: string;
|
|
29
|
-
|
|
30
|
-
@Column({ nullable: true })
|
|
31
|
-
password: string;
|
|
32
|
-
|
|
33
|
-
@Column({ type: 'text', nullable: true })
|
|
34
|
-
avatar?: string;
|
|
35
|
-
|
|
36
|
-
@Column({ nullable: true })
|
|
37
|
-
gender: string;
|
|
38
|
-
|
|
39
|
-
@ManyToMany(() => Role, (role) => role.users, {
|
|
40
|
-
onDelete: 'CASCADE',
|
|
41
|
-
eager: true
|
|
42
|
-
})
|
|
43
|
-
@JoinTable()
|
|
44
|
-
roles?: Role[]
|
|
45
|
-
|
|
46
|
-
@OneToMany(
|
|
47
|
-
() => RefreshToken,
|
|
48
|
-
(refreshToken) =>
|
|
49
|
-
refreshToken.user,
|
|
50
|
-
{ eager: true },
|
|
51
|
-
)
|
|
52
|
-
refreshTokens: RefreshToken[];
|
|
53
|
-
|
|
54
|
-
@OneToMany(
|
|
55
|
-
() => Wallet,
|
|
56
|
-
(wallet) =>
|
|
57
|
-
wallet.user,
|
|
58
|
-
{ eager: true },
|
|
59
|
-
)
|
|
60
|
-
wallets: Wallet[];
|
|
61
|
-
|
|
62
|
-
@OneToMany(
|
|
63
|
-
() => Transaction,
|
|
64
|
-
(transaction) =>
|
|
65
|
-
transaction.user,
|
|
66
|
-
{ eager: true },
|
|
67
|
-
)
|
|
68
|
-
transactions: Transaction[];
|
|
69
|
-
|
|
70
|
-
@OneToMany(
|
|
71
|
-
() => Property,
|
|
72
|
-
(property) =>
|
|
73
|
-
property.user,
|
|
74
|
-
)
|
|
75
|
-
properties: Property[];
|
|
76
|
-
|
|
77
|
-
@Column({
|
|
78
|
-
type: 'enum',
|
|
79
|
-
enum: UserStatus,
|
|
80
|
-
default: UserStatus.PENDING
|
|
81
|
-
})
|
|
82
|
-
status: UserStatus
|
|
83
|
-
|
|
84
|
-
@Column({ default: false })
|
|
85
|
-
isEmailVerified?: boolean;
|
|
86
|
-
|
|
87
|
-
@Column({ nullable: true })
|
|
88
|
-
emailVerificationToken: string | null
|
|
89
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Column, Entity, JoinColumn, OneToOne } from 'typeorm';
|
|
2
|
-
import { BaseEntity } from './BaseEntity';
|
|
3
|
-
import { User } from './user.entity';
|
|
4
|
-
|
|
5
|
-
@Entity({ name: 'user_suspension' })
|
|
6
|
-
export class UserSuspension extends BaseEntity {
|
|
7
|
-
@OneToOne(() => User, {
|
|
8
|
-
//eager: true,
|
|
9
|
-
onDelete: 'CASCADE',
|
|
10
|
-
onUpdate: 'CASCADE',
|
|
11
|
-
})
|
|
12
|
-
@JoinColumn({ name: 'user_id' })
|
|
13
|
-
user: User;
|
|
14
|
-
|
|
15
|
-
@Column({
|
|
16
|
-
nullable: false
|
|
17
|
-
})
|
|
18
|
-
userId: number
|
|
19
|
-
|
|
20
|
-
@Column({
|
|
21
|
-
nullable: false
|
|
22
|
-
})
|
|
23
|
-
reason: string
|
|
24
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { Column, CreateDateColumn, Entity, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
|
|
2
|
-
import { Transaction } from './transaction.entity';
|
|
3
|
-
import { User } from './user.entity';
|
|
4
|
-
import { Currency } from '../types/social.enums';
|
|
5
|
-
|
|
6
|
-
@Entity({ name: 'wallets' })
|
|
7
|
-
export class Wallet {
|
|
8
|
-
@PrimaryGeneratedColumn()
|
|
9
|
-
id: number;
|
|
10
|
-
|
|
11
|
-
@ManyToOne(() => User, (user) => user.wallets)
|
|
12
|
-
@JoinColumn({ name: 'user_id' })
|
|
13
|
-
user: User;
|
|
14
|
-
|
|
15
|
-
@Column()
|
|
16
|
-
userId: number
|
|
17
|
-
|
|
18
|
-
@Column({
|
|
19
|
-
type: 'enum',
|
|
20
|
-
enum: Currency
|
|
21
|
-
})
|
|
22
|
-
currency: number
|
|
23
|
-
|
|
24
|
-
@Column({
|
|
25
|
-
})
|
|
26
|
-
customerId: string
|
|
27
|
-
|
|
28
|
-
@Column({
|
|
29
|
-
})
|
|
30
|
-
bankName: string
|
|
31
|
-
|
|
32
|
-
@Column({
|
|
33
|
-
})
|
|
34
|
-
accountNumber: string
|
|
35
|
-
|
|
36
|
-
@Column({
|
|
37
|
-
})
|
|
38
|
-
accountName: string
|
|
39
|
-
|
|
40
|
-
@Column({ type: 'decimal', precision: 65, scale: 2, nullable: true })
|
|
41
|
-
balance: number;
|
|
42
|
-
|
|
43
|
-
@Column()
|
|
44
|
-
enabled: boolean
|
|
45
|
-
|
|
46
|
-
@CreateDateColumn()
|
|
47
|
-
createdAt: Date;
|
|
48
|
-
|
|
49
|
-
@UpdateDateColumn()
|
|
50
|
-
updatedAt: Date;
|
|
51
|
-
|
|
52
|
-
@OneToMany(() => Transaction, transaction => transaction.wallet)
|
|
53
|
-
transactions: Transaction[]
|
|
54
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
|
2
|
-
import { Reflector } from '@nestjs/core';
|
|
3
|
-
import { RequirePermission } from '../decorator/permission.decorator';
|
|
4
|
-
import { Observable } from 'rxjs';
|
|
5
|
-
import { User } from '../../user/user.entity';
|
|
6
|
-
|
|
7
|
-
@Injectable()
|
|
8
|
-
export class PermissionGuard implements CanActivate {
|
|
9
|
-
constructor(private reflector: Reflector) { }
|
|
10
|
-
|
|
11
|
-
canActivate(
|
|
12
|
-
context: ExecutionContext,
|
|
13
|
-
): boolean | Promise<boolean> | Observable<boolean> {
|
|
14
|
-
const permission = this.reflector.get(RequirePermission, context.getHandler());
|
|
15
|
-
|
|
16
|
-
if (!permission) {
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const request = context.switchToHttp().getRequest();
|
|
21
|
-
|
|
22
|
-
const user: User = request.user;
|
|
23
|
-
|
|
24
|
-
if (!user) {
|
|
25
|
-
return false
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return this.matchPermission(permission, user);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
matchPermission(permission: string, user: User) {
|
|
32
|
-
const roles = user.roles
|
|
33
|
-
|
|
34
|
-
if (!roles || roles.length < 1) {
|
|
35
|
-
return false
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const permissions = roles.map(role => role.permissions).reduce((acc, curr) => [...acc, ...curr]) ?? []
|
|
39
|
-
const permissionNames = permissions?.map(permission => permission.name)
|
|
40
|
-
return permissionNames.includes(permission)
|
|
41
|
-
}
|
|
42
|
-
}
|
package/helpers/ArrayHelper.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default class ArrayHelper {}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { DefaultNamingStrategy, NamingStrategyInterface } from 'typeorm';
|
|
2
|
-
|
|
3
|
-
export class CustomNamingStrategy
|
|
4
|
-
extends DefaultNamingStrategy
|
|
5
|
-
implements NamingStrategyInterface {
|
|
6
|
-
tableName(className: string, customName: string): string {
|
|
7
|
-
return customName ? customName : this.snakeCase(className);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
columnName(
|
|
11
|
-
propertyName: string,
|
|
12
|
-
customName: string,
|
|
13
|
-
//embeddedPrefixes: string[],
|
|
14
|
-
): string {
|
|
15
|
-
return customName ? customName : this.snakeCase(propertyName);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
relationName(propertyName: string): string {
|
|
19
|
-
return this.snakeCase(propertyName);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
private snakeCase(name: string): string {
|
|
23
|
-
return name
|
|
24
|
-
.replace(/([A-Z])/g, (match) => `_${match.toLowerCase()}`)
|
|
25
|
-
.replace(/^_/, '');
|
|
26
|
-
}
|
|
27
|
-
}
|
package/helpers/DateHelper.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { BadRequestException } from '@nestjs/common';
|
|
2
|
-
|
|
3
|
-
export default class DateHelper {
|
|
4
|
-
public static formatDateToYYYYMMDD(dateString: string) {
|
|
5
|
-
try {
|
|
6
|
-
const date = new Date(dateString);
|
|
7
|
-
|
|
8
|
-
// Ensure the input is a valid Date object
|
|
9
|
-
if (!(date instanceof Date)) {
|
|
10
|
-
throw new BadRequestException('Invalid date');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// Format the date using the formatter
|
|
14
|
-
const formattedDate = date.toISOString().split('T')[0];
|
|
15
|
-
|
|
16
|
-
return formattedDate;
|
|
17
|
-
} catch (error) {
|
|
18
|
-
throw new BadRequestException('Invalid date');
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
package/helpers/EmailHelper.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import * as Handlebars from 'handlebars';
|
|
3
|
-
import { FileSystemHelper } from "./FileSystemHelper";
|
|
4
|
-
|
|
5
|
-
export default class EmailHelper {
|
|
6
|
-
public static async compileStringTemplate(rawTemplate: string, variables: Record<string, any>): Promise<string> {
|
|
7
|
-
try {
|
|
8
|
-
// Compile it with Handlebars
|
|
9
|
-
const compiled = Handlebars.compile(rawTemplate);
|
|
10
|
-
|
|
11
|
-
const html = compiled(variables);
|
|
12
|
-
|
|
13
|
-
return html;
|
|
14
|
-
} catch (error) {
|
|
15
|
-
throw new Error(`Failed to generate HTML: ${error.message}`);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
public static async compileTemplate(templatePath: string, variables: Record<string, any>): Promise<string> {
|
|
20
|
-
try {
|
|
21
|
-
// Load the raw template
|
|
22
|
-
const rawTemplate = FileSystemHelper.loadFile(templatePath);
|
|
23
|
-
|
|
24
|
-
// Compile it with Handlebars
|
|
25
|
-
const compiled = Handlebars.compile(rawTemplate);
|
|
26
|
-
|
|
27
|
-
if (templatePath.includes('layout')) {
|
|
28
|
-
console.log({ compiled, variables })
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const html = compiled(variables);
|
|
32
|
-
|
|
33
|
-
return html;
|
|
34
|
-
} catch (error) {
|
|
35
|
-
throw new Error(`Failed to generate HTML: ${error.message}`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { readFileSync, readdirSync, statSync, promises, constants } from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
|
|
4
|
-
export class FileSystemHelper {
|
|
5
|
-
private static root: string = path.join(__dirname, '../../mail/templates/');
|
|
6
|
-
|
|
7
|
-
public static async getFilePath(fileName: string): Promise<string> {
|
|
8
|
-
const filePath = path.join(this.root, fileName);
|
|
9
|
-
return filePath
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
public static async checkFileExists(fileName: string): Promise<boolean> {
|
|
13
|
-
const filePath = path.join(this.root, fileName);
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
await promises.access(`${filePath}`, constants.F_OK)
|
|
17
|
-
console.log({ filePath, found: true })
|
|
18
|
-
return true
|
|
19
|
-
} catch (error) {
|
|
20
|
-
console.log({ filePath, found: false })
|
|
21
|
-
return false
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
public static loadFileWithFullPath(path: string): string {
|
|
26
|
-
const fileContent = readFileSync(path, 'utf-8');
|
|
27
|
-
return fileContent;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public static loadFile(fileName: string): string {
|
|
31
|
-
const filePath = path.join(this.root, fileName);
|
|
32
|
-
|
|
33
|
-
const fileContent = readFileSync(filePath, 'utf-8');
|
|
34
|
-
return fileContent;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
public static async splitFilePath(filePath: string) {
|
|
38
|
-
// Normalize the file path to handle both Windows and Unix formats
|
|
39
|
-
let normalizedPath = path.normalize(filePath)
|
|
40
|
-
normalizedPath = normalizedPath.replaceAll('\\', '/')
|
|
41
|
-
|
|
42
|
-
// Get the file name (last part of the path)
|
|
43
|
-
const fileName = path.basename(normalizedPath);
|
|
44
|
-
|
|
45
|
-
// Get the directory path
|
|
46
|
-
const directoryPath = path.dirname(normalizedPath);
|
|
47
|
-
const extension = path.extname(fileName)
|
|
48
|
-
|
|
49
|
-
// Split the directory path into an array of folders
|
|
50
|
-
const folderArray = directoryPath.split('/');
|
|
51
|
-
|
|
52
|
-
// Reassemble the folder path as a string (optional, if you need it in this format)
|
|
53
|
-
const folderPath = folderArray.join('/');
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
folderArray,
|
|
57
|
-
folderPath,
|
|
58
|
-
fileName,
|
|
59
|
-
extension
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
public static loadTemplate(fileName: string): string {
|
|
64
|
-
const filePath = path.join(this.root, `${fileName}`);
|
|
65
|
-
|
|
66
|
-
const fileContent = readFileSync(filePath, 'utf-8');
|
|
67
|
-
return fileContent;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Method to list all .html files from the templates directory
|
|
71
|
-
public static listHtmlFilesInTemplates(): string[] {
|
|
72
|
-
const htmlFiles: string[] = [];
|
|
73
|
-
|
|
74
|
-
const getFilesRecursively = (dir: string) => {
|
|
75
|
-
try {
|
|
76
|
-
const files = readdirSync(dir);
|
|
77
|
-
|
|
78
|
-
files.forEach(file => {
|
|
79
|
-
const fullPath = path.join(dir, file);
|
|
80
|
-
const relativePath = path.relative(this.root, fullPath);
|
|
81
|
-
|
|
82
|
-
if (statSync(fullPath).isDirectory()) {
|
|
83
|
-
// If it's a directory, go deeper
|
|
84
|
-
getFilesRecursively(fullPath);
|
|
85
|
-
} else if (file.endsWith('.html')) {
|
|
86
|
-
// If it's an HTML file, add to the list
|
|
87
|
-
htmlFiles.push(relativePath);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
} catch (error) {
|
|
91
|
-
console.log(error)
|
|
92
|
-
throw error
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// Start the recursion from the templates folder
|
|
97
|
-
getFilesRecursively(this.root);
|
|
98
|
-
|
|
99
|
-
return htmlFiles;
|
|
100
|
-
}
|
|
101
|
-
}
|
package/index.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { Injectable, NestMiddleware, Logger } from '@nestjs/common';
|
|
2
|
-
import { Request, Response, NextFunction } from 'express';
|
|
3
|
-
|
|
4
|
-
@Injectable()
|
|
5
|
-
export class AccessLoggerMiddleware implements NestMiddleware {
|
|
6
|
-
private readonly logger = new Logger('HTTP');
|
|
7
|
-
|
|
8
|
-
use = (request: Request, response: Response, next: NextFunction): void => {
|
|
9
|
-
const { ip, method, originalUrl: url } = request;
|
|
10
|
-
const userAgent = request.get('user-agent') || '';
|
|
11
|
-
const startTime = Date.now();
|
|
12
|
-
|
|
13
|
-
// 👇 capture body but don’t log yet
|
|
14
|
-
const originalSend = response.send;
|
|
15
|
-
let responseBody: any;
|
|
16
|
-
|
|
17
|
-
response.send = function (body?: any): Response {
|
|
18
|
-
responseBody = body;
|
|
19
|
-
return originalSend.call(this, body);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
response.on('finish', () => {
|
|
23
|
-
const { statusCode } = response;
|
|
24
|
-
const contentLength = response.get('content-length');
|
|
25
|
-
const responseTime = Date.now() - startTime;
|
|
26
|
-
|
|
27
|
-
const message = {
|
|
28
|
-
method,
|
|
29
|
-
url,
|
|
30
|
-
statusCode,
|
|
31
|
-
contentLength,
|
|
32
|
-
responseTime: `${responseTime}ms`,
|
|
33
|
-
userAgent,
|
|
34
|
-
ip,
|
|
35
|
-
timestamp: new Date().toISOString(),
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
if (statusCode >= 500) {
|
|
39
|
-
this.logger.error(JSON.stringify(message));
|
|
40
|
-
|
|
41
|
-
// 👇 only log the response body here
|
|
42
|
-
try {
|
|
43
|
-
if (typeof responseBody === 'object') {
|
|
44
|
-
console.log('Response body:', JSON.stringify(responseBody, null, 2));
|
|
45
|
-
} else {
|
|
46
|
-
console.log('Response body:', responseBody);
|
|
47
|
-
}
|
|
48
|
-
} catch (err) {
|
|
49
|
-
console.log('Response body (unserializable):', responseBody);
|
|
50
|
-
}
|
|
51
|
-
} else {
|
|
52
|
-
this.logger.log(JSON.stringify(message));
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
next();
|
|
57
|
-
};
|
|
58
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Injectable, NestMiddleware } from '@nestjs/common';
|
|
2
|
-
import { Request, Response, NextFunction } from 'express';
|
|
3
|
-
|
|
4
|
-
@Injectable()
|
|
5
|
-
export default class AuthenticationMiddleware implements NestMiddleware {
|
|
6
|
-
use(req: Request, _res: Response, next: NextFunction) {
|
|
7
|
-
// No-op authentication middleware for now. Consumers should attach
|
|
8
|
-
// a real implementation or use a guard. This prevents build-time errors
|
|
9
|
-
// where the middleware is referenced.
|
|
10
|
-
// It preserves any existing req.user if already set by upstream middleware.
|
|
11
|
-
return next();
|
|
12
|
-
}
|
|
13
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { Injectable, NestMiddleware } from '@nestjs/common';
|
|
2
|
-
import { Request, Response, NextFunction } from 'express';
|
|
3
|
-
|
|
4
|
-
// Extend Express Request to include tenantId
|
|
5
|
-
declare global {
|
|
6
|
-
namespace Express {
|
|
7
|
-
interface Request {
|
|
8
|
-
tenantId?: number;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
@Injectable()
|
|
14
|
-
export class TenantMiddleware implements NestMiddleware {
|
|
15
|
-
async use(req: Request, _res: Response, next: NextFunction) {
|
|
16
|
-
// Prefer explicit header `x-tenant-id`
|
|
17
|
-
const tenantIdHeader = (req.headers['x-tenant-id'] as string) || (req.headers['X-Tenant-Id'] as string);
|
|
18
|
-
if (tenantIdHeader) {
|
|
19
|
-
const id = parseInt(tenantIdHeader, 10);
|
|
20
|
-
if (!isNaN(id)) {
|
|
21
|
-
req.tenantId = id;
|
|
22
|
-
return next();
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Fall back to subdomain extraction (subdomain.domain.tld)
|
|
27
|
-
const host = (req.hostname || req.headers.host || '').toString();
|
|
28
|
-
const subdomain = this.extractSubdomain(host);
|
|
29
|
-
if (subdomain) {
|
|
30
|
-
// If subdomain is numeric, treat as tenantId; otherwise leave undefined
|
|
31
|
-
const id = parseInt(subdomain, 10);
|
|
32
|
-
if (!isNaN(id)) {
|
|
33
|
-
req.tenantId = id;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
next();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private extractSubdomain(host: string): string | null {
|
|
41
|
-
if (!host) return null;
|
|
42
|
-
const hostname = host.split(':')[0];
|
|
43
|
-
const parts = hostname.split('.');
|
|
44
|
-
if (hostname === 'localhost' || /^(\d{1,3}\.){3}\d{1,3}$/.test(hostname)) {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
if (parts.length >= 3) return parts[0];
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export default TenantMiddleware;
|
package/pagination/index.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { PaginatedResponse, PaginationQuery } from './pagination.types';
|
|
2
|
-
|
|
3
|
-
export class PaginationHelper {
|
|
4
|
-
/**
|
|
5
|
-
* Creates a paginated response object
|
|
6
|
-
*/
|
|
7
|
-
static paginate<T>(
|
|
8
|
-
items: T[],
|
|
9
|
-
total: number,
|
|
10
|
-
query: PaginationQuery
|
|
11
|
-
): PaginatedResponse<T> {
|
|
12
|
-
const page = Math.max(1, query.page || 1);
|
|
13
|
-
const limit = this.getLimit(query.limit);
|
|
14
|
-
const totalPages = Math.ceil(total / limit);
|
|
15
|
-
|
|
16
|
-
return {
|
|
17
|
-
data: items,
|
|
18
|
-
meta: {
|
|
19
|
-
total,
|
|
20
|
-
page,
|
|
21
|
-
limit,
|
|
22
|
-
totalPages,
|
|
23
|
-
hasNext: page < totalPages,
|
|
24
|
-
hasPrev: page > 1,
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Calculate the number of records to skip for pagination
|
|
31
|
-
*/
|
|
32
|
-
static getSkip(page?: number, limit?: number): number {
|
|
33
|
-
const actualPage = Math.max(1, page || 1);
|
|
34
|
-
const actualLimit = this.getLimit(limit);
|
|
35
|
-
return (actualPage - 1) * actualLimit;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Get validated limit (min: 1, max: 100, default: 10)
|
|
40
|
-
*/
|
|
41
|
-
static getLimit(limit?: number): number {
|
|
42
|
-
return Math.min(100, Math.max(1, limit || 10));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Parse and validate pagination query parameters
|
|
47
|
-
*/
|
|
48
|
-
static parseQuery(query: any): PaginationQuery {
|
|
49
|
-
return {
|
|
50
|
-
page: query.page ? parseInt(query.page, 10) : 1,
|
|
51
|
-
limit: query.limit ? parseInt(query.limit, 10) : 10,
|
|
52
|
-
sortBy: query.sortBy || 'id',
|
|
53
|
-
sortOrder: query.sortOrder?.toUpperCase() === 'ASC' ? 'ASC' : 'DESC',
|
|
54
|
-
search: query.search || undefined,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export interface PaginationQuery {
|
|
2
|
-
page?: number;
|
|
3
|
-
limit?: number;
|
|
4
|
-
sortBy?: string;
|
|
5
|
-
sortOrder?: 'ASC' | 'DESC';
|
|
6
|
-
search?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface PaginationMeta {
|
|
10
|
-
total: number;
|
|
11
|
-
page: number;
|
|
12
|
-
limit: number;
|
|
13
|
-
totalPages: number;
|
|
14
|
-
hasNext: boolean;
|
|
15
|
-
hasPrev: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface PaginatedResponse<T> {
|
|
19
|
-
data: T[];
|
|
20
|
-
meta: PaginationMeta;
|
|
21
|
-
}
|