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 { AdminRouteGuard } from "../../modules/auth/guards/admin.guard";
|
||||||
import { JwtAuthGuard } from "../../modules/auth/guards/auth.guard";
|
import { JwtAuthGuard } from "../../modules/auth/guards/auth.guard";
|
||||||
import { PermissionsGuard } from "../../modules/auth/guards/permission.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";
|
// import { RoleGuard } from "../../modules/auth/guards/role.guard";
|
||||||
|
|
||||||
export function AuthGuards() {
|
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)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("otp/send/reseller")
|
@Post("otp/send/reseller")
|
||||||
sendOtpReseller(@Body() requestOtpDto: RequestOtpDto) {
|
sendOtpReseller(@Body() requestOtpDto: RequestOtpDto) {
|
||||||
return this.authService.requestLoginOtpAgentAndReseller(requestOtpDto);
|
return this.authService.requestLoginOtpReseller(requestOtpDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "verify otp for login" })
|
@ApiOperation({ summary: "verify otp for login" })
|
||||||
@@ -79,9 +79,9 @@ export class AuthController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "verify otp for login" })
|
@ApiOperation({ summary: "verify otp for login" })
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("otp/verify/agent")
|
@Post("otp/verify/reseller")
|
||||||
resellerVerifyOtp(@Body() verifyOtpDto: VerifyOtpDto) {
|
resellerVerifyOtp(@Body() verifyOtpDto: VerifyOtpDto) {
|
||||||
return this.authService.requestLoginOtpAgentAndReseller(verifyOtpDto);
|
return this.authService.resellerVerifyLoginOtp(verifyOtpDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@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 {
|
export interface ITokenPayload {
|
||||||
id: string;
|
id: string;
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
|
isReseller: boolean;
|
||||||
permissions: PermissionEnum[];
|
permissions: PermissionEnum[];
|
||||||
audience?: string; // Client application identifier for SSO
|
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;
|
const { phone } = requestOtpDto;
|
||||||
|
|
||||||
// check if agent with this phone exist or not
|
// 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");
|
const existCode = await this.otpService.checkExistOtp(phone, "LOGIN_RESELLER_AGENT");
|
||||||
if (existCode) {
|
if (existCode) {
|
||||||
@@ -133,8 +133,7 @@ export class AuthService {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
message: AuthMessage.OTP_SENT + otpCode,
|
message: AuthMessage.OTP_SENT + otpCode,
|
||||||
reseller,
|
|
||||||
agent
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +243,7 @@ export class AuthService {
|
|||||||
|
|
||||||
if (user.deletedAt) throw new BadRequestException(AuthMessage.ACCESS_DENIED);
|
if (user.deletedAt) throw new BadRequestException(AuthMessage.ACCESS_DENIED);
|
||||||
|
|
||||||
const tokens = await this.tokensService.generateTokens(user);
|
const tokens = await this.tokensService.generateTokensForReseller(user);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: AuthMessage.LOGIN_SUCCESS,
|
message: AuthMessage.LOGIN_SUCCESS,
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export class SSOService {
|
|||||||
// Generate token with client-specific audience
|
// Generate token with client-specific audience
|
||||||
const payload: ITokenPayload = {
|
const payload: ITokenPayload = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
|
isReseller:false,
|
||||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
||||||
audience: clientId,
|
audience: clientId,
|
||||||
@@ -105,6 +106,7 @@ export class SSOService {
|
|||||||
const payload: ITokenPayload = {
|
const payload: ITokenPayload = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
isAdmin: user.roles.some((r) => r.isAdmin),
|
||||||
|
isReseller:false,
|
||||||
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
||||||
audience: clientId,
|
audience: clientId,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class TokensService {
|
|||||||
private readonly jwtService: JwtService,
|
private readonly jwtService: JwtService,
|
||||||
private readonly refreshTokensRepository: RefreshTokensRepository,
|
private readonly refreshTokensRepository: RefreshTokensRepository,
|
||||||
private readonly dataSource: DataSource,
|
private readonly dataSource: DataSource,
|
||||||
) {}
|
) { }
|
||||||
// ----------- generate token -----------------
|
// ----------- generate token -----------------
|
||||||
|
|
||||||
async generateTokens(user: User, queryRunner?: QueryRunner) {
|
async generateTokens(user: User, queryRunner?: QueryRunner) {
|
||||||
@@ -27,6 +27,19 @@ export class TokensService {
|
|||||||
{
|
{
|
||||||
id: user.id,
|
id: user.id,
|
||||||
isAdmin: user.roles.some((r) => r.isAdmin),
|
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) : [])),
|
permissions: user.roles.flatMap((r) => (r?.permissions?.length ? r.permissions.map((p) => p.name) : [])),
|
||||||
},
|
},
|
||||||
queryRunner,
|
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 { ResellerService } from './reseller.service';
|
||||||
import { ApiOperation } from '@nestjs/swagger';
|
import { ApiOperation } from '@nestjs/swagger';
|
||||||
import { PermissionsDec } from '../../common/decorators/permission.decorator';
|
import { PermissionsDec } from '../../common/decorators/permission.decorator';
|
||||||
import { PermissionEnum } from '../users/enums/permission.enum';
|
import { PermissionEnum } from '../users/enums/permission.enum';
|
||||||
import { CreateResellerDto } from './dto/create-reseller.dto';
|
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')
|
@Controller('reseller')
|
||||||
|
@AuthGuards()
|
||||||
export class ResellerController {
|
export class ResellerController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly resellerService: ResellerService,
|
private readonly resellerService: ResellerService,
|
||||||
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
|
|
||||||
@ApiOperation({ summary: "create Reseller ==> admin route" })
|
@ApiOperation({ summary: "create Reseller ==> admin route" })
|
||||||
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.RESELLER)
|
@PermissionsDec(PermissionEnum.RESELLER)
|
||||||
@Post("reseller")
|
@Post()
|
||||||
createReseller(@Body() dto: CreateResellerDto) {
|
createReseller(@Body() dto: CreateResellerDto) {
|
||||||
return this.resellerService.create(dto)
|
return this.resellerService.create(dto)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get Resellers ==> admin route" })
|
@ApiOperation({ summary: "get Resellers ==> admin route" })
|
||||||
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.RESELLER)
|
@PermissionsDec(PermissionEnum.RESELLER)
|
||||||
@Get("reseller")
|
@Get()
|
||||||
getResellers() {
|
getResellers() {
|
||||||
return this.resellerService.findAll()
|
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 { UsersService } from '../users/providers/users.service';
|
||||||
import { CreateResellerDto } from './dto/create-reseller.dto';
|
import { CreateResellerDto } from './dto/create-reseller.dto';
|
||||||
import { ResellerRepository } from './repositories/reseller.repository';
|
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 smsService: SmsService,
|
||||||
private readonly cacheService: CacheService,
|
private readonly cacheService: CacheService,
|
||||||
private readonly referralsService: ReferralsService,
|
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