Initial commit of edr-passenger-api alpha version

This commit is contained in:
Stephanos A
2026-05-13 16:58:49 +03:00
parent 199a3eba11
commit 39ba561d8f
113 changed files with 3602 additions and 1035 deletions

View File

@@ -0,0 +1,18 @@
import { Body, Controller, Post } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
import { AuthService } from './auth.service';
import { RegisterDto, LoginDto } from './auth.dto';
@ApiTags('Auth')
@Controller('auth')
export class AuthController {
constructor(private service: AuthService) {}
@Post('register')
@ApiOperation({ summary: 'Register new user' })
register(@Body() dto: RegisterDto) { return this.service.register(dto); }
@Post('login')
@ApiOperation({ summary: 'Login and get JWT' })
login(@Body() dto: LoginDto) { return this.service.login(dto); }
}

View File

@@ -0,0 +1,14 @@
import { IsEmail, IsString, MinLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class RegisterDto {
@ApiProperty({ example: 'Kelemu Ketsela' }) @IsString() fullName: string;
@ApiProperty({ example: 'kelemu@email.com' }) @IsEmail() email: string;
@ApiProperty({ example: '+251912345678' }) @IsString() phone: string;
@ApiProperty({ example: 'password123', minLength: 8 }) @IsString() @MinLength(8) password: string;
}
export class LoginDto {
@ApiProperty({ example: 'kelemu@email.com' }) @IsEmail() email: string;
@ApiProperty({ example: 'password123' }) @IsString() password: string;
}

View File

@@ -0,0 +1,24 @@
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { ConfigService } from '@nestjs/config';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { JwtStrategy } from '../../common/jwt.strategy';
@Module({
imports: [
PassportModule,
JwtModule.registerAsync({
inject: [ConfigService],
useFactory: (c: ConfigService) => ({
secret: c.get('JWT_SECRET'),
signOptions: { expiresIn: c.get('JWT_EXPIRES_IN', '7d') },
}),
}),
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy],
exports: [JwtModule],
})
export class AuthModule {}

View File

@@ -0,0 +1,42 @@
import { Injectable, UnauthorizedException, ConflictException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { PrismaService } from '../../common/prisma.service';
import { RegisterDto, LoginDto } from './auth.dto';
import * as bcrypt from 'bcrypt';
@Injectable()
export class AuthService {
constructor(private prisma: PrismaService, private jwt: JwtService) {}
async register(dto: RegisterDto) {
const exists = await this.prisma.user.findFirst({
where: { OR: [{ email: dto.email }, { phone: dto.phone }] },
});
if (exists) throw new ConflictException('Email or phone already registered');
const passwordHash = await bcrypt.hash(dto.password, 10);
const user = await this.prisma.user.create({
data: { fullName: dto.fullName, email: dto.email, phone: dto.phone, passwordHash },
});
const passenger = await this.prisma.passenger.create({ data: { userId: user.id } });
await this.prisma.loyaltyAccount.create({ data: { passengerId: passenger.id } });
await this.prisma.walletAccount.create({ data: { passengerId: passenger.id } });
await this.prisma.userPreferences.create({ data: { userId: user.id } });
return this.signToken(user.id, user.email, user.role, passenger.id);
}
async login(dto: LoginDto) {
const user = await this.prisma.user.findUnique({
where: { email: dto.email },
include: { passenger: true },
});
if (!user || !(await bcrypt.compare(dto.password, user.passwordHash))) {
throw new UnauthorizedException('Invalid credentials');
}
return this.signToken(user.id, user.email, user.role, user.passenger?.id);
}
private signToken(userId: string, email: string, role: string, passengerId?: string) {
const token = this.jwt.sign({ sub: userId, email, role, passengerId });
return { token, user: { id: userId, email, role, passengerId } };
}
}