Update codebase

This commit is contained in:
Hamza-Ayed
2026-07-16 16:01:28 +03:00
parent 951f6d80e1
commit 83f2d0854a
16 changed files with 343 additions and 48 deletions
+77
View File
@@ -0,0 +1,77 @@
import { Injectable, Logger, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { UsersService } from '../users/users.service';
import { User } from '../users/entities/user.entity';
@Injectable()
export class AuthService {
private readonly logger = new Logger('Auth');
constructor(
private usersService: UsersService,
private jwtService: JwtService,
private config: ConfigService,
) {}
private get devCode(): string {
// رمز التطوير الثابت — يُستبدل بمحوّل SMS في P2 (راجع docs/07).
return '1234';
}
async sendOtp(tenantId: string, phone: string) {
// وضع تطوير: الرمز ثابت ويُطبع باللوغ بلا مزوّد SMS.
this.logger.log(`OTP for tenant=${tenantId} phone=${phone} => ${this.devCode} (dev)`);
return {
success: true,
message: 'OTP sent',
dev_code: this.config.get('auth.otpDevMode') ? this.devCode : undefined,
};
}
async verifyOtp(tenantId: string, phone: string, code: string) {
if (code !== this.devCode) {
throw new UnauthorizedException('Invalid OTP code');
}
let user = await this.usersService.findByPhone(tenantId, phone);
if (!user) {
user = await this.usersService.create(tenantId, phone);
}
return this.issueTokens(user, tenantId);
}
async refresh(refreshToken: string) {
let payload: any;
try {
payload = this.jwtService.verify(refreshToken);
} catch {
throw new UnauthorizedException('Invalid refresh token');
}
if (payload.type !== 'refresh') {
throw new UnauthorizedException('Not a refresh token');
}
const user = await this.usersService.findById(payload.tenant_id, payload.sub);
if (!user) throw new UnauthorizedException('User not found');
return this.issueTokens(user, user.tenant_id);
}
/** يصدر access + refresh معاً. */
private issueTokens(user: User, tenantId: string) {
const base = {
sub: user.id,
phone: user.phone,
role: user.role,
tenant_id: tenantId,
};
return {
access_token: this.jwtService.sign(base),
refresh_token: this.jwtService.sign(
{ ...base, type: 'refresh' },
{ expiresIn: this.config.get<string>('jwt.refreshExpires') ?? '30d' },
),
user,
};
}
}