update
This commit is contained in:
@@ -384,7 +384,7 @@ export const enum SmsMessage {
|
|||||||
SEND_SMS_ERROR = 'خطا در ارسال پیامک',
|
SEND_SMS_ERROR = 'خطا در ارسال پیامک',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum BusinessMessage {
|
export const enum RestMessage {
|
||||||
NOT_FOUND = 'کسب و کار یافت نشد',
|
NOT_FOUND = 'کسب و کار یافت نشد',
|
||||||
BUSINESS_ID_REQUIRED = 'شناسه کسب و کار مورد نیاز است',
|
BUSINESS_ID_REQUIRED = 'شناسه کسب و کار مورد نیاز است',
|
||||||
SLUG_REQUIRED = 'اسلاگ مورد نیاز است',
|
SLUG_REQUIRED = 'اسلاگ مورد نیاز است',
|
||||||
|
|||||||
@@ -16,4 +16,9 @@ export class VerifyOtpDto {
|
|||||||
@ApiProperty({ example: '12345', description: 'Otp' })
|
@ApiProperty({ example: '12345', description: 'Otp' })
|
||||||
@Length(5)
|
@Length(5)
|
||||||
otp: string;
|
otp: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
@ApiProperty({ example: '', description: 'Restuarant slug' })
|
||||||
|
slug: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export enum AuthEntityType {
|
|||||||
export interface AuthRequest extends Request {
|
export interface AuthRequest extends Request {
|
||||||
user: {
|
user: {
|
||||||
sub: string; // userId
|
sub: string; // userId
|
||||||
|
slug: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export interface JwtPayload {
|
export interface JwtPayload {
|
||||||
@@ -42,8 +43,6 @@ export class AuthGuard implements CanActivate {
|
|||||||
if (payload.type !== AuthEntityType.USER) {
|
if (payload.type !== AuthEntityType.USER) {
|
||||||
throw new UnauthorizedException('Access denied. User rights required.');
|
throw new UnauthorizedException('Access denied. User rights required.');
|
||||||
}
|
}
|
||||||
// 💡 We're assigning the payload to the request object here
|
|
||||||
// so that we can access it in our route handlers
|
|
||||||
request['user'] = payload;
|
request['user'] = payload;
|
||||||
} catch {
|
} catch {
|
||||||
throw new UnauthorizedException();
|
throw new UnauthorizedException();
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
export interface ILocalTokenPayload {
|
export interface ITokenPayload {
|
||||||
id: string;
|
id: string;
|
||||||
|
restId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IConsoleTokenPayload {
|
|
||||||
id: string;
|
|
||||||
slug: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITokenPayload extends ILocalTokenPayload, IConsoleTokenPayload {}
|
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import { JwtService } from '@nestjs/jwt';
|
|||||||
import { AdminService } from '../../admin/admin.service';
|
import { AdminService } from '../../admin/admin.service';
|
||||||
import { AuthEntityType } from 'src/modules/auth/guards/auth.guard';
|
import { AuthEntityType } from 'src/modules/auth/guards/auth.guard';
|
||||||
import { TokensService } from './tokens.service';
|
import { TokensService } from './tokens.service';
|
||||||
|
import { RestaurantsService } from 'src/modules/restaurants/restaurants.service';
|
||||||
|
import { RestRepository } from 'src/modules/restaurants/repositories/user.repository';
|
||||||
|
import { RestMessage } from 'src/common/enums/message.enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
@@ -18,13 +21,14 @@ export class AuthService {
|
|||||||
private readonly jwtService: JwtService,
|
private readonly jwtService: JwtService,
|
||||||
private readonly adminService: AdminService,
|
private readonly adminService: AdminService,
|
||||||
private readonly tokensService: TokensService,
|
private readonly tokensService: TokensService,
|
||||||
|
private readonly restRepository: RestRepository,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async requestOtp(dto: RequestOtpDto) {
|
async requestOtp(dto: RequestOtpDto) {
|
||||||
const { phone, slug } = dto;
|
const { phone, slug } = dto;
|
||||||
const code = this.generateOtpCode();
|
const code = this.generateOtpCode();
|
||||||
|
|
||||||
await this.cacheService.set(`otp:${phone}:${slug}`, code, 160);
|
await this.cacheService.set(`otp:${slug}:${phone}`, code, 160);
|
||||||
|
|
||||||
await this.smsService.sendOtp(phone, code);
|
await this.smsService.sendOtp(phone, code);
|
||||||
|
|
||||||
@@ -48,17 +52,20 @@ export class AuthService {
|
|||||||
return { success: true, message: ' OTP sent successfully' };
|
return { success: true, message: ' OTP sent successfully' };
|
||||||
}
|
}
|
||||||
|
|
||||||
async verifyOtp(phone: string, code: string) {
|
async verifyOtp(phone: string, slug: string, code: string) {
|
||||||
const cachedCode = await this.cacheService.get(`otp:${phone}`);
|
const cachedCode = await this.cacheService.get(`otp:${slug}:${phone}`);
|
||||||
if (!cachedCode) throw new BadRequestException('OTP expired or not found');
|
if (!cachedCode) throw new BadRequestException('OTP expired or not found');
|
||||||
if (cachedCode !== code) throw new BadRequestException('Invalid OTP');
|
if (cachedCode !== code) throw new BadRequestException('Invalid OTP');
|
||||||
|
|
||||||
await this.cacheService.del(`otp:${phone}`);
|
await this.cacheService.del(`otp:${slug}:${phone}`);
|
||||||
|
|
||||||
const user = await this.userService.findOrCreateByPhone(phone);
|
const user = await this.userService.findOrCreateByPhone(phone);
|
||||||
|
const rest = await this.restRepository.findOne({ slug });
|
||||||
|
if (!rest) {
|
||||||
|
throw new BadRequestException(RestMessage.NOT_FOUND);
|
||||||
|
}
|
||||||
// const accessToken = await this.issueToken(user.id, AuthEntityType.USER);
|
// const accessToken = await this.issueToken(user.id, AuthEntityType.USER);
|
||||||
const tokens = await this.tokensService.generateTokens(user);
|
const tokens = await this.tokensService.generateTokens(user, rest);
|
||||||
|
|
||||||
return { success: true, message: 'User registered successfully!', tokens };
|
return { success: true, message: 'User registered successfully!', tokens };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { AuthMessage, UserMessage } from '../../../common/enums/message.enum';
|
|||||||
import { RefreshToken } from '../../users/entities/refresh-token.entity';
|
import { RefreshToken } from '../../users/entities/refresh-token.entity';
|
||||||
import { User } from '../../users/entities/user.entity';
|
import { User } from '../../users/entities/user.entity';
|
||||||
import { ITokenPayload } from '../interfaces/IToken-payload';
|
import { ITokenPayload } from '../interfaces/IToken-payload';
|
||||||
|
import { Restaurant } from 'src/modules/restaurants/entities/restaurant.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TokensService {
|
export class TokensService {
|
||||||
@@ -20,10 +21,11 @@ export class TokensService {
|
|||||||
private readonly em: EntityManager,
|
private readonly em: EntityManager,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async generateTokens(user: User, em?: EntityManager) {
|
async generateTokens(user: User, rest: Restaurant, em?: EntityManager) {
|
||||||
return this.generateAccessAndRefreshToken(
|
return this.generateAccessAndRefreshToken(
|
||||||
{
|
{
|
||||||
id: user.id,
|
id: user.id,
|
||||||
|
restId: rest.id,
|
||||||
},
|
},
|
||||||
em,
|
em,
|
||||||
);
|
);
|
||||||
@@ -33,7 +35,11 @@ export class TokensService {
|
|||||||
const accessExpire = this.configService.getOrThrow<number>('ACCESS_TOKEN_EXPIRE');
|
const accessExpire = this.configService.getOrThrow<number>('ACCESS_TOKEN_EXPIRE');
|
||||||
const refreshExpire = this.configService.getOrThrow<number>('REFRESH_TOKEN_EXPIRE');
|
const refreshExpire = this.configService.getOrThrow<number>('REFRESH_TOKEN_EXPIRE');
|
||||||
|
|
||||||
const accessToken = await this.jwtService.signAsync(payload, { expiresIn: `${accessExpire}m` });
|
const tokenPayload: ITokenPayload = {
|
||||||
|
id: payload.id,
|
||||||
|
restId: payload.restId,
|
||||||
|
};
|
||||||
|
const accessToken = await this.jwtService.signAsync(tokenPayload, { expiresIn: `${accessExpire}m` });
|
||||||
const refreshToken = this.generateRefreshToken();
|
const refreshToken = this.generateRefreshToken();
|
||||||
|
|
||||||
await this.storeRefreshToken(payload.id, refreshToken, em);
|
await this.storeRefreshToken(payload.id, refreshToken, em);
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { EntityRepository } from '@mikro-orm/postgresql';
|
||||||
|
import type { Restaurant } from '../entities/restaurant.entity';
|
||||||
|
|
||||||
|
// import { PaginationUtils } from '../../utils/services/pagination.utils';
|
||||||
|
|
||||||
|
export class RestRepository extends EntityRepository<Restaurant> {}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { EntityRepository, FilterQuery } from "@mikro-orm/postgresql";
|
||||||
|
|
||||||
|
import { PaginationUtils } from "../../utils/services/pagination.utils";
|
||||||
|
import { UserListQueryDto } from "../DTO/user-list-query.dto";
|
||||||
|
import { User } from "../entities/user.entity";
|
||||||
|
|
||||||
|
export class UserRepository extends EntityRepository<User> {
|
||||||
|
async getUserListForAdmin(businessId: string, queryDto: UserListQueryDto) {
|
||||||
|
const { limit, skip } = PaginationUtils(queryDto);
|
||||||
|
|
||||||
|
const whereClause: FilterQuery<User> = {
|
||||||
|
business: { id: businessId },
|
||||||
|
emailEnabled: true,
|
||||||
|
deletedAt: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (queryDto.q) {
|
||||||
|
whereClause.$or = [
|
||||||
|
{ userName: { $like: `%${queryDto.q}%` } },
|
||||||
|
{ emailAddress: { $like: `%${queryDto.q}%` } },
|
||||||
|
{ displayName: { $like: `%${queryDto.q}%` } },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.isActive) {
|
||||||
|
console.log(queryDto.isActive);
|
||||||
|
|
||||||
|
whereClause.isActive = queryDto.isActive === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.findAndCount(whereClause, {
|
||||||
|
exclude: ["password"],
|
||||||
|
populate: ["domain", "business"],
|
||||||
|
limit,
|
||||||
|
offset: skip,
|
||||||
|
orderBy: { createdAt: "DESC" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@ export class UserController {
|
|||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ApiOperation({ summary: 'Get the current authenticated user profile' })
|
@ApiOperation({ summary: 'Get the current authenticated user profile' })
|
||||||
@Get('/')
|
@Get('/me')
|
||||||
async getUser(@Req() req: AuthRequest) {
|
async getUser(@Req() req: AuthRequest) {
|
||||||
const userId = req.user.sub;
|
const userId = req.user.sub;
|
||||||
const user = await this.userService.findById(userId);
|
const user = await this.userService.findById(userId);
|
||||||
|
|||||||
Reference in New Issue
Block a user