-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
83f8b47
commit 1ce0d87
Showing
17 changed files
with
641 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { | ||
Body, | ||
Controller, | ||
Delete, | ||
Get, | ||
HttpCode, | ||
HttpStatus, | ||
Param, | ||
Post, | ||
Query, | ||
UseGuards, | ||
UseInterceptors, | ||
} from '@nestjs/common'; | ||
import { | ||
ApiBearerAuth, | ||
ApiOperation, | ||
ApiQuery, | ||
ApiTags, | ||
} from '@nestjs/swagger'; | ||
import { JwtGuard } from '@rahino/auth/guard'; | ||
import { PermissionGuard } from '@rahino/permission-checker/guard'; | ||
import { JsonResponseTransformInterceptor } from '@rahino/response/interceptor'; | ||
import { CheckPermission } from '@rahino/permission-checker/decorator'; | ||
import { GetUser } from '@rahino/auth/decorator'; | ||
import { User } from '@rahino/database/models/core/user.entity'; | ||
import { CourierService } from './courier.service'; | ||
import { CourierDto, GetCourierDto } from './dto'; | ||
|
||
@ApiTags('Admin-Couriers') | ||
@ApiBearerAuth() | ||
@UseGuards(JwtGuard, PermissionGuard) | ||
@UseInterceptors(JsonResponseTransformInterceptor) | ||
@Controller({ | ||
version: ['1'], | ||
path: '/api/ecommerce/admin/couriers', | ||
}) | ||
export class CourierController { | ||
constructor(private readonly service: CourierService) {} | ||
|
||
// public url | ||
@ApiOperation({ description: 'show all couriers' }) | ||
@Get('/') | ||
@ApiQuery({ | ||
name: 'filter', | ||
type: GetCourierDto, | ||
style: 'deepObject', | ||
explode: true, | ||
}) | ||
@CheckPermission({ permissionSymbol: 'ecommerce.admin.couriers.getall' }) | ||
@HttpCode(HttpStatus.OK) | ||
async findAll(@Query() filter: GetCourierDto, @GetUser() user: User) { | ||
return await this.service.findAll(user, filter); | ||
} | ||
|
||
@UseGuards(JwtGuard, PermissionGuard) | ||
@ApiBearerAuth() | ||
@ApiOperation({ description: 'show courier by given id' }) | ||
@CheckPermission({ permissionSymbol: 'ecommerce.admin.couriers.getone' }) | ||
@Get('/:id') | ||
@HttpCode(HttpStatus.OK) | ||
async findById(@Param('id') entityId: number, @GetUser() user: User) { | ||
return await this.service.findById(entityId, user); | ||
} | ||
|
||
@UseGuards(JwtGuard, PermissionGuard) | ||
@ApiBearerAuth() | ||
@ApiOperation({ description: 'create courier by admin' }) | ||
@CheckPermission({ permissionSymbol: 'ecommerce.admin.couriers.create' }) | ||
@Post('/') | ||
@HttpCode(HttpStatus.CREATED) | ||
async create(@GetUser() user: User, @Body() dto: CourierDto) { | ||
return await this.service.create(user, dto); | ||
} | ||
|
||
@UseGuards(JwtGuard, PermissionGuard) | ||
@ApiBearerAuth() | ||
@ApiOperation({ description: 'delete courier by admin' }) | ||
@Delete('/:id') | ||
@CheckPermission({ permissionSymbol: 'ecommerce.admin.couriers.delete' }) | ||
@HttpCode(HttpStatus.OK) | ||
async deleteById(@Param('id') entityId: number) { | ||
return await this.service.deleteById(entityId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { SequelizeModule } from '@nestjs/sequelize'; | ||
import { Permission } from '@rahino/database/models/core/permission.entity'; | ||
import { User } from '@rahino/database/models/core/user.entity'; | ||
import { ECCourier } from '@rahino/database/models/ecommerce-eav/ec-courier.entity'; | ||
import { CourierService } from './courier.service'; | ||
import { CourierProfile } from './mapper'; | ||
import { UserRoleModule } from '@rahino/core/admin/user-role/user-role.module'; | ||
import { Role } from '@rahino/database/models/core/role.entity'; | ||
|
||
@Module({ | ||
imports: [ | ||
SequelizeModule.forFeature([User, Permission, Role, ECCourier]), | ||
UserRoleModule, | ||
], | ||
controllers: [], | ||
providers: [CourierService, CourierProfile], | ||
}) | ||
export class CourierModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
import { | ||
BadRequestException, | ||
Injectable, | ||
NotFoundException, | ||
} from '@nestjs/common'; | ||
import { User } from '@rahino/database/models/core/user.entity'; | ||
import { CourierDto, GetCourierDto } from './dto'; | ||
import { QueryOptionsBuilder } from '@rahino/query-filter/sequelize-query-builder'; | ||
import { Sequelize } from 'sequelize'; | ||
import { Op } from 'sequelize'; | ||
import { InjectModel } from '@nestjs/sequelize'; | ||
import { ECCourier } from '@rahino/database/models/ecommerce-eav/ec-courier.entity'; | ||
import { I18nContext, I18nService } from 'nestjs-i18n'; | ||
import { I18nTranslations } from 'apps/main/src/generated/i18n.generated'; | ||
import { InjectMapper } from 'automapper-nestjs'; | ||
import { Mapper } from 'automapper-core'; | ||
import { UserCourierDto } from './dto/user-courier-dto'; | ||
import _ from 'lodash'; | ||
import { UserRoleService } from '@rahino/core/admin/user-role/user-role.service'; | ||
import { Role } from '@rahino/database/models/core/role.entity'; | ||
|
||
@Injectable() | ||
export class CourierService { | ||
private readonly courierRoleStaticId = 3; | ||
constructor( | ||
@InjectModel(ECCourier) | ||
private readonly repository: typeof ECCourier, | ||
@InjectModel(User) | ||
private readonly userRepository: typeof User, | ||
@InjectModel(Role) | ||
private readonly roleRepository: typeof Role, | ||
private readonly i18n: I18nService<I18nTranslations>, | ||
private readonly userRoleService: UserRoleService, | ||
@InjectMapper() | ||
private readonly mapper: Mapper, | ||
) {} | ||
|
||
async findAll(user: User, filter: GetCourierDto) { | ||
let queryBuilder = new QueryOptionsBuilder().filter( | ||
Sequelize.where( | ||
Sequelize.fn('isnull', Sequelize.col('ECCourier.isDeleted'), 0), | ||
{ | ||
[Op.eq]: 0, | ||
}, | ||
), | ||
); | ||
const count = await this.repository.count(queryBuilder.build()); | ||
queryBuilder = queryBuilder | ||
.attributes(['id', 'userId', 'createdAt', 'updatedAt']) | ||
.include([ | ||
{ | ||
model: User, | ||
as: 'user', | ||
attributes: [ | ||
'id', | ||
'firstname', | ||
'lastname', | ||
'username', | ||
'phoneNumber', | ||
], | ||
}, | ||
]) | ||
.offset(filter.offset, filter.ignorePaging) | ||
.limit(filter.limit, filter.ignorePaging) | ||
.order({ orderBy: filter.orderBy, sortOrder: filter.sortOrder }); | ||
return { | ||
result: await this.repository.findAll(queryBuilder.build()), | ||
total: count, | ||
}; | ||
} | ||
|
||
async findById(entityId: number, user: User) { | ||
let queryBuilder = new QueryOptionsBuilder() | ||
.attributes(['id', 'userId', 'createdAt', 'updatedAt']) | ||
.include([ | ||
{ | ||
model: User, | ||
as: 'user', | ||
attributes: [ | ||
'id', | ||
'firstname', | ||
'lastname', | ||
'username', | ||
'phoneNumber', | ||
], | ||
}, | ||
]) | ||
.filter( | ||
Sequelize.where( | ||
Sequelize.fn('isnull', Sequelize.col('ECCourier.isDeleted'), 0), | ||
{ | ||
[Op.eq]: 0, | ||
}, | ||
), | ||
) | ||
.filter({ id: entityId }); | ||
const item = await this.repository.findOne(queryBuilder.build()); | ||
if (!item) { | ||
throw new NotFoundException( | ||
this.i18n.t('core.not_found_id', { | ||
lang: I18nContext.current().lang, | ||
}), | ||
); | ||
} | ||
return { | ||
result: item, | ||
}; | ||
} | ||
|
||
async create(user: User, dto: CourierDto) { | ||
let findUser = await this.userRepository.findOne( | ||
new QueryOptionsBuilder() | ||
.filter({ phoneNumber: dto.phoneNumber }) | ||
.build(), | ||
); | ||
if (findUser) { | ||
const queryBuilder = new QueryOptionsBuilder() | ||
.filter( | ||
Sequelize.where( | ||
Sequelize.fn('isnull', Sequelize.col('ECCourier.isDeleted'), 0), | ||
{ | ||
[Op.eq]: 0, | ||
}, | ||
), | ||
) | ||
.filter({ userId: findUser.id }); | ||
const item = await this.repository.findOne(queryBuilder.build()); | ||
if (item) { | ||
throw new BadRequestException( | ||
this.i18n.t('ecommerce.user_exists_before', { | ||
lang: I18nContext.current().lang, | ||
}), | ||
); | ||
} | ||
} else { | ||
const mappedItem = this.mapper.map(dto, UserCourierDto, User); | ||
const insertedItem = _.omit(mappedItem.toJSON(), ['id']); | ||
insertedItem.username = dto.phoneNumber; | ||
findUser = await this.userRepository.create(insertedItem); | ||
} | ||
const role = await this.roleRepository.findOne( | ||
new QueryOptionsBuilder() | ||
.filter({ static_id: this.courierRoleStaticId }) | ||
.build(), | ||
); | ||
if (!role) { | ||
throw new BadRequestException( | ||
this.i18n.t('core.not_found_role', { | ||
lang: I18nContext.current().lang, | ||
}), | ||
); | ||
} | ||
await this.userRoleService.insertRoleToUser(role, findUser); | ||
const item = await this.repository.create({ userId: findUser.id }); | ||
|
||
return { | ||
result: item, | ||
}; | ||
} | ||
|
||
async deleteById(entityId: number) { | ||
let queryBuilder = new QueryOptionsBuilder() | ||
.attributes(['id', 'userId', 'createdAt', 'updatedAt']) | ||
.include([{ model: User, as: 'user' }]) | ||
.filter( | ||
Sequelize.where( | ||
Sequelize.fn('isnull', Sequelize.col('ECCourier.isDeleted'), 0), | ||
{ | ||
[Op.eq]: 0, | ||
}, | ||
), | ||
) | ||
.filter({ id: entityId }); | ||
let item = await this.repository.findOne(queryBuilder.build()); | ||
if (!item) { | ||
throw new NotFoundException( | ||
this.i18n.t('core.not_found_id', { | ||
lang: I18nContext.current().lang, | ||
}), | ||
); | ||
} | ||
|
||
const user = await this.userRepository.findOne( | ||
new QueryOptionsBuilder().filter({ id: item.userId }).build(), | ||
); | ||
|
||
const role = await this.roleRepository.findOne( | ||
new QueryOptionsBuilder() | ||
.filter({ static_id: this.courierRoleStaticId }) | ||
.build(), | ||
); | ||
if (!role) { | ||
throw new BadRequestException( | ||
this.i18n.t('core.not_found_role', { | ||
lang: I18nContext.current().lang, | ||
}), | ||
); | ||
} | ||
await this.userRoleService.removeRoleFromUser(role, user); | ||
|
||
item = await item.save(); | ||
|
||
return { | ||
result: item, | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { IntersectionType } from '@nestjs/swagger'; | ||
import { UserCourierDto } from './user-courier-dto'; | ||
|
||
export class CourierDto extends IntersectionType(UserCourierDto) {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { IntersectionType } from '@nestjs/swagger'; | ||
import { IgnorePagingFilter, ListFilter } from '@rahino/query-filter'; | ||
|
||
export class GetCourierDto extends IntersectionType( | ||
ListFilter, | ||
IgnorePagingFilter, | ||
) {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './courier.dto'; | ||
export * from './get-courier.dto'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { ApiProperty } from '@nestjs/swagger'; | ||
import { I18nTranslations } from 'apps/main/src/generated/i18n.generated'; | ||
import { AutoMap } from 'automapper-classes'; | ||
import { | ||
IsNotEmpty, | ||
IsString, | ||
Matches, | ||
MaxLength, | ||
MinLength, | ||
} from 'class-validator'; | ||
import { i18nValidationMessage } from 'nestjs-i18n'; | ||
|
||
export class UserCourierDto { | ||
@MinLength(3, { | ||
message: i18nValidationMessage<I18nTranslations>('validation.MIN'), | ||
}) | ||
@MaxLength(256, { | ||
message: i18nValidationMessage<I18nTranslations>('validation.MAX'), | ||
}) | ||
@IsNotEmpty({ | ||
message: i18nValidationMessage<I18nTranslations>('validation.NOT_EMPTY'), | ||
}) | ||
@AutoMap() | ||
firstname: string; | ||
|
||
@MinLength(3, { | ||
message: i18nValidationMessage<I18nTranslations>('validation.MIN'), | ||
}) | ||
@MaxLength(256, { | ||
message: i18nValidationMessage<I18nTranslations>('validation.MAX'), | ||
}) | ||
@IsNotEmpty({ | ||
message: i18nValidationMessage<I18nTranslations>('validation.NOT_EMPTY'), | ||
}) | ||
@AutoMap() | ||
lastname: string; | ||
|
||
@MinLength(3, { | ||
message: i18nValidationMessage<I18nTranslations>('validation.MIN'), | ||
}) | ||
@MaxLength(256, { | ||
message: i18nValidationMessage<I18nTranslations>('validation.MAX'), | ||
}) | ||
@IsNotEmpty({ | ||
message: i18nValidationMessage<I18nTranslations>('validation.NOT_EMPTY'), | ||
}) | ||
@AutoMap() | ||
@Matches(new RegExp('^([0-9]){4}([0-9]){7,8}$')) | ||
@ApiProperty({ | ||
required: true, | ||
type: IsString, | ||
default: 'string', | ||
description: 'phoneNumber', | ||
}) | ||
phoneNumber: string; | ||
} |
Oops, something went wrong.