diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index b332087..aa02638 100755 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -56,6 +56,9 @@ export const enum AuthMessage { TIMESTAMP_NOT_EMPTY = "زمان نمی‌تواند خالی باشد", ADMIN_CAN_NOT_LOGIN = "ادمین نمی‌تواند وارد شود", NATIONAL_CODE_INVALID = "کد ملی نامعتبر است", + INVALID_REFRESH_TOKEN = "توکن رفرش نامعتبر است", + REFRESH_TOKEN_EXPIRED = "توکن رفرش منقضی شده است", + LOGOUT_SUCCESS = "خروج با موفقیت انجام شد", } export const enum UserMessage { @@ -95,6 +98,8 @@ export const enum UserMessage { FINANCIAL_TYPE_IS_REAL = "نوع کاربر حقیقی می‌باشد", LEGAL_DATA_NOT_FOUND = "اطلاعات حقوقی یافت نشد", REAL_DATA_NOT_FOUND = "اطلاعات حقیقی یافت نشد", + REGISTRATION_NAME_EXIST = "نام ثبت قبلا ثبت شده است", + ADDRESS_NOT_FOUND = "آدرس یافت نشد", } export const enum CommonMessage { diff --git a/src/modules/address/entities/city.entity.ts b/src/modules/address/entities/city.entity.ts index 3b031cf..312819e 100755 --- a/src/modules/address/entities/city.entity.ts +++ b/src/modules/address/entities/city.entity.ts @@ -10,6 +10,6 @@ export class City { @Column({ type: "varchar", length: 255 }) name: string; - @ManyToOne(() => Province, (province) => province.cities, { eager: true, nullable: false }) + @ManyToOne(() => Province, (province) => province.cities, { nullable: false }) province: Province; } diff --git a/src/modules/auth/DTO/refresh-token.dto.ts b/src/modules/auth/DTO/refresh-token.dto.ts new file mode 100644 index 0000000..8fed9d6 --- /dev/null +++ b/src/modules/auth/DTO/refresh-token.dto.ts @@ -0,0 +1,9 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsNotEmpty, IsString } from "class-validator"; + +export class RefreshTokenDto { + @ApiProperty({ description: "Refresh token" }) + @IsString({ message: "Refresh token must be a string" }) + @IsNotEmpty({ message: "Refresh token is required" }) + refreshToken: string; +} diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts index 2061f05..016284e 100755 --- a/src/modules/auth/auth.controller.ts +++ b/src/modules/auth/auth.controller.ts @@ -5,6 +5,7 @@ import { Throttle, ThrottlerGuard } from "@nestjs/throttler"; import { ChangePasswordDto } from "./DTO/change-password.dto"; import { CompleteRegistrationDto } from "./DTO/complete-register.dto"; import { CheckUserExistDto, LoginPasswordDTO } from "./DTO/loginPassword.dto"; +import { RefreshTokenDto } from "./DTO/refresh-token.dto"; import { RequestOtpDto } from "./DTO/request-otp.dto"; import { VerifyOtpDto } from "./DTO/verify-otp.dto"; import { AuthService } from "./providers/auth.service"; @@ -82,6 +83,22 @@ export class AuthController { changePassword(@UserDec("id") userId: string, @Body() changePasswordDto: ChangePasswordDto) { return this.authService.changePassword(userId, changePasswordDto); } + + @AuthGuards() + @ApiOperation({ summary: "refresh the user access token / refresh token" }) + @HttpCode(HttpStatus.OK) + @Post("refresh") + refresh(@Body() refreshTokenDto: RefreshTokenDto) { + return this.authService.refreshToken(refreshTokenDto.refreshToken); + } + + @AuthGuards() + @ApiOperation({ summary: "logout the user" }) + @HttpCode(HttpStatus.OK) + @Post("logout") + logout(@Body() refreshTokenDto: RefreshTokenDto) { + return this.authService.logout(refreshTokenDto.refreshToken); + } //***************************** */ // @Post("forgot-password") diff --git a/src/modules/auth/providers/auth.service.ts b/src/modules/auth/providers/auth.service.ts index c1cd720..32de88f 100755 --- a/src/modules/auth/providers/auth.service.ts +++ b/src/modules/auth/providers/auth.service.ts @@ -5,7 +5,6 @@ import { TokensService } from "./tokens.service"; import { AuthMessage, UserMessage } from "../../../common/enums/message.enum"; import { NotificationsService } from "../../notifications/providers/notifications.service"; import { Role } from "../../users/entities/role.entity"; -import { User } from "../../users/entities/user.entity"; import { UsersService } from "../../users/providers/users.service"; import { OTPService } from "../../utils/providers/otp.service"; import { PasswordService } from "../../utils/providers/password.service"; @@ -69,7 +68,7 @@ export class AuthService { const hashedPassword = await this.passwordService.hashPassword(completeRegistrationDto.password); const user = await this.usersService.createUser(completeRegistrationDto, hashedPassword, queryRunner); - const tokens = this.generateAccessAndRefreshToken(user); + const tokens = await this.tokensService.generateTokens(user); await queryRunner.commitTransaction(); @@ -93,7 +92,7 @@ export class AuthService { if (!user.roles.some((role) => !role.isAdmin)) throw new BadRequestException(AuthMessage.ADMIN_CAN_NOT_LOGIN); - const tokens = this.generateAccessAndRefreshToken(user); + const tokens = await this.tokensService.generateTokens(user); await this.notificationService.createLoginNotification(user.id, { userPhone: user.phone }); @@ -113,7 +112,7 @@ export class AuthService { const isAdmin = this.checkUserIsAdmin(user.roles); if (!isAdmin) throw new BadRequestException(AuthMessage.NOT_ADMIN); - const tokens = this.generateAccessAndRefreshToken(user); + const tokens = await this.tokensService.generateTokens(user); return { message: AuthMessage.PASSWORD_LOGIN_SUCCESS, @@ -174,7 +173,7 @@ export class AuthService { if (!user.roles.some((role) => !role.isAdmin)) throw new BadRequestException(AuthMessage.ADMIN_CAN_NOT_LOGIN); // if (user.roles.some((role) => role.isAdmin)) throw new BadRequestException(AuthMessage.ADMIN_CAN_NOT_LOGIN); - const tokens = this.generateAccessAndRefreshToken(user); + const tokens = await this.tokensService.generateTokens(user); await this.notificationService.createLoginNotification(user.id, { userPhone: user.phone }); return { @@ -183,7 +182,6 @@ export class AuthService { }; } - //****************** */ //****************** */ async adminVerifyLoginOtp(verifyOtpDto: VerifyOtpDto) { @@ -195,7 +193,7 @@ export class AuthService { if (!isUserAdmin) throw new BadRequestException(AuthMessage.NOT_ADMIN); - const tokens = this.generateAccessAndRefreshToken(user); + const tokens = await this.tokensService.generateTokens(user); return { message: AuthMessage.LOGIN_SUCCESS, @@ -219,6 +217,19 @@ export class AuthService { message: AuthMessage.PASSWORD_CHANGED_SUCCESSFULLY, }; } + //****************** */ + + async refreshToken(oldRefreshToken: string) { + return this.tokensService.refreshToken(oldRefreshToken); + } + //****************** */ + + async logout(refreshToken: string) { + await this.tokensService.invalidateRefreshToken(refreshToken); + return { + message: AuthMessage.LOGOUT_SUCCESS, + }; + } //****************** */ @@ -245,17 +256,6 @@ export class AuthService { return user; } - //****************** */ - //****************** */ - private generateAccessAndRefreshToken(user: User) { - return this.tokensService.generateAccessAndRefreshToken({ - id: user.id, - isAdmin: user.roles.some((r) => r.isAdmin), - permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])), - }); - } - //****************** */ - //****************** */ // private checkUserPerm(user: User, perm: PermissionEnum) { // return user.roles.some((role) => role?.permissions?.some((p) => p.name === perm)); // } diff --git a/src/modules/auth/providers/tokens.service.ts b/src/modules/auth/providers/tokens.service.ts index fd441a2..ba7fd0c 100755 --- a/src/modules/auth/providers/tokens.service.ts +++ b/src/modules/auth/providers/tokens.service.ts @@ -1,53 +1,83 @@ -import { Injectable } from "@nestjs/common"; +import { Injectable, UnauthorizedException } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { JwtService } from "@nestjs/jwt"; +import dayjs from "dayjs"; +import { AuthMessage } from "../../../common/enums/message.enum"; +import { User } from "../../users/entities/user.entity"; +import { UsersService } from "../../users/providers/users.service"; +import { RefreshTokensRepository } from "../../users/repositories/refresh-token.repository"; import { ITokenPayload } from "../interfaces/IToken-payload"; -// import { UserRepository } from "../users/providers/users.repository"; @Injectable() export class TokensService { constructor( private readonly configService: ConfigService, private readonly jwtService: JwtService, - // private readonly userRepository: UserRepository, + private readonly refreshTokensRepository: RefreshTokensRepository, + private readonly usersService: UsersService, ) {} // ----------- generate token ----------------- - generateAccessAndRefreshToken(payload: ITokenPayload) { - const access_expire = this.configService.getOrThrow("ACCESS_TOKEN_EXPIRE"); - const refresh_expire = this.configService.getOrThrow("REFRESH_TOKEN_EXPIRE"); - const accessToken = this.jwtService.sign(payload, { expiresIn: `${access_expire}h` }); + async generateTokens(user: User) { + return this.generateAccessAndRefreshToken({ + id: user.id, + isAdmin: user.roles.some((r) => r.isAdmin), + permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])), + }); + } - const refreshToken = this.jwtService.sign(payload, { expiresIn: `${refresh_expire}d` }); + //**************************************************************** */ + + private async generateAccessAndRefreshToken(payload: ITokenPayload) { + const accessExpire = this.configService.getOrThrow("ACCESS_TOKEN_EXPIRE"); + const refreshExpire = this.configService.getOrThrow("REFRESH_TOKEN_EXPIRE"); + + const accessToken = this.jwtService.sign(payload, { expiresIn: `${accessExpire}h` }); + + const refreshToken = this.jwtService.sign(payload, { expiresIn: `${refreshExpire}d` }); + + await this.storeRefreshToken(payload.id, refreshToken); return { - accessToken: { token: accessToken, expire: Date.now() + 1000 * 60 * 60 * access_expire }, - refreshToken: { token: refreshToken, expire: Date.now() + 1000 * 60 * 60 * 24 * refresh_expire }, + accessToken: { token: accessToken, expire: Date.now() + 1000 * 60 * 60 * accessExpire }, + refreshToken: { token: refreshToken, expire: Date.now() + 1000 * 60 * 60 * 24 * refreshExpire }, }; } - //****************************** */ - // validateRefreshToken(token: string) { - // const { sub } = this.verifyToken(token, "refresh"); - // return this.generateAccessAndRefreshToken({ sub: sub }); - // } + //**************************************************************** */ + async storeRefreshToken(userId: string, refreshToken: string) { + const refreshExpire = this.configService.getOrThrow("REFRESH_TOKEN_EXPIRE"); - // verifyToken(token: string, type: "access" | "refresh"): ITokenPayload { - // try { - // if (type === "access") { - // return this.jwtService.verify(token, { - // secret: process.env.ACCESS_TOKEN_SECRET, - // ignoreExpiration: false, - // }); - // } else if (type === "refresh") { - // return this.jwtService.verify(token, { - // secret: process.env.REFRESH_TOKEN_SECRET, - // ignoreExpiration: false, - // }); - // } else throw new Error("Invalid token type => access / refresh"); - // } catch { - // throw new HttpException(AuthMessage.LoginAgain, HttpStatus.UNAUTHORIZED); - // } - // } + const expiresAt = dayjs().add(refreshExpire, "day").toDate(); + + const token = this.refreshTokensRepository.create({ + token: refreshToken, + user: { id: userId }, + expiresAt, + }); + + await this.refreshTokensRepository.save(token); + } + /************************************************************ */ + + async refreshToken(oldRefreshToken: string) { + const token = await this.refreshTokensRepository.findOne({ where: { token: oldRefreshToken }, relations: { user: true } }); + + if (!token) throw new UnauthorizedException(AuthMessage.INVALID_REFRESH_TOKEN); + + if (dayjs(token.expiresAt).isBefore(dayjs())) throw new UnauthorizedException(AuthMessage.REFRESH_TOKEN_EXPIRED); + + const { user } = await this.usersService.findOneById(token.user.id); + await this.refreshTokensRepository.delete({ id: token.id }); + + return await this.generateTokens(user); + } + /************************************************************ */ + + async invalidateRefreshToken(oldRefreshToken: string) { + const token = await this.refreshTokensRepository.findOne({ where: { token: oldRefreshToken }, relations: { user: true } }); + + if (token) await this.refreshTokensRepository.delete({ id: token.id }); + } } diff --git a/src/modules/users/entities/refresh-token.entity.ts b/src/modules/users/entities/refresh-token.entity.ts new file mode 100644 index 0000000..8a9dde7 --- /dev/null +++ b/src/modules/users/entities/refresh-token.entity.ts @@ -0,0 +1,16 @@ +import { Column, Entity, ManyToOne } from "typeorm"; + +import { User } from "./user.entity"; +import { BaseEntity } from "../../../common/entities/base.entity"; + +@Entity() +export class RefreshToken extends BaseEntity { + @Column({ type: "text" }) + token: string; + + @ManyToOne(() => User, (user) => user.refreshTokens, { onDelete: "CASCADE" }) + user: User; + + @Column({ type: "timestamptz", nullable: true }) + expiresAt: Date; +} diff --git a/src/modules/users/entities/user.entity.ts b/src/modules/users/entities/user.entity.ts index df4f523..666e9dd 100755 --- a/src/modules/users/entities/user.entity.ts +++ b/src/modules/users/entities/user.entity.ts @@ -3,6 +3,7 @@ import { Column, Entity, JoinTable, ManyToMany, OneToMany, OneToOne } from "type import { LegalUser } from "./legal-user.entity"; import { RealUser } from "./real-user.entity"; +import { RefreshToken } from "./refresh-token.entity"; import { Role } from "./role.entity"; import { UserGroup } from "./user-group.entity"; import { BaseEntity } from "../../../common/entities/base.entity"; @@ -120,6 +121,9 @@ export class User extends BaseEntity { @OneToMany(() => UserQuickAccess, (quickAccess) => quickAccess.user) quickAccesses: UserQuickAccess[]; + + @OneToMany(() => RefreshToken, (refreshToken) => refreshToken.user, { cascade: true }) + refreshTokens: RefreshToken[]; } // @ManyToMany(() => DanakService, (danakService) => danakService.users) diff --git a/src/modules/users/providers/customers.service.ts b/src/modules/users/providers/customers.service.ts index 238f1aa..c3671b1 100644 --- a/src/modules/users/providers/customers.service.ts +++ b/src/modules/users/providers/customers.service.ts @@ -2,6 +2,7 @@ import { BadRequestException, Injectable, Logger } from "@nestjs/common"; import { DataSource, Not } from "typeorm"; import { CommonMessage, UserMessage } from "../../../common/enums/message.enum"; +import { Address } from "../../address/entities/address.entity"; import { AddressService } from "../../address/providers/address.service"; import { UserSettingsService } from "../../settings/providers/user-settings.service"; import { PasswordService } from "../../utils/providers/password.service"; @@ -83,67 +84,144 @@ export class CustomersService { await queryRunner.connect(); await queryRunner.startTransaction(); + const { + registrationName, + economicCode, + nationalIdentity, + registrationCode, + postalCode, + nationalCode, + address, + cityId, + birthDate, + email, + firstName, + lastName, + password, + phone, + } = updateDto; + + const legalUserUpdateData = { + registrationName, + economicCode, + nationalIdentity, + registrationCode, + phone, + }; + + const userUpdateData = { + email, + firstName, + lastName, + password, + phone, + birthDate, + }; + + // const addressUpdateData = { + // postalCode, + // address, + // cityId, + // }; + const user = await queryRunner.manager.findOne(this.userRepository.target, { where: { id: customerId } }); if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND); - if (updateDto.email) { + if (email) { const existingEmail = await queryRunner.manager.findOne(this.userRepository.target, { - where: { email: updateDto.email, id: Not(user.id) }, + where: { email, id: Not(user.id) }, }); if (existingEmail) throw new BadRequestException(UserMessage.EMAIL_EXIST); } - if (updateDto.nationalCode) { + if (nationalCode) { const existingNationalCode = await queryRunner.manager.findOne(this.userRepository.target, { - where: { nationalCode: updateDto.nationalCode, id: Not(user.id) }, + where: { nationalCode: nationalCode, id: Not(user.id) }, }); if (existingNationalCode) throw new BadRequestException(UserMessage.NATIONAL_CODE_EXIST); } - if (updateDto.phone) { + if (phone) { const existingPhone = await queryRunner.manager.findOne(this.userRepository.target, { - where: { phone: updateDto.phone, id: Not(user.id) }, + where: { phone: phone, id: Not(user.id) }, }); if (existingPhone) throw new BadRequestException(UserMessage.PHONE_EXIST); } - await queryRunner.manager.update(this.userRepository.target, { id: customerId }, updateDto); + if (nationalCode) { + const existingNationalCode = await queryRunner.manager.findOne(this.realUserRepository.target, { + where: { nationalCode: nationalCode, id: Not(user.id) }, + }); + if (existingNationalCode) throw new BadRequestException(UserMessage.NATIONAL_CODE_EXIST); + } - const legalUser = await queryRunner.manager.findOne(this.legalUserRepository.target, { where: { user: { id: customerId } } }); + await queryRunner.manager.update(this.userRepository.target, { id: customerId }, userUpdateData); + if (password) { + const hashPassword = await this.passwordService.hashPassword(password); + await queryRunner.manager.update(this.userRepository.target, { id: customerId }, { password: hashPassword }); + } + + const legalUser = await queryRunner.manager.findOne(this.legalUserRepository.target, { + where: { user: { id: customerId } }, + relations: { address: true }, + }); if (!legalUser) throw new BadRequestException(UserMessage.LEGAL_DATA_NOT_FOUND); - if (updateDto.economicCode) { + if (economicCode) { const existingEconomicCode = await queryRunner.manager.findOne(this.legalUserRepository.target, { - where: { economicCode: updateDto.economicCode, id: Not(legalUser.id) }, + where: { economicCode, id: Not(legalUser.id) }, }); if (existingEconomicCode) throw new BadRequestException(UserMessage.ECONOMIC_CODE_EXIST); } - if (updateDto.registrationCode) { + if (registrationCode) { const existingRegistrationCode = await queryRunner.manager.findOne(this.legalUserRepository.target, { - where: { registrationCode: updateDto.registrationCode, id: Not(legalUser.id) }, + where: { registrationCode, id: Not(legalUser.id) }, }); if (existingRegistrationCode) throw new BadRequestException(UserMessage.REGISTRATION_CODE_EXIST); } - if (updateDto.nationalIdentity) { + if (nationalIdentity) { const existingNationalIdentity = await queryRunner.manager.findOne(this.legalUserRepository.target, { - where: { nationalIdentity: updateDto.nationalIdentity, id: Not(legalUser.id) }, + where: { nationalIdentity, id: Not(legalUser.id) }, }); if (existingNationalIdentity) throw new BadRequestException(UserMessage.NATIONAL_IDENTITY_EXIST); } - if (updateDto.cityId) { - const { city } = await this.addressService.getCity(+updateDto.cityId); - await queryRunner.manager.update(this.legalUserRepository.target, { id: legalUser.id }, { address: { city } }); + if (registrationName) { + const existingRegistrationName = await queryRunner.manager.findOne(this.legalUserRepository.target, { + where: { registrationName, id: Not(legalUser.id) }, + }); + if (existingRegistrationName) throw new BadRequestException(UserMessage.REGISTRATION_NAME_EXIST); } - const { address, ...legalUserUpdateData } = updateDto; await queryRunner.manager.update(this.legalUserRepository.target, { id: legalUser.id }, legalUserUpdateData); - if (address) { - await queryRunner.manager.update(this.legalUserRepository.target, { id: legalUser.id }, { address: { fullAddress: address } }); + // Update address if needed + if (cityId || address || postalCode) { + // Get the address entity + const addressEntity = legalUser.address; + + if (!addressEntity) throw new BadRequestException(UserMessage.ADDRESS_NOT_FOUND); + + // Prepare address updates + const addressUpdates: any = {}; + + if (cityId) { + const { city } = await this.addressService.getCity(+cityId); + addressUpdates.city = city; + } + + if (address) { + addressUpdates.fullAddress = address; + } + + if (postalCode) { + addressUpdates.postalCode = postalCode; + } + + await queryRunner.manager.update(Address, { id: addressEntity.id }, addressUpdates); } await queryRunner.commitTransaction(); @@ -306,7 +384,7 @@ export class CustomersService { async getCustomerById(userId: string) { const customer = await this.userRepository.findOne({ where: { id: userId, roles: { name: RoleEnum.USER } }, - relations: { legalUser: true, realUser: true }, + relations: { legalUser: { address: { city: { province: true } } }, realUser: { address: { city: { province: true } } } }, }); return { customer }; diff --git a/src/modules/users/repositories/refresh-token.repository.ts b/src/modules/users/repositories/refresh-token.repository.ts new file mode 100644 index 0000000..f9f7c9d --- /dev/null +++ b/src/modules/users/repositories/refresh-token.repository.ts @@ -0,0 +1,12 @@ +import { Injectable } from "@nestjs/common"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Repository } from "typeorm"; + +import { RefreshToken } from "../entities/refresh-token.entity"; + +@Injectable() +export class RefreshTokensRepository extends Repository { + constructor(@InjectRepository(RefreshToken) refreshTokenRepository: Repository) { + super(refreshTokenRepository.target, refreshTokenRepository.manager, refreshTokenRepository.queryRunner); + } +} diff --git a/src/modules/users/users.controller.ts b/src/modules/users/users.controller.ts index b29587d..8c06aaa 100755 --- a/src/modules/users/users.controller.ts +++ b/src/modules/users/users.controller.ts @@ -12,6 +12,7 @@ import { CreateRoleDto } from "./DTO/create-role.dto"; import { SearchAdminQueryDto } from "./DTO/search-admins-query.dto"; import { SearchCustomersDto } from "./DTO/search-customers.dto"; import { SearchRolesQueryDto } from "./DTO/search-roles.dto"; +import { UpdateCustomerDto } from "./DTO/update-customer.dto"; import { UpdateProfileDto } from "./DTO/update-profile.dto"; import { CreateUserGroupDto } from "./DTO/user-group.dto"; import { EmailVerifyQueryDto } from "./DTO/verify-email-query.dto"; @@ -144,11 +145,18 @@ export class UsersController { @ApiOperation({ summary: "Create customer" }) @AuthGuards() @HttpCode(HttpStatus.CREATED) - @Post("customer") + @Post("customers") createCustomer(@Body() createDto: CreateCustomerDto) { return this.customersService.createCustomer(createDto); } + @ApiOperation({ summary: "Update customer" }) + @AuthGuards() + @Patch("customers/:id") + updateCustomer(@Param() paramDto: ParamDto, @Body() updateDto: UpdateCustomerDto) { + return this.customersService.updateCustomer(paramDto.id, updateDto); + } + @ApiOperation({ summary: "get customers ==> admin route" }) @AuthGuards() @PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS) diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index 281f777..e370441 100755 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -3,6 +3,7 @@ import { TypeOrmModule } from "@nestjs/typeorm"; import { LegalUser } from "./entities/legal-user.entity"; import { Permission } from "./entities/permission.entity"; +import { RefreshToken } from "./entities/refresh-token.entity"; import { Role } from "./entities/role.entity"; import { UserGroup } from "./entities/user-group.entity"; import { User } from "./entities/user.entity"; @@ -24,10 +25,11 @@ import { UsersController } from "./users.controller"; import { UtilsModule } from "../utils/utils.module"; import { AdminsService } from "./providers/admins.service"; import { CustomersService } from "./providers/customers.service"; +import { RefreshTokensRepository } from "./repositories/refresh-token.repository"; @Module({ imports: [ - TypeOrmModule.forFeature([User, Role, UserGroup, UserSetting, RealUser, LegalUser, Permission]), + TypeOrmModule.forFeature([User, Role, UserGroup, UserSetting, RealUser, LegalUser, Permission, RefreshToken]), WalletsModule, UtilsModule, AddressModule, @@ -37,6 +39,7 @@ import { CustomersService } from "./providers/customers.service"; AdminsService, CustomersService, UserRepository, + RefreshTokensRepository, RoleRepository, UserGroupRepository, UserSettingsRepository, @@ -47,6 +50,6 @@ import { CustomersService } from "./providers/customers.service"; AddressService, ], controllers: [UsersController], - exports: [UsersService, UserRepository, CustomersService, AdminsService], + exports: [UsersService, UserRepository, CustomersService, AdminsService, RefreshTokensRepository], }) export class UsersModule {}