update
This commit is contained in:
+2
-1
@@ -58,7 +58,8 @@
|
||||
"fastify": "^5.6.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"ulid": "^3.0.1"
|
||||
"ulid": "^3.0.1",
|
||||
"dayjs": "^1.11.18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
|
||||
@@ -4,14 +4,12 @@ import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||
import { Admin } from './entities/admin.entity';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { AdminRepository } from './repositories/admin.repository';
|
||||
|
||||
import { AdminController } from './controllers/admin.controller';
|
||||
import { UtilsModule } from '../utils/utils.module';
|
||||
import { BusinessModule } from '../business/business.module';
|
||||
|
||||
|
||||
@Module({
|
||||
providers: [AdminService, AdminRepository, ],
|
||||
controllers: [AdminController],
|
||||
providers: [AdminService, AdminRepository,],
|
||||
controllers: [],
|
||||
imports: [
|
||||
MikroOrmModule.forFeature([Admin]),
|
||||
JwtModule,
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import { Controller, Post, Body, HttpCode, HttpStatus, Get, UseGuards, Patch, Param, Delete } from '@nestjs/common';
|
||||
import { AdminService } from '../providers/admin.service';
|
||||
import { UpdateAdminDto } from '../dto/update-admin.dto';
|
||||
import { ApiTags, ApiOperation, ApiBody, ApiBearerAuth, ApiParam } from '@nestjs/swagger';
|
||||
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
||||
import { SuperAdminAuthGuard } from 'src/modules/auth/guards/superAdminAuth.guard';
|
||||
import { BusinessId } from 'src/common/decorators';
|
||||
import { AdminId } from 'src/common/decorators/admin-id.decorator';
|
||||
|
||||
@ApiBearerAuth()
|
||||
@ApiTags('admin')
|
||||
@Controller()
|
||||
export class AdminController {
|
||||
constructor(private readonly adminService: AdminService) { }
|
||||
|
||||
// @Get('admin/admins')
|
||||
// @UseGuards(AdminAuthGuard)
|
||||
// @Permissions(Permission.MANAGE_ADMINS)
|
||||
// getAll(@BusinessId() restId: string) {
|
||||
// return this.adminService.findAllByRestaurantId(restId);
|
||||
// }
|
||||
|
||||
// @Get('admin/admins/profile')
|
||||
// @UseGuards(AdminAuthGuard)
|
||||
// @Permissions(Permission.MANAGE_ADMINS)
|
||||
// getMe(@AdminId() adminId: string, @BusinessId() restId: string) {
|
||||
// return this.adminService.finAdminById(adminId, restId);
|
||||
// }
|
||||
|
||||
|
||||
// @Patch('admin/admins/:adminId')
|
||||
// @UseGuards(AdminAuthGuard)
|
||||
// @Permissions(Permission.MANAGE_ADMINS)
|
||||
// @ApiOperation({ summary: 'Update an admin' })
|
||||
// @ApiParam({ name: 'adminId', description: 'Admin ID' })
|
||||
// update(@Param('adminId') adminId: string, @Body() dto: UpdateAdminDto,
|
||||
// @BusinessId() restId: string) {
|
||||
// return this.adminService.update(adminId, restId, dto);
|
||||
// }
|
||||
|
||||
// @Get('admin/admins/:adminId')
|
||||
// @UseGuards(AdminAuthGuard)
|
||||
// @Permissions(Permission.MANAGE_ADMINS)
|
||||
// getById(@Param('adminId') adminId: string, @BusinessId() restId: string) {
|
||||
// return this.adminService.finAdminById(adminId, restId);
|
||||
// }
|
||||
|
||||
// @Delete('admin/admins/:adminId')
|
||||
// @UseGuards(AdminAuthGuard)
|
||||
// @Permissions(Permission.MANAGE_ADMINS)
|
||||
// @ApiOperation({ summary: 'Delete an admin by ID' })
|
||||
// @ApiParam({ name: 'id', description: 'Admin ID' })
|
||||
// deleteById(@Param('adminId') adminId: string, @BusinessId() restId: string) {
|
||||
// return this.adminService.remove(adminId, restId);
|
||||
// }
|
||||
|
||||
|
||||
// @UseGuards(SuperAdminAuthGuard)
|
||||
// @Delete('super-admin/restaurants/:restaurantId/admins/:adminId')
|
||||
// @ApiOperation({ summary: 'Revoke admin role from a restaurant (Super Admin only)' })
|
||||
// @ApiParam({ name: 'restaurantId', description: 'Restaurant ID' })
|
||||
// @ApiParam({ name: 'adminId', description: 'Admin ID' })
|
||||
// revokeAdminFromRestaurant(
|
||||
// @Param('restaurantId') restaurantId: string,
|
||||
// @Param('adminId') adminId: string,
|
||||
// ) {
|
||||
// return this.adminService.remove(adminId, restaurantId);
|
||||
// }
|
||||
}
|
||||
@@ -1,80 +1,16 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { wrap } from '@mikro-orm/core';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { UpdateAdminDto } from '../dto/update-admin.dto';
|
||||
import { AdminRepository } from '../repositories/admin.repository';
|
||||
import { CreateAdminDto } from '../dto/create-admin.dto';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class AdminService {
|
||||
constructor(
|
||||
private readonly adminRepository: AdminRepository,
|
||||
private readonly em: EntityManager,
|
||||
private readonly em: EntityManager,
|
||||
) { }
|
||||
|
||||
async findByPhone(phone: string) {
|
||||
return this.adminRepository.findOne({ phone });
|
||||
}
|
||||
|
||||
// async create(dto:CreateAdminDto){
|
||||
// this.em.create(dto)
|
||||
// }
|
||||
|
||||
async finAdminById(
|
||||
adminId: string,
|
||||
restId: string,
|
||||
) {
|
||||
const admin = await this.adminRepository.findOne(
|
||||
{ id: adminId },
|
||||
{},
|
||||
);
|
||||
if (!admin) {
|
||||
throw new NotFoundException('Admin not found');
|
||||
}
|
||||
const adminPlain = wrap(admin).toObject();
|
||||
|
||||
return { ...adminPlain };
|
||||
}
|
||||
|
||||
async findAllByRestaurantId(restId: string) {
|
||||
return this.adminRepository.find({}, { populate: [] });
|
||||
}
|
||||
|
||||
|
||||
|
||||
async update(adminId: string, restId: string, dto: UpdateAdminDto) {
|
||||
const admin = await this.adminRepository.findOne(
|
||||
{ id: adminId },
|
||||
{ populate: [] },
|
||||
);
|
||||
|
||||
if (!admin) {
|
||||
throw new NotFoundException('Admin not found');
|
||||
}
|
||||
|
||||
const { ...rest } = dto;
|
||||
|
||||
// Update scalar fields (firstName, lastName, phone)
|
||||
if (rest.firstName !== undefined) {
|
||||
admin.firstName = rest.firstName;
|
||||
}
|
||||
if (rest.lastName !== undefined) {
|
||||
admin.lastName = rest.lastName;
|
||||
}
|
||||
if (rest.phone !== undefined && rest.phone !== admin.phone) {
|
||||
// const exists = await this.adminRepository.findOne({ phone: normalizedPhone });
|
||||
// if (exists) {
|
||||
// throw new ConflictException('This Phone Number is already taken');
|
||||
// }
|
||||
// admin.phone = normalizedPhone;
|
||||
}
|
||||
|
||||
// Update role if roleId is provided
|
||||
|
||||
|
||||
await this.em.persistAndFlush(admin);
|
||||
return admin;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import type { Admin } from '../entities/admin.entity';
|
||||
|
||||
export interface AdminDetailResponse {
|
||||
id: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
phone: string;
|
||||
role: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
permissions: string[];
|
||||
restaurant?: {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Extract permissions - ensure collection is loaded if needed
|
||||
@@ -10,36 +10,6 @@ import { RefreshTokenDto } from '../dto/refresh-token.dto';
|
||||
export class AuthController {
|
||||
constructor(private readonly authService: AuthService) { }
|
||||
|
||||
// @Throttle({ default: { limit: 3, ttl: 180_000 } })
|
||||
// @Post('public/auth/otp/request')
|
||||
// @ApiOperation({ summary: 'Request OTP for login or signup' })
|
||||
// @ApiBody({ type: RequestOtpDto, description: 'Mobile number to receive OTP' })
|
||||
// otpRequest(@Body() dto: RequestOtpDto) {
|
||||
// return this.authService.requestOtp(dto, false);
|
||||
// }
|
||||
|
||||
|
||||
// @RefreshTokenRateLimit()
|
||||
// @ApiOperation({ summary: 'refresh the user access token / refresh token' })
|
||||
// @Post('public/auth/refresh')
|
||||
// refreshToken(@Body() refreshTokenDto: RefreshTokenDto) {
|
||||
// return this.authService.refreshToken(refreshTokenDto.refreshToken);
|
||||
// }
|
||||
|
||||
// @Throttle({ default: { limit: 3, ttl: 180_000 } })
|
||||
// @Post('admin/auth/otp/request')
|
||||
// @ApiOperation({ summary: 'Request OTP for login or signup' })
|
||||
// @ApiBody({ type: RequestOtpDto, description: 'Mobile number to receive OTP' })
|
||||
// otpRequestAdmin(@Body() dto: RequestOtpDto) {
|
||||
// return this.authService.requestOtp(dto, true);
|
||||
// }
|
||||
|
||||
// @Post('admin/auth/otp/verify')
|
||||
// @ApiOperation({ summary: 'Verify OTP code' })
|
||||
// @ApiBody({ type: VerifyOtpDto, description: 'Mobile number and OTP code' })
|
||||
// otpVerifyAdmin(@Body() dto: VerifyOtpDto) {
|
||||
// return this.authService.verifyOtpAdmin(dto.phone, dto.slug, dto.otp);
|
||||
// }
|
||||
|
||||
@ApiOperation({ summary: 'refresh the admin access token / refresh token' })
|
||||
@Post('admin/auth/refresh')
|
||||
@@ -47,7 +17,6 @@ export class AuthController {
|
||||
return this.authService.refreshToken(refreshTokenDto.refreshToken);
|
||||
}
|
||||
|
||||
// //super admin routes
|
||||
|
||||
@UseGuards(SuperAdminAuthGuard)
|
||||
@Post('super-admin/auth/direct-login')
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { IsNotEmpty, IsString, IsMobilePhone } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class RequestOtpDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@ApiProperty({ example: '09362532122', description: 'Mobile number' })
|
||||
@IsMobilePhone('fa-IR')
|
||||
phone: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@ApiProperty({ example: 'zhivan', description: 'restaurant slug' })
|
||||
slug: string;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { IsNotEmpty, IsString, Length, IsMobilePhone } from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class VerifyOtpDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@ApiProperty({ example: '09362532122', description: 'Mobile number' })
|
||||
@IsMobilePhone('fa-IR')
|
||||
phone: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@ApiProperty({ example: '', description: 'Otp' })
|
||||
@Length(5)
|
||||
otp: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@ApiProperty({ example: 'zhivan', description: 'restaurant slug' })
|
||||
slug: string;
|
||||
}
|
||||
@@ -7,12 +7,11 @@ import {
|
||||
Logger,
|
||||
ForbiddenException,
|
||||
} from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { Request } from 'express';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { IAdminTokenPayload } from '../interfaces/IToken-payload';
|
||||
|
||||
|
||||
export interface AdminAuthRequest extends Request {
|
||||
adminId: string;
|
||||
businessId: string;
|
||||
@@ -27,7 +26,6 @@ export class AdminAuthGuard implements CanActivate {
|
||||
private readonly jwtService: JwtService,
|
||||
@Inject(ConfigService)
|
||||
private readonly configService: ConfigService,
|
||||
private readonly reflector: Reflector,
|
||||
) { }
|
||||
|
||||
async canActivate(context: ExecutionContext) {
|
||||
@@ -60,17 +58,6 @@ export class AdminAuthGuard implements CanActivate {
|
||||
request['adminId'] = payload.adminId;
|
||||
request['businessId'] = payload.businessId;
|
||||
|
||||
// check if the user has the required permissions
|
||||
// const requiredPermissions =
|
||||
// this.reflector.getAllAndOverride<string[]>(PERMISSIONS_KEY, [context.getHandler(), context.getClass()]) ?? [];
|
||||
|
||||
// if (!requiredPermissions || requiredPermissions.length === 0) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
|
||||
@@ -11,99 +11,13 @@ export class AuthService {
|
||||
) {
|
||||
}
|
||||
|
||||
// private userOtpKey(restaurantSlug: string, phone: string) {
|
||||
// return `otp:${restaurantSlug}:${phone}`;
|
||||
// }
|
||||
|
||||
// private adminOtpKey(restaurantSlug: string, phone: string) {
|
||||
// return `otp-admin:${restaurantSlug}:${phone}`;
|
||||
// }
|
||||
|
||||
async directLogin(danakSubId: string) {
|
||||
const business = await this.businessService.findBySubIdOrFail(danakSubId)
|
||||
console.log(business)
|
||||
const admin = business.admin
|
||||
const tokens = await this.tokensService.generateAccessAndRefreshToken(admin.id, business.id);
|
||||
return { tokens }
|
||||
}
|
||||
|
||||
// async requestOtp(dto: RequestOtpDto, isAdmin: boolean) {
|
||||
// const { phone, slug } = dto;
|
||||
// const normalizedPhone = normalizePhone(phone);
|
||||
|
||||
// if (isAdmin) {
|
||||
// const admin = await this.adminRepository.findByPhoneAndRestaurantSlug(normalizedPhone, slug);
|
||||
// if (!admin) {
|
||||
// throw new BadRequestException(AuthMessage.ADMIN_NOT_FOUND);
|
||||
// }
|
||||
// }
|
||||
// const code = this.generateOtpCode();
|
||||
// const key = isAdmin ? this.adminOtpKey(slug, normalizedPhone) : this.userOtpKey(slug, normalizedPhone);
|
||||
// await this.cacheService.set(key, code, this.OTP_EXPIRATION_TIME);
|
||||
|
||||
// await this.smsService.sendotp(normalizedPhone, code);
|
||||
|
||||
// return { code: null };
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// async verifyOtpAdmin(phone: string, slug: string, code: string) {
|
||||
// const normalizedPhone = normalizePhone(phone);
|
||||
// const key = this.adminOtpKey(slug, normalizedPhone);
|
||||
// const cachedCode = await this.cacheService.get(key);
|
||||
|
||||
// if (!cachedCode) throw new BadRequestException('OTP expired or not found');
|
||||
|
||||
// if (cachedCode !== code) throw new BadRequestException('Invalid OTP');
|
||||
// await this.cacheService.del(key);
|
||||
|
||||
// // const admin = await this.adminRepository.findByPhoneAndRestaurantSlug(normalizedPhone, slug);
|
||||
|
||||
// // if (!admin) {
|
||||
// // throw new BadRequestException(AuthMessage.ADMIN_NOT_FOUND);
|
||||
// // }
|
||||
|
||||
// const rest = await this.restRepository.findOne({ slug });
|
||||
|
||||
// if (!rest) {
|
||||
// throw new BadRequestException(RestMessage.NOT_FOUND);
|
||||
// }
|
||||
|
||||
// const tokens = await this.tokensService.generateAccessAndRefreshToken(admin.id, rest.id, true, slug);
|
||||
|
||||
|
||||
|
||||
// return { tokens, admin };
|
||||
// }
|
||||
/**
|
||||
*
|
||||
to use for login directly from DSC
|
||||
*/
|
||||
// async loginAdminForDsc(phone: string, slug: string) {
|
||||
// const normalizedPhone = normalizePhone(phone);
|
||||
// const admin = await this.adminRepository.findByPhoneAndRestaurantSlug(normalizedPhone, slug);
|
||||
|
||||
// if (!admin) {
|
||||
// throw new BadRequestException(AuthMessage.ADMIN_NOT_FOUND);
|
||||
// }
|
||||
|
||||
// const rest = await this.restRepository.findOne({ slug });
|
||||
|
||||
// if (!rest) {
|
||||
// throw new BadRequestException(RestMessage.NOT_FOUND);
|
||||
// }
|
||||
|
||||
// const tokens = await this.tokensService.generateAccessAndRefreshToken(admin.id, rest.id, true, slug);
|
||||
|
||||
|
||||
// return { tokens, admin };
|
||||
// }
|
||||
|
||||
// private generateOtpCode(): string {
|
||||
// const code = randomInt(10000, 100000);
|
||||
// return code.toString();
|
||||
// }
|
||||
|
||||
refreshToken(oldRefreshToken: string) {
|
||||
return this.tokensService.refreshToken(oldRefreshToken);
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
|
||||
export interface UserLoginResponse {
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName?: string;
|
||||
phone: string;
|
||||
|
||||
isActive?: boolean;
|
||||
restaurant: {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user