fix(auth): resolve tenant slug to UUID before user queries
This commit is contained in:
@@ -5,11 +5,13 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
|
|||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
import { AuthController } from './auth.controller';
|
import { AuthController } from './auth.controller';
|
||||||
import { UsersModule } from '../users/users.module';
|
import { UsersModule } from '../users/users.module';
|
||||||
|
import { TenantsModule } from '../tenants/tenants.module';
|
||||||
import { JwtStrategy } from './strategies/jwt.strategy';
|
import { JwtStrategy } from './strategies/jwt.strategy';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
UsersModule,
|
UsersModule,
|
||||||
|
TenantsModule,
|
||||||
PassportModule,
|
PassportModule,
|
||||||
JwtModule.registerAsync({
|
JwtModule.registerAsync({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule],
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { JwtService } from '@nestjs/jwt';
|
|||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { UsersService } from '../users/users.service';
|
import { UsersService } from '../users/users.service';
|
||||||
import { User } from '../users/entities/user.entity';
|
import { User } from '../users/entities/user.entity';
|
||||||
|
import { TenantsService } from '../tenants/tenants.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
@@ -12,8 +13,16 @@ export class AuthService {
|
|||||||
private usersService: UsersService,
|
private usersService: UsersService,
|
||||||
private jwtService: JwtService,
|
private jwtService: JwtService,
|
||||||
private config: ConfigService,
|
private config: ConfigService,
|
||||||
|
private tenantsService: TenantsService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
/** يحوّل الـ slug القادم من الهيدر إلى UUID المستأجر (tenant_id). */
|
||||||
|
private async resolveTenantId(tenantSlugOrId: string): Promise<string> {
|
||||||
|
const tenant = await this.tenantsService.resolve(tenantSlugOrId);
|
||||||
|
if (!tenant) throw new UnauthorizedException('Unknown tenant');
|
||||||
|
return tenant.id;
|
||||||
|
}
|
||||||
|
|
||||||
private get devCode(): string {
|
private get devCode(): string {
|
||||||
// رمز التطوير الثابت — يُستبدل بمحوّل SMS في P2 (راجع docs/07).
|
// رمز التطوير الثابت — يُستبدل بمحوّل SMS في P2 (راجع docs/07).
|
||||||
return '1234';
|
return '1234';
|
||||||
@@ -29,11 +38,14 @@ export class AuthService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async verifyOtp(tenantId: string, phone: string, code: string) {
|
async verifyOtp(tenantSlug: string, phone: string, code: string) {
|
||||||
if (code !== this.devCode) {
|
if (code !== this.devCode) {
|
||||||
throw new UnauthorizedException('Invalid OTP code');
|
throw new UnauthorizedException('Invalid OTP code');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// الهيدر يحمل slug — نحوّله لـ UUID قبل أي استعلام على tenant_id.
|
||||||
|
const tenantId = await this.resolveTenantId(tenantSlug);
|
||||||
|
|
||||||
let user = await this.usersService.findByPhone(tenantId, phone);
|
let user = await this.usersService.findByPhone(tenantId, phone);
|
||||||
if (!user) {
|
if (!user) {
|
||||||
user = await this.usersService.create(tenantId, phone);
|
user = await this.usersService.create(tenantId, phone);
|
||||||
|
|||||||
@@ -18,6 +18,23 @@ export class TenantsService {
|
|||||||
return this.repo.findOne({ where: { slug } });
|
return this.repo.findOne({ where: { slug } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly UUID_RE =
|
||||||
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* يحوّل معرّف المستأجر القادم من الهيدر (slug مثل "siro" أو UUID) إلى سجل المستأجر.
|
||||||
|
* التطبيقات ترسل الـ slug؛ نحوّله للـ UUID المستخدَم في tenant_id (راجع docs/06).
|
||||||
|
*/
|
||||||
|
async resolve(idOrSlug: string): Promise<Tenant | null> {
|
||||||
|
if (!idOrSlug) return null;
|
||||||
|
const bySlug = await this.findBySlug(idOrSlug);
|
||||||
|
if (bySlug) return bySlug;
|
||||||
|
if (TenantsService.UUID_RE.test(idOrSlug)) {
|
||||||
|
return this.repo.findOne({ where: { id: idOrSlug } });
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
create(data: Partial<Tenant>): Promise<Tenant> {
|
create(data: Partial<Tenant>): Promise<Tenant> {
|
||||||
return this.repo.save(this.repo.create(data));
|
return this.repo.save(this.repo.create(data));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user