change otp
This commit is contained in:
@@ -24,10 +24,12 @@ import { LearningModule } from './modules/learnings/learning.module';
|
||||
import { CriticismModule } from './modules/criticisms/criticisms.module';
|
||||
import { AnnouncementModule } from './modules/announcements/announcement.module';
|
||||
import { TicketModule } from './modules/ticket/ticket.module';
|
||||
import { cacheConfig } from './config/cache.config';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({ isGlobal: true, cache: true }),
|
||||
CacheModule.registerAsync(cacheConfig()),
|
||||
MikroOrmModule.forRootAsync(dataBaseConfig),
|
||||
UserModule,
|
||||
UtilsModule,
|
||||
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
import { Keyv } from 'keyv';
|
||||
import KeyvRedis from '@keyv/redis';
|
||||
import type { CacheModuleAsyncOptions } from '@nestjs/cache-manager';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { CacheableMemory } from 'cacheable';
|
||||
|
||||
export function cacheConfig(): CacheModuleAsyncOptions {
|
||||
return {
|
||||
isGlobal: true,
|
||||
inject: [ConfigService],
|
||||
useFactory: async (configService: ConfigService) => {
|
||||
const redisUri = configService.get('REDIS_URI');
|
||||
const namespace = configService.get('CACHE_NAMESPACE', 'app-cache');
|
||||
const ttl = +configService.get<number>('CACHE_TTL', 3600); //1 hour
|
||||
|
||||
return {
|
||||
stores: [
|
||||
new Keyv({
|
||||
store: new CacheableMemory({ ttl: ttl * 1000, lruSize: 5000 }),
|
||||
namespace: namespace
|
||||
}),
|
||||
new KeyvRedis(redisUri, { namespace: namespace }),
|
||||
],
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -11,10 +11,7 @@ import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||
import { AdminAuthGuard } from './guards/adminAuth.guard';
|
||||
import { RefreshToken } from './entities/refresh-token.entity';
|
||||
import { NotificationsModule } from '../notification/notifications.module';
|
||||
import { OtpRepository } from './repository/otp.repository';
|
||||
import { OtpService } from './services/otp.service';
|
||||
import { Otp } from './entities/otp.entity';
|
||||
import { AuthCrone } from './crone/auth.crone';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -35,13 +32,12 @@ import { AuthCrone } from './crone/auth.crone';
|
||||
inject: [ConfigService],
|
||||
}),
|
||||
forwardRef(() => AdminModule),
|
||||
|
||||
MikroOrmModule.forFeature([RefreshToken, Otp]),
|
||||
MikroOrmModule.forFeature([RefreshToken]),
|
||||
forwardRef(() => NotificationsModule),
|
||||
|
||||
UtilsModule
|
||||
],
|
||||
controllers: [AuthController],
|
||||
providers: [AuthService, TokensService, AdminAuthGuard, OtpRepository, OtpService, AuthCrone],
|
||||
providers: [AuthService, TokensService, AdminAuthGuard, OtpService],
|
||||
exports: [AdminAuthGuard],
|
||||
})
|
||||
export class AuthModule { }
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { Cron } from '@nestjs/schedule';
|
||||
import { OtpRepository } from '../repository/otp.repository';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class AuthCrone {
|
||||
private readonly logger = new Logger(AuthCrone.name);
|
||||
|
||||
constructor(
|
||||
private readonly otpRepository: OtpRepository
|
||||
) { }
|
||||
|
||||
@Cron('*/59 * * * *', {
|
||||
name: 'completeOldDeliveredOrders',
|
||||
timeZone: 'UTC',
|
||||
})
|
||||
async removeExpireOtp() {
|
||||
this.logger.log("Delete expire otps")
|
||||
await this.otpRepository.nativeDelete({
|
||||
expiresAt: { $lt: new Date() }
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { Entity, Index, OptionalProps, PrimaryKey, Property } from '@mikro-orm/core';
|
||||
|
||||
@Entity({ tableName: 'otp' })
|
||||
@Index({ properties: ['phone'] })
|
||||
export class Otp {
|
||||
[OptionalProps]?: 'createdAt'
|
||||
|
||||
@PrimaryKey({ type: 'varchar', })
|
||||
phone!: string;
|
||||
|
||||
@Property()
|
||||
code!: string;
|
||||
|
||||
@Property({ columnType: 'timestamptz' })
|
||||
expiresAt!: Date
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Otp } from '../entities/otp.entity';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class OtpRepository extends EntityRepository<Otp> {
|
||||
constructor(
|
||||
readonly em: EntityManager,
|
||||
) {
|
||||
super(em, Otp);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +1,21 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { OtpRepository } from "../repository/otp.repository";
|
||||
import { EntityManager } from "@mikro-orm/postgresql";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { CacheService } from "src/modules/util/cache.service";
|
||||
|
||||
@Injectable()
|
||||
export class OtpService {
|
||||
private OTP_EXPIRATION_TIME: number;// in seconds
|
||||
constructor(
|
||||
private readonly otpRepository: OtpRepository,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly em: EntityManager
|
||||
private readonly cacheService: CacheService
|
||||
) {
|
||||
this.OTP_EXPIRATION_TIME = this.configService.get<number>('OTP_EXPIRATION_TIME') ?? 240;
|
||||
}
|
||||
|
||||
async set(phone: string, code: string) {
|
||||
let otpRecord = await this.otpRepository.findOne({ phone })
|
||||
const expiresAt = new Date(Date.now() + this.OTP_EXPIRATION_TIME * 1000)
|
||||
const key = `otp:${phone}`
|
||||
|
||||
if (!otpRecord) {
|
||||
otpRecord = this.otpRepository.create({
|
||||
phone,
|
||||
code,
|
||||
expiresAt
|
||||
})
|
||||
} else {
|
||||
otpRecord.code = code
|
||||
otpRecord.expiresAt = expiresAt
|
||||
}
|
||||
|
||||
await this.em.persistAndFlush(otpRecord)
|
||||
await this.cacheService.set(key, code, this.OTP_EXPIRATION_TIME)
|
||||
|
||||
return { successs: true }
|
||||
|
||||
@@ -37,14 +23,17 @@ export class OtpService {
|
||||
|
||||
async get(phone: string) {
|
||||
|
||||
let otpRecord = await this.otpRepository.findOne({ phone, expiresAt: { $gt: new Date() } })
|
||||
const key = `otp:${phone}`
|
||||
|
||||
return otpRecord?.code
|
||||
return this.cacheService.get(key)
|
||||
|
||||
}
|
||||
|
||||
async delete(phone: string) {
|
||||
await this.otpRepository.nativeDelete({ phone })
|
||||
const key = `otp:${phone}`
|
||||
|
||||
await this.cacheService.del(key)
|
||||
|
||||
return { successs: true }
|
||||
}
|
||||
}
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
import { CACHE_MANAGER, Cache } from '@nestjs/cache-manager';
|
||||
import { Inject, Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class CacheService implements OnModuleInit {
|
||||
private readonly logger = new Logger(CacheService.name);
|
||||
|
||||
constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}
|
||||
|
||||
async onModuleInit() {
|
||||
|
||||
// Should log 'Keyv' or 'KeyvRedis'. If it says 'Memory', the config is still wrong.
|
||||
this.logger.log('Pinging Redis to check connection...');
|
||||
try {
|
||||
await this.set('ping', 'pong', 10); // TTL in seconds
|
||||
const result = await this.get('ping');
|
||||
|
||||
if (result === 'pong') {
|
||||
this.logger.log('✅ Redis connection successful (set/get test passed).');
|
||||
} else {
|
||||
this.logger.error(`❌ Redis connection test failed. Expected 'pong', got '${result}'.`);
|
||||
}
|
||||
|
||||
await this.del('ping');
|
||||
} catch (error: any) {
|
||||
this.logger.error('❌ Failed to connect to Redis during ping test:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get value from cache */
|
||||
async get<T>(key: string): Promise<T | undefined> {
|
||||
return await this.cacheManager.get<T>(key);
|
||||
}
|
||||
|
||||
/** Set value in cache with TTL in seconds */
|
||||
async set(key: string, value: any, ttlSeconds: number) {
|
||||
// cache-manager expects TTL in seconds
|
||||
await this.cacheManager.set(key, value, ttlSeconds * 1000);
|
||||
}
|
||||
|
||||
/** Delete a key from cache */
|
||||
async del(key: string) {
|
||||
await this.cacheManager.del(key);
|
||||
}
|
||||
|
||||
/** Get remaining TTL in seconds */
|
||||
async getTtl(key: string): Promise<number | undefined> {
|
||||
return await this.cacheManager.ttl(key);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { CacheService } from './cache.service';
|
||||
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [],
|
||||
providers: [ ],
|
||||
exports: [],
|
||||
providers: [CacheService],
|
||||
exports: [CacheService],
|
||||
})
|
||||
export class UtilsModule {}
|
||||
export class UtilsModule { }
|
||||
|
||||
Reference in New Issue
Block a user