Skip to content

Commit

Permalink
Merge pull request #518 from andrechristikan/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
andrechristikan authored Jun 18, 2024
2 parents d727a86 + 6f44811 commit bd453e6
Show file tree
Hide file tree
Showing 58 changed files with 920 additions and 389 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ack-nestjs-boilerplate",
"version": "6.1.0",
"version": "6.1.1",
"description": "Ack NestJs Boilerplate",
"repository": {
"type": "git",
Expand Down
13 changes: 13 additions & 0 deletions src/app/filters/app.http.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { ResponseMetadataDto } from 'src/common/response/dtos/response.dto';
@Catch(HttpException)
export class AppHttpFilter implements ExceptionFilter {
private readonly debug: boolean;
private readonly globalPrefix: string;
private readonly docPrefix: string;
private readonly logger = new Logger(AppHttpFilter.name);

constructor(
Expand All @@ -30,6 +32,8 @@ export class AppHttpFilter implements ExceptionFilter {
private readonly helperDateService: HelperDateService
) {
this.debug = this.configService.get<boolean>('app.debug');
this.globalPrefix = this.configService.get<string>('app.globalPrefix');
this.docPrefix = this.configService.get<string>('doc.prefix');
}

async catch(exception: HttpException, host: ArgumentsHost): Promise<void> {
Expand All @@ -41,6 +45,15 @@ export class AppHttpFilter implements ExceptionFilter {
this.logger.error(exception);
}

if (
!request.path.startsWith(this.globalPrefix) &&
!request.path.startsWith(this.docPrefix)
) {
response.redirect(HttpStatus.PERMANENT_REDIRECT, this.docPrefix);

return;
}

// set default
let statusHttp: HttpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
let messagePath = `http.${statusHttp}`;
Expand Down
21 changes: 21 additions & 0 deletions src/common/database/decorators/database.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ export function DatabaseQueryIn<T = string>(
},
};
}
export function DatabaseQueryNin<T = string>(
field: string,
values: T[]
): Record<string, any> {
return {
[field]: {
$nin: values,
},
};
}

export function DatabaseQueryEqual<T = string>(
field: string,
Expand All @@ -72,6 +82,17 @@ export function DatabaseQueryEqual<T = string>(
};
}

export function DatabaseQueryNotEqual<T = string>(
field: string,
value: T
): Record<string, any> {
return {
[field]: {
$ne: value,
},
};
}

export function DatabaseQueryContain(
field: string,
value: string,
Expand Down
1 change: 1 addition & 0 deletions src/common/database/interfaces/database.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface IDatabaseJoin {
model: any;
condition?: Record<string, any>;
justOne?: boolean;
join?: this | this[];
}

export type IDatabaseDocument<T> = T & Document;
Expand Down
31 changes: 31 additions & 0 deletions src/common/pagination/decorators/pagination.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { PaginationFilterDatePipe } from 'src/common/pagination/pipes/pagination
import { PaginationFilterEqualPipe } from 'src/common/pagination/pipes/pagination.filter-equal.pipe';
import { PaginationFilterInBooleanPipe } from 'src/common/pagination/pipes/pagination.filter-in-boolean.pipe';
import { PaginationFilterInEnumPipe } from 'src/common/pagination/pipes/pagination.filter-in-enum.pipe';
import { PaginationFilterNinEnumPipe } from 'src/common/pagination/pipes/pagination.filter-nin-enum.pipe';
import { PaginationFilterNotEqualPipe } from 'src/common/pagination/pipes/pagination.filter-not-equal.pipe';
import { PaginationFilterStringContainPipe } from 'src/common/pagination/pipes/pagination.filter-string-contain.pipe';
import { PaginationOrderPipe } from 'src/common/pagination/pipes/pagination.order.pipe';
import { PaginationPagingPipe } from 'src/common/pagination/pipes/pagination.paging.pipe';
Expand Down Expand Up @@ -54,6 +56,35 @@ export function PaginationQueryFilterInEnum<T>(
);
}

//! Pagination query filter enum will convert into repository
export function PaginationQueryFilterNinEnum<T>(
field: string,
defaultValue: T,
defaultEnum: Record<string, any>,
options?: IPaginationFilterOptions
): ParameterDecorator {
return Query(
options?.queryField ?? field,
PaginationFilterNinEnumPipe<T>(
field,
defaultValue,
defaultEnum,
options
)
);
}

//! Pagination query filter equal will convert into repository
export function PaginationQueryFilterNotEqual(
field: string,
options?: IPaginationFilterEqualOptions
): ParameterDecorator {
return Query(
options?.queryField ?? field,
PaginationFilterNotEqualPipe(field, options)
);
}

//! Pagination query filter equal will convert into repository
export function PaginationQueryFilterEqual(
field: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@ export interface IPaginationService {
): IPaginationOrder;
search(searchValue: string, availableSearch: string[]): Record<string, any>;
filterEqual<T = string>(field: string, filterValue: T): Record<string, T>;
filterNotEqual<T = string>(
field: string,
filterValue: T
): Record<string, T>;
filterContain(field: string, filterValue: string): Record<string, any>;
filterContainFullMatch(
field: string,
filterValue: string
): Record<string, any>;
filterIn<T = string>(field: string, filterValue: T[]): Record<string, any>;
filterNin<T = string>(field: string, filterValue: T[]): Record<string, any>;
filterDate(field: string, filterValue: Date): Record<string, Date>;
}
53 changes: 53 additions & 0 deletions src/common/pagination/pipes/pagination.filter-nin-enum.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Inject, Injectable, mixin, Type } from '@nestjs/common';
import { PipeTransform, Scope } from '@nestjs/common/interfaces';
import { REQUEST } from '@nestjs/core';
import { IPaginationFilterOptions } from 'src/common/pagination/interfaces/pagination.interface';
import { PaginationService } from 'src/common/pagination/services/pagination.service';
import { IRequestApp } from 'src/common/request/interfaces/request.interface';

export function PaginationFilterNinEnumPipe<T>(
field: string,
defaultValue: T,
defaultEnum: Record<string, any>,
options?: IPaginationFilterOptions
): Type<PipeTransform> {
@Injectable({ scope: Scope.REQUEST })
class MixinPaginationFilterInEnumPipe implements PipeTransform {
constructor(
@Inject(REQUEST) protected readonly request: IRequestApp,
private readonly paginationService: PaginationService
) {}

async transform(value: string): Promise<Record<string, any>> {
if (options?.raw) {
this.addToRequestInstance(value);
return {
[field]: value,
};
}

const finalValue: T[] = value
? (value
.split(',')
.map((val: string) => defaultEnum[val])
.filter((val: string) => val) as T[])
: (defaultValue as T[]);

return this.paginationService.filterNin<T>(field, finalValue);
}

addToRequestInstance(value: any): void {
this.request.__pagination = {
...this.request.__pagination,
filters: this.request.__pagination?.filters
? {
...this.request.__pagination?.filters,
[field]: value,
}
: { [field]: value },
};
}
}

return mixin(MixinPaginationFilterInEnumPipe);
}
55 changes: 55 additions & 0 deletions src/common/pagination/pipes/pagination.filter-not-equal.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Inject, Injectable, mixin, Type } from '@nestjs/common';
import { PipeTransform, Scope } from '@nestjs/common/interfaces';
import { REQUEST } from '@nestjs/core';
import { IPaginationFilterEqualOptions } from 'src/common/pagination/interfaces/pagination.interface';
import { PaginationService } from 'src/common/pagination/services/pagination.service';
import { IRequestApp } from 'src/common/request/interfaces/request.interface';

