user account create

This commit is contained in:
yaschalew
2026-05-26 05:40:53 +03:00
parent 69db7cd960
commit 5a4d6baec2
24 changed files with 3387 additions and 1817 deletions

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { OtpController } from './otp.controller';
describe('OtpController', () => {
let controller: OtpController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [OtpController],
}).compile();
controller = module.get<OtpController>(OtpController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@@ -0,0 +1,53 @@
// otp.controller.ts
import {
Body,
Controller,
Post,
} from "@nestjs/common";
import { OtpService } from "./otp.service";
import { Public } from "@edr/api-common";
@Controller("otp")
@Public()
export class OtpController {
constructor(
private readonly otpService: OtpService
) {}
// ---------------------------------------------------------------------------
// Send OTP
// ---------------------------------------------------------------------------
@Post("send")
async sendOtp(
@Body("phone")
phone: string,
@Body("otp")
otp: string
) {
return this.otpService.sendOtp(
phone,otp
);
}
// ---------------------------------------------------------------------------
// Verify OTP
// ---------------------------------------------------------------------------
@Post("verify")
async verifyOtp(
@Body("phone")
phone: string,
@Body("otp")
otp: string
) {
return this.otpService.verifyOtp(
phone,
otp
);
}
}

View File

@@ -0,0 +1,25 @@
// otp.entity.ts
import {
Column,
Entity,
} from "typeorm";
import { BaseEntity } from "@edr/api-common";
@Entity({
name: "otp_verifications",
})
export class OtpVerification extends BaseEntity{
@Column({
unique: true,
})
phone!: string;
@Column()
otp!: string;
@Column({
default: false,
})
verified!: boolean;
}

View File

@@ -0,0 +1,33 @@
// otp.module.ts
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { OtpVerification } from "./otp.entity";
import { OtpController } from "./otp.controller";
import { OtpService } from "./otp.service";
import { OtpRepository } from "./otp.repository";
@Module({
imports: [
TypeOrmModule.forFeature([
OtpVerification,
]),
],
controllers: [OtpController],
providers: [
OtpService,
OtpRepository,
],
exports: [
OtpRepository,
],
})
export class OtpModule {}

View File

@@ -0,0 +1,86 @@
// otp.repository.ts
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { OtpVerification } from "./otp.entity";
@Injectable()
export class OtpRepository {
constructor(
@InjectRepository(
OtpVerification
)
private readonly repository: Repository<OtpVerification>
) {}
// ---------------------------------------------------------------------------
// Find By Phone
// ---------------------------------------------------------------------------
async findByPhone(
phone: string
) {
return this.repository.findOne({
where: {
phone,
},
});
}
// ---------------------------------------------------------------------------
// Create OTP
// ---------------------------------------------------------------------------
async createOtp(
phone: string,
otp: string
) {
const entity =
this.repository.create({
phone,
otp,
verified: false,
});
return this.repository.save(
entity
);
}
// ---------------------------------------------------------------------------
// Update OTP
// ---------------------------------------------------------------------------
async updateOtp(
otpVerification: OtpVerification,
otp: string
) {
otpVerification.otp = otp;
otpVerification.verified =
false;
return this.repository.save(
otpVerification
);
}
// ---------------------------------------------------------------------------
// Verify Phone
// ---------------------------------------------------------------------------
async verifyPhone(
otpVerification: OtpVerification
) {
otpVerification.verified =
true;
return this.repository.save(
otpVerification
);
}
}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { OtpService } from './otp.service';
describe('OtpService', () => {
let service: OtpService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [OtpService],
}).compile();
service = module.get<OtpService>(OtpService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,141 @@
// otp.service.ts
import {
BadRequestException,
Injectable,
} from "@nestjs/common";
import axios from "axios";
import { OtpRepository } from "./otp.repository";
@Injectable()
export class OtpService {
constructor(
private readonly otpRepository: OtpRepository
) {}
// ---------------------------------------------------------------------------
// Generate OTP
// ---------------------------------------------------------------------------
generateOtp(): string {
return Math.floor(
100000 + Math.random() * 900000
).toString();
}
// ---------------------------------------------------------------------------
// Send OTP
// ---------------------------------------------------------------------------
async sendOtp(phone: string, otp: string) {
try {
// generate otp
// const otp =
// this.generateOtp();
// find existing phone
const existingPhone =
await this.otpRepository.findByPhone(
phone
);
// update existing otp
if (existingPhone) {
await this.otpRepository.updateOtp(
existingPhone,
otp
);
} else {
// create new otp
await this.otpRepository.createOtp(
phone,
otp
);
}
// send sms
await axios.post(
"https://notification-dev.license.aafda.gov.et/api/sms-services/ozeking/sms",
{
to: phone,
sourceId: "EDR",
sourceName:
"EDR Freight",
appKey:
"YOUR_APP_KEY",
text: `Your verification code is ${otp}`,
callbackUrl: "",
},
{
headers: {
accept: "*/*",
"Content-Type":
"application/json",
},
}
);
return {
success: true,
message:
"OTP sent successfully",
};
} catch (error) {
console.log(error);
throw new BadRequestException(
"Failed to send OTP"
);
}
}
// ---------------------------------------------------------------------------
// Verify OTP
// ---------------------------------------------------------------------------
async verifyOtp(
phone: string,
otp: string
) {
// find phone
const otpData =
await this.otpRepository.findByPhone(
phone
);
// phone not found
if (!otpData) {
throw new BadRequestException(
"Phone number not found"
);
}
// invalid otp
if (otpData.otp !== otp) {
throw new BadRequestException(
"Invalid OTP"
);
}
// verify phone
await this.otpRepository.verifyPhone(
otpData
);
return {
success: true,
message:
"Phone verified successfully",
};
}
}