add : reseller
This commit is contained in:
@@ -4,8 +4,9 @@ import { ApiBearerAuth } from "@nestjs/swagger";
|
||||
import { AdminRouteGuard } from "../../modules/auth/guards/admin.guard";
|
||||
import { JwtAuthGuard } from "../../modules/auth/guards/auth.guard";
|
||||
import { PermissionsGuard } from "../../modules/auth/guards/permission.guard";
|
||||
import { ResellerRouteGuard } from "../../modules/auth/guards/reseller.guard";
|
||||
// import { RoleGuard } from "../../modules/auth/guards/role.guard";
|
||||
|
||||
export function AuthGuards() {
|
||||
return applyDecorators(UseGuards(JwtAuthGuard, PermissionsGuard, AdminRouteGuard), ApiBearerAuth("authorization"));
|
||||
return applyDecorators(UseGuards(JwtAuthGuard, PermissionsGuard, AdminRouteGuard,ResellerRouteGuard), ApiBearerAuth("authorization"));
|
||||
}
|
||||
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
export const RESELLER_ROUTE = "shouldReseller";
|
||||
import { SetMetadata } from "@nestjs/common";
|
||||
|
||||
export const ResellerRoute = (isResellerRoute: boolean = true) => SetMetadata(RESELLER_ROUTE, isResellerRoute);
|
||||
@@ -34,11 +34,11 @@ export class AuthController {
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation({ summary: "request to login with otp" })
|
||||
@ApiOperation({ summary: "request to login with otp as reseller" })
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post("otp/send/reseller")
|
||||
sendOtpReseller(@Body() requestOtpDto: RequestOtpDto) {
|
||||
return this.authService.requestLoginOtpAgentAndReseller(requestOtpDto);
|
||||
return this.authService.requestLoginOtpReseller(requestOtpDto);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: "verify otp for login" })
|
||||
@@ -79,9 +79,9 @@ export class AuthController {
|
||||
|
||||
@ApiOperation({ summary: "verify otp for login" })
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post("otp/verify/agent")
|
||||
@Post("otp/verify/reseller")
|
||||
resellerVerifyOtp(@Body() verifyOtpDto: VerifyOtpDto) {
|
||||
return this.authService.requestLoginOtpAgentAndReseller(verifyOtpDto);
|
||||
return this.authService.resellerVerifyLoginOtp(verifyOtpDto);
|
||||
}
|
||||
|
||||
@AuthGuards()
|
||||
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from "@nestjs/common";
|
||||
import { FastifyRequest } from "fastify";
|
||||
|
||||
import { AuthMessage } from "../../../common/enums/message.enum";
|
||||
import { Reflector } from "@nestjs/core";
|
||||
import { RESELLER_ROUTE } from "../../../common/decorators/reseller.decorator";
|
||||
|
||||
@Injectable()
|
||||
export class ResellerRouteGuard implements CanActivate {
|
||||
constructor(private reflector: Reflector) {}
|
||||
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const requiredReseller = this.reflector.getAllAndOverride<boolean>(RESELLER_ROUTE, [context.getHandler(), context.getClass()]);
|
||||
if (!requiredReseller) return true;
|
||||
|
||||
const req = context.switchToHttp().getRequest<FastifyRequest>();
|
||||
const user = req.user;
|
||||
|
||||
if (!user) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
||||
|
||||
if (!user.isReseller) throw new ForbiddenException(AuthMessage.UNAUTHORIZED_ACCESS);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { PermissionEnum } from "../../users/enums/permission.enum";
|
||||
export interface ITokenPayload {
|
||||
id: string;
|
||||
isAdmin: boolean;
|
||||
isReseller: boolean;
|
||||
permissions: PermissionEnum[];
|
||||
audience?: string; // Client application identifier for SSO
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ export class AuthService {
|
||||
//****************** */
|
||||
//****************** */
|
||||
|
||||
async requestLoginOtpAgentAndReseller(requestOtpDto: RequestOtpDto) {
|
||||
async requestLoginOtpReseller(requestOtpDto: RequestOtpDto) {
|
||||
const { phone } = requestOtpDto;
|
||||
|
||||
// check if agent with this phone exist or not
|
||||
const { reseller, agent } = await this.checkAgentExistWithPhone(phone)
|
||||
await this.checkAgentExistWithPhone(phone)
|
||||
|
||||
const existCode = await this.otpService.checkExistOtp(phone, "LOGIN_RESELLER_AGENT");
|
||||
if (existCode) {
|
||||
@@ -133,8 +133,7 @@ export class AuthService {
|
||||
|
||||
return {
|
||||
message: AuthMessage.OTP_SENT + otpCode,
|
||||
reseller,
|
||||
agent
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -244,7 +243,7 @@ export class AuthService {
|
||||
|
||||
if (user.deletedAt) throw new BadRequestException(AuthMessage.ACCESS_DENIED);
|
||||
|
||||
const tokens = await this.tokensService.generateTokens(user);
|
||||
const tokens = await this.tokensService.generateTokensForReseller(user);
|
||||
|
||||
return {
|
||||
message: AuthMessage.LOGIN_SUCCESS,
|
||||
|
||||
@@ -45,6 +45,7 @@ export class SSOService {
|
||||
// Generate token with client-specific audience
|
||||
const payload: ITokenPayload = {
|
||||
id: user.id,
|
||||
isReseller:false,
|
||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
||||
audience: clientId,
|
||||
@@ -105,6 +106,7 @@ export class SSOService {
|
||||
const payload: ITokenPayload = {
|
||||
id: user.id,
|
||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||
isReseller:false,
|
||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
||||
audience: clientId,
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ export class TokensService {
|
||||
private readonly jwtService: JwtService,
|
||||
private readonly refreshTokensRepository: RefreshTokensRepository,
|
||||
private readonly dataSource: DataSource,
|
||||
) {}
|
||||
) { }
|
||||
// ----------- generate token -----------------
|
||||
|
||||
async generateTokens(user: User, queryRunner?: QueryRunner) {
|
||||
@@ -27,6 +27,19 @@ export class TokensService {
|
||||
{
|
||||
id: user.id,
|
||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||
isReseller: false,
|
||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
||||
},
|
||||
queryRunner,
|
||||
);
|
||||
}
|
||||
// -----------------------------
|
||||
async generateTokensForReseller(user: User, queryRunner?: QueryRunner) {
|
||||
return this.generateAccessAndRefreshToken(
|
||||
{
|
||||
id: user.id,
|
||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||
isReseller: true,
|
||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
||||
},
|
||||
queryRunner,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsNotEmpty, IsString } from "class-validator";
|
||||
|
||||
export class CreateResellerAgentDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@ApiProperty()
|
||||
userId: string;
|
||||
}
|
||||
@@ -1,29 +1,60 @@
|
||||
import { Controller, Get, Post, Body } from '@nestjs/common';
|
||||
import { Controller, Get, Post, Body, Delete } from '@nestjs/common';
|
||||
import { ResellerService } from './reseller.service';
|
||||
import { ApiOperation } from '@nestjs/swagger';
|
||||
import { PermissionsDec } from '../../common/decorators/permission.decorator';
|
||||
import { PermissionEnum } from '../users/enums/permission.enum';
|
||||
import { CreateResellerDto } from './dto/create-reseller.dto';
|
||||
import { AuthGuards } from '../../common/decorators/auth-guard.decorator';
|
||||
import { AdminRoute } from '../../common/decorators/admin.decorator';
|
||||
import { ResellerRoute } from '../../common/decorators/reseller.decorator';
|
||||
import { UserDec } from '../../common/decorators/user.decorator';
|
||||
import { CreateResellerAgentDto } from './dto/create-reseller-agent.dto';
|
||||
|
||||
@Controller('reseller')
|
||||
@AuthGuards()
|
||||
export class ResellerController {
|
||||
constructor(
|
||||
private readonly resellerService: ResellerService,
|
||||
|
||||
) { }
|
||||
|
||||
|
||||
@ApiOperation({ summary: "create Reseller ==> admin route" })
|
||||
@AdminRoute()
|
||||
@PermissionsDec(PermissionEnum.RESELLER)
|
||||
@Post("reseller")
|
||||
@Post()
|
||||
createReseller(@Body() dto: CreateResellerDto) {
|
||||
return this.resellerService.create(dto)
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: "get Resellers ==> admin route" })
|
||||
@AdminRoute()
|
||||
@PermissionsDec(PermissionEnum.RESELLER)
|
||||
@Get("reseller")
|
||||
@Get()
|
||||
getResellers() {
|
||||
return this.resellerService.findAll()
|
||||
}
|
||||
|
||||
// =========== Reseller-->Agent =============
|
||||
|
||||
@ApiOperation({ summary: "get Reseller agents ==> reseller route" })
|
||||
@ResellerRoute()
|
||||
@Get('agents')
|
||||
getResellerAgents(@UserDec("id") userId: string) {
|
||||
return this.resellerService.finResellerAgents(userId)
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: "Create Reseller agent ==> reseller route" })
|
||||
@ResellerRoute()
|
||||
@Post('agents')
|
||||
createResellerAgent(@UserDec("id") userId: string, @Body() dto: CreateResellerAgentDto) {
|
||||
return this.resellerService.createResellerAgent(userId, dto.userId)
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: "Remove Reseller agent ==> reseller route" })
|
||||
@ResellerRoute()
|
||||
@Delete('agents')
|
||||
deleteResellerAgent(@UserDec("id") userId: string, @Body() dto: CreateResellerAgentDto) {
|
||||
return this.resellerService.removeResellerAgent(userId, dto.userId)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { UsersService } from '../users/providers/users.service';
|
||||
import { CreateResellerDto } from './dto/create-reseller.dto';
|
||||
import { ResellerRepository } from './repositories/reseller.repository';
|
||||
@@ -37,4 +37,47 @@ export class ResellerService {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async finResellerAgents(userId: string) {
|
||||
const reseller = await this.FindOneOrFailByUserId(userId)
|
||||
|
||||
return reseller.agents
|
||||
}
|
||||
|
||||
async FindOneOrFailByUserId(userId: string) {
|
||||
const reseller = await this.resellerRepository.findOne({
|
||||
where: { owner: { id: userId } },
|
||||
relations: { agents: true }
|
||||
})
|
||||
|
||||
if (!reseller) {
|
||||
throw new NotFoundException()
|
||||
}
|
||||
|
||||
return reseller
|
||||
}
|
||||
|
||||
async createResellerAgent(userId: string, userTobeAgent: string) {
|
||||
const reseller = await this.FindOneOrFailByUserId(userId)
|
||||
|
||||
const { user } = await this.usersService.findOneById(userTobeAgent)
|
||||
|
||||
user.reseller = reseller
|
||||
|
||||
await this.usersService.save(user)
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
async removeResellerAgent(userId: string, agentToBeDeleted: string) {
|
||||
await this.FindOneOrFailByUserId(userId)
|
||||
|
||||
const { user } = await this.usersService.findOneById(agentToBeDeleted)
|
||||
|
||||
user.reseller = undefined
|
||||
|
||||
await this.usersService.save(user)
|
||||
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ export class UsersService {
|
||||
private readonly smsService: SmsService,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly referralsService: ReferralsService,
|
||||
) { }
|
||||
) { }
|
||||
|
||||
/************************************************************ */
|
||||
|
||||
@@ -416,5 +416,7 @@ export class UsersService {
|
||||
|
||||
/************************************************************ */
|
||||
|
||||
|
||||
async save(user: User) {
|
||||
return this.userRepository.save(user)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user