export function PaginationFilterNotEqualPipe(
field: string,
options?: IPaginationFilterEqualOptions
): Type<PipeTransform> {
@Injectable({ scope: Scope.REQUEST })
class MixinPaginationFilterEqualPipe implements PipeTransform {
constructor(
@Inject(REQUEST) protected readonly request: IRequestApp,
private readonly paginationService: PaginationService
) {}

async transform(
value: string
): Promise<Record<string, string | number>> {
if (!value) {
return undefined;
}

if (options?.raw) {
this.addToRequestInstance(value);
return {
[field]: value,
};
}

const finalValue: string | number = options?.isNumber
? Number.parseInt(value)
: value.trim();

this.addToRequestInstance(finalValue);
return this.paginationService.filterEqual(field, finalValue);
}

addToRequestInstance(value: any): void {
this.request.__pagination = {
...this.request.__pagination,
filters: this.request.__pagination?.filters
? {
...this.request.__pagination?.filters,
[field]: value,
}
: { [field]: value },
};
}
}

return mixin(MixinPaginationFilterEqualPipe);
}
16 changes: 16 additions & 0 deletions src/common/pagination/services/pagination.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
DatabaseQueryContain,
DatabaseQueryEqual,
DatabaseQueryIn,
DatabaseQueryNin,
DatabaseQueryNotEqual,
DatabaseQueryOr,
} from 'src/common/database/decorators/database.decorator';
import {
Expand Down Expand Up @@ -90,6 +92,13 @@ export class PaginationService implements IPaginationService {
return DatabaseQueryEqual<T>(field, filterValue);
}

filterNotEqual<T = string>(
field: string,
filterValue: T
): Record<string, T> {
return DatabaseQueryNotEqual<T>(field, filterValue);
}

filterContain(field: string, filterValue: string): Record<string, any> {
return DatabaseQueryContain(field, filterValue);
}
Expand All @@ -105,6 +114,13 @@ export class PaginationService implements IPaginationService {
return DatabaseQueryIn<T>(field, filterValue);
}

filterNin<T = string>(
field: string,
filterValue: T[]
): Record<string, any> {
return DatabaseQueryNin<T>(field, filterValue);
}

filterDate(field: string, filterValue: Date): Record<string, Date> {
return DatabaseQueryEqual<Date>(field, filterValue);
}
Expand Down
5 changes: 3 additions & 2 deletions src/languages/en/user.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"list": "List of users retrieved successfully.",
"listHistory": "User history retrieved successfully.",
"listPassword": "User password history retrieved successfully.",
"stateHistoryList": "User history retrieved successfully.",
"passwordHistoryList": "User password history retrieved successfully.",
"loginHistoryList": "User login history retrieved successfully.",
"get": "User details fetched successfully.",
"create": "New user created successfully.",
"inactive": "User marked as inactive.",
Expand Down
36 changes: 24 additions & 12 deletions src/migration/seeds/migration.user.seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ import { UserDoc } from 'src/modules/user/repository/entities/user.entity';
import { RoleDoc } from 'src/modules/role/repository/entities/role.entity';
import { RoleService } from 'src/modules/role/services/role.service';
import { ENUM_USER_SIGN_UP_FROM } from 'src/modules/user/constants/user.enum.constant';
import { UserPasswordService } from 'src/modules/user/services/user-password.service';
import { UserHistoryService } from 'src/modules/user/services/user-history.service';
import { CountryDoc } from 'src/modules/country/repository/entities/country.entity';
import { CountryService } from 'src/modules/country/services/country.service';
import { ENUM_MESSAGE_LANGUAGE } from 'src/common/message/constants/message.enum.constant';
import { UserPasswordHistoryService } from 'src/modules/user/services/user-password-history.service';
import { UserStateHistoryService } from 'src/modules/user/services/user-state-history.service';

@Injectable()
export class MigrationUserSeed {
constructor(
private readonly authService: AuthService,
private readonly userService: UserService,
private readonly userPasswordService: UserPasswordService,
private readonly userHistoryService: UserHistoryService,
private readonly userPasswordHistoryService: UserPasswordHistoryService,
private readonly userStateHistoryService: UserStateHistoryService,
private readonly roleService: RoleService,
private readonly countryService: CountryService
) {}
Expand Down Expand Up @@ -84,14 +84,26 @@ export class MigrationUserSeed {
ENUM_USER_SIGN_UP_FROM.ADMIN
);

await this.userHistoryService.createCreatedByUser(user1, user1._id);
await this.userHistoryService.createCreatedByUser(user2, user2._id);
await this.userHistoryService.createCreatedByUser(user3, user3._id);
await this.userHistoryService.createCreatedByUser(user4, user4._id);
await this.userPasswordService.createByUser(user1);
await this.userPasswordService.createByUser(user2);
await this.userPasswordService.createByUser(user3);
await this.userPasswordService.createByUser(user4);
await this.userStateHistoryService.createCreated(user1, user1._id);
await this.userStateHistoryService.createCreated(user2, user2._id);
await this.userStateHistoryService.createCreated(user3, user3._id);
await this.userStateHistoryService.createCreated(user4, user4._id);
await this.userPasswordHistoryService.createByAdmin(
user1,
user1._id
);
await this.userPasswordHistoryService.createByAdmin(
user2,
user1._id
);
await this.userPasswordHistoryService.createByAdmin(
user3,
user1._id
);
await this.userPasswordHistoryService.createByAdmin(
user4,
user1._id
);
} catch (err: any) {
throw new Error(err.message);
}
Expand Down
11 changes: 7 additions & 4 deletions src/modules/country/controllers/country.admin.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,18 @@ export class CountryAdminController {
order: _order,
}
);
const mapCountries: CountryListResponseDto[] =
await this.countryService.mapList(countries);
const total: number = await this.countryService.getTotal(find);
const totalPage: number = this.paginationService.totalPage(
total,
_limit
);

const mapped: CountryListResponseDto[] =
await this.countryService.mapList(countries);

return {
_pagination: { total, totalPage },
data: mapCountries,
data: mapped,
};
}

Expand All @@ -117,7 +118,9 @@ export class CountryAdminController {
@Param('country', RequestRequiredPipe, CountryParsePipe)
country: CountryDoc
): Promise<IResponse<CountryGetResponseDto>> {
return { data: country };
const mapped: CountryGetResponseDto =
await this.countryService.mapGet(country);
return { data: mapped };
}

@CountryAdminInactiveDoc()
Expand Down
Loading

0 comments on commit bd453e6

Please sign in to comment.