feat: implement billing, usage tracking, and administrative geocoding features in API with infrastructure updates

This commit is contained in:
Hamza-Ayed
2026-07-28 04:43:23 +03:00
parent 2f7c2066f7
commit dc9d546733
133 changed files with 3599 additions and 356 deletions
+17 -2
View File
@@ -8,6 +8,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.AppModule = void 0; exports.AppModule = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
const core_1 = require("@nestjs/core");
const config_1 = require("@nestjs/config"); const config_1 = require("@nestjs/config");
const typeorm_1 = require("@nestjs/typeorm"); const typeorm_1 = require("@nestjs/typeorm");
const schedule_1 = require("@nestjs/schedule"); const schedule_1 = require("@nestjs/schedule");
@@ -16,6 +17,10 @@ const maps_module_1 = require("./maps/maps.module");
const geocoding_module_1 = require("./geocoding/geocoding.module"); const geocoding_module_1 = require("./geocoding/geocoding.module");
const auth_module_1 = require("./auth/auth.module"); const auth_module_1 = require("./auth/auth.module");
const throttler_1 = require("@nestjs/throttler"); const throttler_1 = require("@nestjs/throttler");
const usage_module_1 = require("./usage/usage.module");
const billing_module_1 = require("./billing/billing.module");
const mail_module_1 = require("./common/mail.module");
const usage_interceptor_1 = require("./usage/usage.interceptor");
let AppModule = class AppModule { let AppModule = class AppModule {
}; };
exports.AppModule = AppModule; exports.AppModule = AppModule;
@@ -33,17 +38,27 @@ exports.AppModule = AppModule = __decorate([
type: 'postgres', type: 'postgres',
url: config.get('DATABASE_URL'), url: config.get('DATABASE_URL'),
autoLoadEntities: true, autoLoadEntities: true,
synchronize: true, synchronize: false,
}), }),
}), }),
throttler_1.ThrottlerModule.forRoot([{ throttler_1.ThrottlerModule.forRoot([{
ttl: 60, ttl: 60000,
limit: 10, limit: 10,
}]), }]),
auth_module_1.AuthModule, auth_module_1.AuthModule,
telemetry_module_1.TelemetryModule, telemetry_module_1.TelemetryModule,
maps_module_1.MapsModule, maps_module_1.MapsModule,
geocoding_module_1.GeocodingModule, geocoding_module_1.GeocodingModule,
usage_module_1.UsageModule,
billing_module_1.BillingModule,
mail_module_1.MailModule,
],
controllers: [],
providers: [
{
provide: core_1.APP_INTERCEPTOR,
useClass: usage_interceptor_1.UsageInterceptor,
},
], ],
}) })
], AppModule); ], AppModule);
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2CAA6D;AAC7D,6CAAgD;AAChD,+CAAkD;AAClD,mEAA+D;AAC/D,oDAAgD;AAChD,mEAA+D;AAC/D,oDAAgD;AAChD,iDAAoD;AA4B7C,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IA1BrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,CAAC;gBACnB,QAAQ,EAAE,IAAI;aACf,CAAC;YACF,yBAAc,CAAC,OAAO,EAAE;YACxB,uBAAa,CAAC,YAAY,CAAC;gBACzB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,MAAM,EAAE,CAAC,sBAAa,CAAC;gBACvB,UAAU,EAAE,CAAC,MAAqB,EAAE,EAAE,CAAC,CAAC;oBACtC,IAAI,EAAE,UAAU;oBAChB,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;oBAC/B,gBAAgB,EAAE,IAAI;oBACtB,WAAW,EAAE,IAAI;iBAClB,CAAC;aACH,CAAC;YACF,2BAAe,CAAC,OAAO,CAAC,CAAC;oBACvB,GAAG,EAAE,EAAE;oBACP,KAAK,EAAE,EAAE;iBACV,CAAC,CAAC;YACH,wBAAU;YACV,kCAAe;YACf,wBAAU;YACV,kCAAe;SAChB;KACF,CAAC;GACW,SAAS,CAAG"} {"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,uCAA0D;AAC1D,2CAA6D;AAC7D,6CAAgD;AAChD,+CAAkD;AAClD,mEAA+D;AAC/D,oDAAgD;AAChD,mEAA+D;AAC/D,oDAAgD;AAChD,iDAAoD;AACpD,uDAAmD;AACnD,6DAAyD;AACzD,sDAAkD;AAClD,iEAA6D;AAsCtD,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IApCrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY,CAAC,OAAO,CAAC;gBACnB,QAAQ,EAAE,IAAI;aACf,CAAC;YACF,yBAAc,CAAC,OAAO,EAAE;YACxB,uBAAa,CAAC,YAAY,CAAC;gBACzB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,MAAM,EAAE,CAAC,sBAAa,CAAC;gBACvB,UAAU,EAAE,CAAC,MAAqB,EAAE,EAAE,CAAC,CAAC;oBACtC,IAAI,EAAE,UAAU;oBAChB,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;oBAC/B,gBAAgB,EAAE,IAAI;oBACtB,WAAW,EAAE,KAAK;iBACnB,CAAC;aACH,CAAC;YACF,2BAAe,CAAC,OAAO,CAAC,CAAC;oBACvB,GAAG,EAAE,KAAK;oBACV,KAAK,EAAE,EAAE;iBACV,CAAC,CAAC;YACH,wBAAU;YACV,kCAAe;YACf,wBAAU;YACV,kCAAe;YACf,0BAAW;YACX,8BAAa;YACb,wBAAU;SACX;QACD,WAAW,EAAE,EAAE;QACf,SAAS,EAAE;YACT;gBACE,OAAO,EAAE,sBAAe;gBACxB,QAAQ,EAAE,oCAAgB;aAC3B;SACF;KACF,CAAC;GACW,SAAS,CAAG"}
+8 -4
View File
@@ -8,6 +8,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
var __metadata = (this && this.__metadata) || function (k, v) { var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}; };
var _a;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthModule = void 0; exports.AuthModule = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
@@ -17,6 +18,9 @@ const tenant_entity_1 = require("./entities/tenant.entity");
const api_key_entity_1 = require("./entities/api-key.entity"); const api_key_entity_1 = require("./entities/api-key.entity");
const redis_module_1 = require("../common/redis.module"); const redis_module_1 = require("../common/redis.module");
const config_1 = require("@nestjs/config"); const config_1 = require("@nestjs/config");
const tenant_controller_1 = require("./tenant.controller");
const firebase_admin_service_1 = require("./firebase-admin.service");
const firebase_auth_guard_1 = require("./guards/firebase-auth.guard");
let AuthModule = class AuthModule { let AuthModule = class AuthModule {
authService; authService;
configService; configService;
@@ -40,10 +44,10 @@ exports.AuthModule = AuthModule = __decorate([
typeorm_1.TypeOrmModule.forFeature([tenant_entity_1.Tenant, api_key_entity_1.ApiKey]), typeorm_1.TypeOrmModule.forFeature([tenant_entity_1.Tenant, api_key_entity_1.ApiKey]),
redis_module_1.RedisModule, redis_module_1.RedisModule,
], ],
providers: [auth_service_1.AuthService], controllers: [tenant_controller_1.TenantController],
exports: [auth_service_1.AuthService], providers: [auth_service_1.AuthService, firebase_admin_service_1.FirebaseAdminService, firebase_auth_guard_1.FirebaseAuthGuard],
exports: [auth_service_1.AuthService, firebase_admin_service_1.FirebaseAdminService, firebase_auth_guard_1.FirebaseAuthGuard],
}), }),
__metadata("design:paramtypes", [auth_service_1.AuthService, __metadata("design:paramtypes", [auth_service_1.AuthService, typeof (_a = typeof config_1.ConfigService !== "undefined" && config_1.ConfigService) === "function" ? _a : Object])
config_1.ConfigService])
], AuthModule); ], AuthModule);
//# sourceMappingURL=auth.module.js.map //# sourceMappingURL=auth.module.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA8D;AAC9D,6CAAgD;AAChD,iDAA6C;AAC7C,4DAAkD;AAClD,8DAAmD;AACnD,yDAAqD;AACrD,2CAA+C;AAWxC,IAAM,UAAU,GAAhB,MAAM,UAAU;IAEF;IACA;IAFnB,YACmB,WAAwB,EACxB,aAA4B;QAD5B,gBAAW,GAAX,WAAW,CAAa;QACxB,kBAAa,GAAb,aAAa,CAAe;IAC5C,CAAC;IAMJ,KAAK,CAAC,YAAY;QAChB,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,aAAa,CAAC,CAAC;QACjE,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,gBAAgB,EAAE,mBAAmB,EAAE,UAAU,CAAC,CAAC;YACzF,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;CACF,CAAA;AAjBY,gCAAU;qBAAV,UAAU;IATtB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,uBAAa,CAAC,UAAU,CAAC,CAAC,sBAAM,EAAE,uBAAM,CAAC,CAAC;YAC1C,0BAAW;SACZ;QACD,SAAS,EAAE,CAAC,0BAAW,CAAC;QACxB,OAAO,EAAE,CAAC,0BAAW,CAAC;KACvB,CAAC;qCAGgC,0BAAW;QACT,sBAAa;GAHpC,UAAU,CAiBtB"} {"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAA8D;AAC9D,6CAAgD;AAChD,iDAA6C;AAC7C,4DAAkD;AAClD,8DAAmD;AACnD,yDAAqD;AACrD,2CAA+C;AAC/C,2DAAuD;AACvD,qEAAgE;AAChE,sEAAiE;AAY1D,IAAM,UAAU,GAAhB,MAAM,UAAU;IAEF;IACA;IAFnB,YACmB,WAAwB,EACxB,aAA4B;QAD5B,gBAAW,GAAX,WAAW,CAAa;QACxB,kBAAa,GAAb,aAAa,CAAe;IAC5C,CAAC;IAMJ,KAAK,CAAC,YAAY;QAChB,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,aAAa,CAAC,CAAC;QACjE,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,gBAAgB,EAAE,mBAAmB,EAAE,UAAU,CAAC,CAAC;YACzF,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;CACF,CAAA;AAjBY,gCAAU;qBAAV,UAAU;IAVtB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,uBAAa,CAAC,UAAU,CAAC,CAAC,sBAAM,EAAE,uBAAM,CAAC,CAAC;YAC1C,0BAAW;SACZ;QACD,WAAW,EAAE,CAAC,oCAAgB,CAAC;QAC/B,SAAS,EAAE,CAAC,0BAAW,EAAE,6CAAoB,EAAE,uCAAiB,CAAC;QACjE,OAAO,EAAE,CAAC,0BAAW,EAAE,6CAAoB,EAAE,uCAAiB,CAAC;KAChE,CAAC;qCAGgC,0BAAW,sBACT,sBAAa,oBAAb,sBAAa;GAHpC,UAAU,CAiBtB"}
+4
View File
@@ -17,4 +17,8 @@ export declare class AuthService {
private isDomainAllowed; private isDomainAllowed;
hashSecret(secret: string): string; hashSecret(secret: string): string;
seedDefaultKey(name: string, email: string, keyString: string): Promise<void>; seedDefaultKey(name: string, email: string, keyString: string): Promise<void>;
getApiKeys(tenantId: string): Promise<ApiKey[]>;
createApiKey(tenantId: string, name: string, rateLimit?: number, allowedOrigins?: string[]): Promise<ApiKey>;
getDefaultTenant(): Promise<Tenant>;
findOrCreateByFirebaseUid(uid: string, email: string, name: string, photoUrl?: string): Promise<Tenant>;
} }
+70 -5
View File
@@ -12,6 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); } return function (target, key) { decorator(target, key, paramIndex); }
}; };
var AuthService_1; var AuthService_1;
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthService = void 0; exports.AuthService = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
@@ -49,7 +50,7 @@ let AuthService = AuthService_1 = class AuthService {
const result = { const result = {
tenant: apiKey.tenant, tenant: apiKey.tenant,
apiKey: apiKey, apiKey: apiKey,
rateLimit: apiKey.rateLimit || 100, rateLimit: apiKey.rateLimit || tenant_entity_1.RATE_LIMITS[apiKey.tenant.plan] || 100,
}; };
await this.redisService.set(cacheKey, result, 3600); await this.redisService.set(cacheKey, result, 3600);
this.apiKeyRepository.update(apiKey.id, { lastUsedAt: new Date() }).catch(err => this.logger.error(`Failed to update lastUsedAt for API key ${apiKey.id}: ${err.message}`)); this.apiKeyRepository.update(apiKey.id, { lastUsedAt: new Date() }).catch(err => this.logger.error(`Failed to update lastUsedAt for API key ${apiKey.id}: ${err.message}`));
@@ -87,7 +88,8 @@ let AuthService = AuthService_1 = class AuthService {
tenant = await this.tenantRepository.save({ tenant = await this.tenantRepository.save({
name, name,
email, email,
isActive: true isActive: true,
plan: tenant_entity_1.TenantPlan.ENTERPRISE,
}); });
} }
const existingKey = await this.apiKeyRepository.findOne({ where: { key: keyString } }); const existingKey = await this.apiKeyRepository.findOne({ where: { key: keyString } });
@@ -102,14 +104,77 @@ let AuthService = AuthService_1 = class AuthService {
}); });
} }
} }
async getApiKeys(tenantId) {
return this.apiKeyRepository.find({
where: { tenantId },
order: { createdAt: 'DESC' }
});
}
async createApiKey(tenantId, name, rateLimit, allowedOrigins) {
const existingKeysCount = await this.apiKeyRepository.count({ where: { tenantId } });
if (existingKeysCount >= 1) {
throw new common_1.ConflictException('Limit reached: Only 1 API key allowed per developer currently.');
}
const key = `in_${(0, crypto_1.createHash)('md5').update(Math.random().toString()).digest('hex').substring(0, 24)}`;
const apiKey = this.apiKeyRepository.create({
key,
secretHash: this.hashSecret(key),
name,
tenantId,
rateLimit: rateLimit || 100,
allowedOrigins: allowedOrigins || [],
isActive: true
});
return this.apiKeyRepository.save(apiKey);
}
async getDefaultTenant() {
const tenant = await this.tenantRepository.findOne({ where: {} });
if (!tenant)
throw new common_1.NotFoundException('No tenants found in system');
return tenant;
}
async findOrCreateByFirebaseUid(uid, email, name, photoUrl) {
let tenant = await this.tenantRepository.findOne({ where: { firebaseUid: uid } });
if (!tenant) {
tenant = await this.tenantRepository.findOne({ where: { email } });
if (tenant) {
this.logger.log(`Linking existing tenant ${email} to Firebase UID: ${uid}`);
tenant.firebaseUid = uid;
if (photoUrl)
tenant.photoUrl = photoUrl;
tenant = await this.tenantRepository.save(tenant);
}
else {
this.logger.log(`Creating new tenant for Firebase user: ${email} (${uid})`);
const isAdmin = email === 'hamzaaleghwairyeen@gmail.com' || email === 'hamzadoctor@gmail.com' || email === 'hamzaayedpython@gmail.com';
tenant = await this.tenantRepository.save({
firebaseUid: uid,
email,
name,
photoUrl,
plan: isAdmin ? tenant_entity_1.TenantPlan.ENTERPRISE : tenant_entity_1.TenantPlan.FREE,
isActive: true,
});
}
}
else {
const isAdmin = email === 'hamzaaleghwairyeen@gmail.com' || email === 'hamzadoctor@gmail.com' || email === 'hamzaayedpython@gmail.com';
if (isAdmin && tenant.plan !== tenant_entity_1.TenantPlan.ENTERPRISE) {
tenant.plan = tenant_entity_1.TenantPlan.ENTERPRISE;
await this.tenantRepository.save(tenant);
}
if (tenant.photoUrl !== photoUrl || tenant.name !== name) {
await this.tenantRepository.update(tenant.id, { photoUrl, name });
}
}
return tenant;
}
}; };
exports.AuthService = AuthService; exports.AuthService = AuthService;
exports.AuthService = AuthService = AuthService_1 = __decorate([ exports.AuthService = AuthService = AuthService_1 = __decorate([
(0, common_1.Injectable)(), (0, common_1.Injectable)(),
__param(0, (0, typeorm_1.InjectRepository)(api_key_entity_1.ApiKey)), __param(0, (0, typeorm_1.InjectRepository)(api_key_entity_1.ApiKey)),
__param(1, (0, typeorm_1.InjectRepository)(tenant_entity_1.Tenant)), __param(1, (0, typeorm_1.InjectRepository)(tenant_entity_1.Tenant)),
__metadata("design:paramtypes", [typeorm_2.Repository, __metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object, typeof (_b = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _b : Object, redis_service_1.RedisService])
typeorm_2.Repository,
redis_service_1.RedisService])
], AuthService); ], AuthService);
//# sourceMappingURL=auth.service.js.map //# sourceMappingURL=auth.service.js.map
File diff suppressed because one or more lines are too long
+5
View File
@@ -0,0 +1,5 @@
export declare class CreateKeyDto {
name: string;
rateLimit?: number;
allowedOrigins?: string[];
}
+35
View File
@@ -0,0 +1,35 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CreateKeyDto = void 0;
const class_validator_1 = require("class-validator");
class CreateKeyDto {
name;
rateLimit;
allowedOrigins;
}
exports.CreateKeyDto = CreateKeyDto;
__decorate([
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], CreateKeyDto.prototype, "name", void 0);
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.IsNumber)(),
__metadata("design:type", Number)
], CreateKeyDto.prototype, "rateLimit", void 0);
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.IsArray)(),
(0, class_validator_1.IsString)({ each: true }),
__metadata("design:type", Array)
], CreateKeyDto.prototype, "allowedOrigins", void 0);
//# sourceMappingURL=create-key.dto.js.map
@@ -0,0 +1 @@
{"version":3,"file":"create-key.dto.js","sourceRoot":"","sources":["../../../../src/auth/dto/management/create-key.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAA0E;AAE1E,MAAa,YAAY;IAEvB,IAAI,CAAS;IAIb,SAAS,CAAU;IAKnB,cAAc,CAAY;CAC3B;AAZD,oCAYC;AAVC;IADC,IAAA,0BAAQ,GAAE;;0CACE;AAIb;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;+CACQ;AAKnB;IAHC,IAAA,4BAAU,GAAE;IACZ,IAAA,yBAAO,GAAE;IACT,IAAA,0BAAQ,EAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;;oDACC"}
+11 -1
View File
@@ -1,14 +1,24 @@
import { ApiKey } from './api-key.entity'; import { ApiKey } from './api-key.entity';
export declare enum TenantPlan { export declare enum TenantPlan {
FREE = "FREE", FREE = "FREE",
PREMIUM = "PREMIUM", STARTER = "STARTER",
PRO = "PRO",
ENTERPRISE = "ENTERPRISE" ENTERPRISE = "ENTERPRISE"
} }
export declare enum TenantRole {
USER = "USER",
ADMIN = "ADMIN"
}
export declare const QUOTA_LIMITS: Record<TenantPlan, number>;
export declare const RATE_LIMITS: Record<TenantPlan, number>;
export declare class Tenant { export declare class Tenant {
id: string; id: string;
name: string; name: string;
email: string; email: string;
plan: TenantPlan; plan: TenantPlan;
firebaseUid: string;
role: TenantRole;
photoUrl: string;
isActive: boolean; isActive: boolean;
createdAt: Date; createdAt: Date;
updatedAt: Date; updatedAt: Date;
+39 -2
View File
@@ -9,20 +9,41 @@ var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.Tenant = exports.TenantPlan = void 0; exports.Tenant = exports.RATE_LIMITS = exports.QUOTA_LIMITS = exports.TenantRole = exports.TenantPlan = void 0;
const typeorm_1 = require("typeorm"); const typeorm_1 = require("typeorm");
const api_key_entity_1 = require("./api-key.entity"); const api_key_entity_1 = require("./api-key.entity");
var TenantPlan; var TenantPlan;
(function (TenantPlan) { (function (TenantPlan) {
TenantPlan["FREE"] = "FREE"; TenantPlan["FREE"] = "FREE";
TenantPlan["PREMIUM"] = "PREMIUM"; TenantPlan["STARTER"] = "STARTER";
TenantPlan["PRO"] = "PRO";
TenantPlan["ENTERPRISE"] = "ENTERPRISE"; TenantPlan["ENTERPRISE"] = "ENTERPRISE";
})(TenantPlan || (exports.TenantPlan = TenantPlan = {})); })(TenantPlan || (exports.TenantPlan = TenantPlan = {}));
var TenantRole;
(function (TenantRole) {
TenantRole["USER"] = "USER";
TenantRole["ADMIN"] = "ADMIN";
})(TenantRole || (exports.TenantRole = TenantRole = {}));
exports.QUOTA_LIMITS = {
[TenantPlan.FREE]: 8000,
[TenantPlan.STARTER]: 25000,
[TenantPlan.PRO]: 100000,
[TenantPlan.ENTERPRISE]: 500000,
};
exports.RATE_LIMITS = {
[TenantPlan.FREE]: 5,
[TenantPlan.STARTER]: 100,
[TenantPlan.PRO]: 500,
[TenantPlan.ENTERPRISE]: 50000,
};
let Tenant = class Tenant { let Tenant = class Tenant {
id; id;
name; name;
email; email;
plan; plan;
firebaseUid;
role;
photoUrl;
isActive; isActive;
createdAt; createdAt;
updatedAt; updatedAt;
@@ -49,6 +70,22 @@ __decorate([
}), }),
__metadata("design:type", String) __metadata("design:type", String)
], Tenant.prototype, "plan", void 0); ], Tenant.prototype, "plan", void 0);
__decorate([
(0, typeorm_1.Column)({ nullable: true, unique: true }),
__metadata("design:type", String)
], Tenant.prototype, "firebaseUid", void 0);
__decorate([
(0, typeorm_1.Column)({
type: 'enum',
enum: TenantRole,
default: TenantRole.USER,
}),
__metadata("design:type", String)
], Tenant.prototype, "role", void 0);
__decorate([
(0, typeorm_1.Column)({ nullable: true }),
__metadata("design:type", String)
], Tenant.prototype, "photoUrl", void 0);
__decorate([ __decorate([
(0, typeorm_1.Column)({ default: true }), (0, typeorm_1.Column)({ default: true }),
__metadata("design:type", Boolean) __metadata("design:type", Boolean)
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"tenant.entity.js","sourceRoot":"","sources":["../../../src/auth/entities/tenant.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAAgH;AAChH,qDAA0C;AAE1C,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,2BAAa,CAAA;IACb,iCAAmB,CAAA;IACnB,uCAAyB,CAAA;AAC3B,CAAC,EAJW,UAAU,0BAAV,UAAU,QAIrB;AAGM,IAAM,MAAM,GAAZ,MAAM,MAAM;IAEjB,EAAE,CAAS;IAGX,IAAI,CAAS;IAGb,KAAK,CAAS;IAOd,IAAI,CAAa;IAGjB,QAAQ,CAAU;IAGlB,SAAS,CAAO;IAGhB,SAAS,CAAO;IAGhB,OAAO,CAAW;CACnB,CAAA;AA5BY,wBAAM;AAEjB;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;kCACpB;AAGX;IADC,IAAA,gBAAM,GAAE;;oCACI;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;;qCACX;AAOd;IALC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,UAAU,CAAC,IAAI;KACzB,CAAC;;oCACe;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;;wCACR;AAGlB;IADC,IAAA,0BAAgB,GAAE;8BACR,IAAI;yCAAC;AAGhB;IADC,IAAA,0BAAgB,GAAE;8BACR,IAAI;yCAAC;AAGhB;IADC,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,uBAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;;uCACjC;iBA3BP,MAAM;IADlB,IAAA,gBAAM,EAAC,SAAS,CAAC;GACL,MAAM,CA4BlB"} {"version":3,"file":"tenant.entity.js","sourceRoot":"","sources":["../../../src/auth/entities/tenant.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAAgH;AAChH,qDAA0C;AAE1C,IAAY,UAKX;AALD,WAAY,UAAU;IACpB,2BAAa,CAAA;IACb,iCAAmB,CAAA;IACnB,yBAAW,CAAA;IACX,uCAAyB,CAAA;AAC3B,CAAC,EALW,UAAU,0BAAV,UAAU,QAKrB;AAED,IAAY,UAGX;AAHD,WAAY,UAAU;IACpB,2BAAa,CAAA;IACb,6BAAe,CAAA;AACjB,CAAC,EAHW,UAAU,0BAAV,UAAU,QAGrB;AAEY,QAAA,YAAY,GAA+B;IACtD,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI;IACvB,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,KAAK;IAC3B,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM;IACxB,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM;CAChC,CAAC;AAEW,QAAA,WAAW,GAA+B;IACrD,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;IACpB,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG;IACzB,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG;IACrB,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,KAAK;CAC/B,CAAC;AAGK,IAAM,MAAM,GAAZ,MAAM,MAAM;IAEjB,EAAE,CAAS;IAGX,IAAI,CAAS;IAGb,KAAK,CAAS;IAOd,IAAI,CAAa;IAGjB,WAAW,CAAS;IAOpB,IAAI,CAAa;IAGjB,QAAQ,CAAS;IAGjB,QAAQ,CAAU;IAGlB,SAAS,CAAO;IAGhB,SAAS,CAAO;IAGhB,OAAO,CAAW;CACnB,CAAA;AAzCY,wBAAM;AAEjB;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;kCACpB;AAGX;IADC,IAAA,gBAAM,GAAE;;oCACI;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;;qCACX;AAOd;IALC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,UAAU,CAAC,IAAI;KACzB,CAAC;;oCACe;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;;2CACrB;AAOpB;IALC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,UAAU,CAAC,IAAI;KACzB,CAAC;;oCACe;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;wCACV;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;;wCACR;AAGlB;IADC,IAAA,0BAAgB,GAAE;8BACR,IAAI;yCAAC;AAGhB;IADC,IAAA,0BAAgB,GAAE;8BACR,IAAI;yCAAC;AAGhB;IADC,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,uBAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;;uCACjC;iBAxCP,MAAM;IADlB,IAAA,gBAAM,EAAC,SAAS,CAAC;GACL,MAAM,CAyClB"}
+11
View File
@@ -0,0 +1,11 @@
import { OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as admin from 'firebase-admin';
export declare class FirebaseAdminService implements OnModuleInit {
private configService;
private readonly logger;
private firebaseApp;
constructor(configService: ConfigService);
onModuleInit(): void;
verifyIdToken(token: string): Promise<admin.auth.DecodedIdToken>;
}
+99
View File
@@ -0,0 +1,99 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var FirebaseAdminService_1;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FirebaseAdminService = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const admin = __importStar(require("firebase-admin"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
let FirebaseAdminService = FirebaseAdminService_1 = class FirebaseAdminService {
configService;
logger = new common_1.Logger(FirebaseAdminService_1.name);
firebaseApp;
constructor(configService) {
this.configService = configService;
}
onModuleInit() {
const keyPath = this.configService.get('FIREBASE_SERVICE_ACCOUNT_PATH');
if (!keyPath) {
this.logger.error('FIREBASE_SERVICE_ACCOUNT_PATH is not defined in environment variables');
return;
}
try {
const absolutePath = path.isAbsolute(keyPath)
? keyPath
: path.resolve(process.cwd(), keyPath);
if (!fs.existsSync(absolutePath)) {
this.logger.error(`Firebase service account key not found at: ${absolutePath}`);
return;
}
const serviceAccount = JSON.parse(fs.readFileSync(absolutePath, 'utf8'));
this.firebaseApp = admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
});
this.logger.log('✅ Firebase Admin SDK initialized successfully');
}
catch (error) {
this.logger.error(`Failed to initialize Firebase Admin SDK: ${error.message}`);
}
}
async verifyIdToken(token) {
try {
return await admin.auth().verifyIdToken(token);
}
catch (error) {
this.logger.error(`Token verification failed: ${error.message}`);
throw error;
}
}
};
exports.FirebaseAdminService = FirebaseAdminService;
exports.FirebaseAdminService = FirebaseAdminService = FirebaseAdminService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [typeof (_a = typeof config_1.ConfigService !== "undefined" && config_1.ConfigService) === "function" ? _a : Object])
], FirebaseAdminService);
//# sourceMappingURL=firebase-admin.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"firebase-admin.service.js","sourceRoot":"","sources":["../../src/auth/firebase-admin.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAkE;AAClE,2CAA+C;AAC/C,sDAAwC;AACxC,uCAAyB;AACzB,2CAA6B;AAGtB,IAAM,oBAAoB,4BAA1B,MAAM,oBAAoB;IAIX;IAHH,MAAM,GAAG,IAAI,eAAM,CAAC,sBAAoB,CAAC,IAAI,CAAC,CAAC;IACxD,WAAW,CAAgB;IAEnC,YAAoB,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAEpD,YAAY;QACV,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,+BAA+B,CAAC,CAAC;QAEhF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;YAC3F,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YAEH,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAC3C,CAAC,CAAC,OAAO;gBACT,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;YAEzC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;gBACjC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8CAA8C,YAAY,EAAE,CAAC,CAAC;gBAChF,OAAO;YACT,CAAC;YAED,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;YAEzE,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,aAAa,CAAC;gBACrC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC;aAClD,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,KAAa;QAC/B,IAAI,CAAC;YACH,OAAO,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACjE,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF,CAAA;AA7CY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;yDAKwB,sBAAa,oBAAb,sBAAa;GAJrC,oBAAoB,CA6ChC"}
+10
View File
@@ -0,0 +1,10 @@
import { CanActivate, ExecutionContext } from '@nestjs/common';
import { FirebaseAdminService } from '../firebase-admin.service';
import { AuthService } from '../auth.service';
export declare class FirebaseAuthGuard implements CanActivate {
private firebaseAdminService;
private authService;
private readonly logger;
constructor(firebaseAdminService: FirebaseAdminService, authService: AuthService);
canActivate(context: ExecutionContext): Promise<boolean>;
}
+54
View File
@@ -0,0 +1,54 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var FirebaseAuthGuard_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FirebaseAuthGuard = void 0;
const common_1 = require("@nestjs/common");
const firebase_admin_service_1 = require("../firebase-admin.service");
const auth_service_1 = require("../auth.service");
let FirebaseAuthGuard = FirebaseAuthGuard_1 = class FirebaseAuthGuard {
firebaseAdminService;
authService;
logger = new common_1.Logger(FirebaseAuthGuard_1.name);
constructor(firebaseAdminService, authService) {
this.firebaseAdminService = firebaseAdminService;
this.authService = authService;
}
async canActivate(context) {
const request = context.switchToHttp().getRequest();
const authHeader = request.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
throw new common_1.UnauthorizedException('Missing or invalid Authorization header');
}
const token = authHeader.split('Bearer ')[1];
try {
const decodedToken = await this.firebaseAdminService.verifyIdToken(token);
const tenant = await this.authService.findOrCreateByFirebaseUid(decodedToken.uid, decodedToken.email || '', decodedToken.name || decodedToken.email?.split('@')[0] || 'Unknown User', decodedToken.picture);
if (!tenant.isActive) {
throw new common_1.UnauthorizedException('Tenant account is disabled');
}
request['tenant'] = tenant;
request['user'] = decodedToken;
return true;
}
catch (error) {
this.logger.error(`Firebase Auth failed: ${error.message}`);
throw new common_1.UnauthorizedException(error.message || 'Authentication failed');
}
}
};
exports.FirebaseAuthGuard = FirebaseAuthGuard;
exports.FirebaseAuthGuard = FirebaseAuthGuard = FirebaseAuthGuard_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [firebase_admin_service_1.FirebaseAdminService,
auth_service_1.AuthService])
], FirebaseAuthGuard);
//# sourceMappingURL=firebase-auth.guard.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"firebase-auth.guard.js","sourceRoot":"","sources":["../../../src/auth/guards/firebase-auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAMwB;AACxB,sEAAiE;AACjE,kDAA8C;AAGvC,IAAM,iBAAiB,yBAAvB,MAAM,iBAAiB;IAIlB;IACA;IAJO,MAAM,GAAG,IAAI,eAAM,CAAC,mBAAiB,CAAC,IAAI,CAAC,CAAC;IAE7D,YACU,oBAA0C,EAC1C,WAAwB;QADxB,yBAAoB,GAApB,oBAAoB,CAAsB;QAC1C,gBAAW,GAAX,WAAW,CAAa;IAC/B,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QACpD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QAEjD,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,8BAAqB,CAAC,yCAAyC,CAAC,CAAC;QAC7E,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7C,IAAI,CAAC;YAEH,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAG1E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,yBAAyB,CAC7D,YAAY,CAAC,GAAG,EAChB,YAAY,CAAC,KAAK,IAAI,EAAE,EACxB,YAAY,CAAC,IAAI,IAAI,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,cAAc,EACxE,YAAY,CAAC,OAAO,CACrB,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACrB,MAAM,IAAI,8BAAqB,CAAC,4BAA4B,CAAC,CAAC;YAChE,CAAC;YAGD,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC;YAC3B,OAAO,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC;YAE/B,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5D,MAAM,IAAI,8BAAqB,CAAC,KAAK,CAAC,OAAO,IAAI,uBAAuB,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;CACF,CAAA;AA5CY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;qCAKqB,6CAAoB;QAC7B,0BAAW;GALvB,iBAAiB,CA4C7B"}
+9
View File
@@ -0,0 +1,9 @@
import { AuthService } from './auth.service';
import { CreateKeyDto } from './dto/management/create-key.dto';
export declare class TenantController {
private readonly authService;
constructor(authService: AuthService);
createKey(req: any, dto: CreateKeyDto): Promise<import("./entities/api-key.entity").ApiKey>;
getKeys(req: any): Promise<import("./entities/api-key.entity").ApiKey[]>;
getMe(req: any): Promise<any>;
}
+74
View File
@@ -0,0 +1,74 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TenantController = void 0;
const common_1 = require("@nestjs/common");
const auth_service_1 = require("./auth.service");
const create_key_dto_1 = require("./dto/management/create-key.dto");
const swagger_1 = require("@nestjs/swagger");
const firebase_auth_guard_1 = require("./guards/firebase-auth.guard");
let TenantController = class TenantController {
authService;
constructor(authService) {
this.authService = authService;
}
async createKey(req, dto) {
if (req.user && req.user.email_verified === false) {
throw new common_1.ForbiddenException('You must verify your email address before creating an API key.');
}
const tenantId = req.tenant.id;
return this.authService.createApiKey(tenantId, dto.name, dto.rateLimit, dto.allowedOrigins);
}
async getKeys(req) {
const tenantId = req.tenant.id;
return this.authService.getApiKeys(tenantId);
}
async getMe(req) {
return req.tenant;
}
};
exports.TenantController = TenantController;
__decorate([
(0, common_1.Post)('keys'),
(0, swagger_1.ApiOperation)({ summary: 'Create a new API key' }),
__param(0, (0, common_1.Req)()),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, create_key_dto_1.CreateKeyDto]),
__metadata("design:returntype", Promise)
], TenantController.prototype, "createKey", null);
__decorate([
(0, common_1.Get)('keys'),
(0, swagger_1.ApiOperation)({ summary: 'Get all API keys for the authenticated tenant' }),
__param(0, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], TenantController.prototype, "getKeys", null);
__decorate([
(0, common_1.Get)('me'),
(0, swagger_1.ApiOperation)({ summary: 'Get current authenticated tenant info' }),
__param(0, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], TenantController.prototype, "getMe", null);
exports.TenantController = TenantController = __decorate([
(0, swagger_1.ApiTags)('auth'),
(0, swagger_1.ApiBearerAuth)(),
(0, common_1.UseGuards)(firebase_auth_guard_1.FirebaseAuthGuard),
(0, common_1.Controller)('auth/management'),
__metadata("design:paramtypes", [auth_service_1.AuthService])
], TenantController);
//# sourceMappingURL=tenant.controller.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"tenant.controller.js","sourceRoot":"","sources":["../../src/auth/tenant.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAwG;AACxG,iDAA6C;AAC7C,oEAA+D;AAC/D,6CAAuE;AACvE,sEAAiE;AAM1D,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IACE;IAA7B,YAA6B,WAAwB;QAAxB,gBAAW,GAAX,WAAW,CAAa;IAAG,CAAC;IAInD,AAAN,KAAK,CAAC,SAAS,CACN,GAAQ,EACP,GAAiB;QAEzB,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;YAClD,MAAM,IAAI,2BAAkB,CAAC,gEAAgE,CAAC,CAAC;QACjG,CAAC;QAED,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,CAClC,QAAQ,EACR,GAAG,CAAC,IAAI,EACR,GAAG,CAAC,SAAS,EACb,GAAG,CAAC,cAAc,CACnB,CAAC;IACJ,CAAC;IAIK,AAAN,KAAK,CAAC,OAAO,CAAQ,GAAQ;QAC3B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAIK,AAAN,KAAK,CAAC,KAAK,CAAQ,GAAQ;QACzB,OAAO,GAAG,CAAC,MAAM,CAAC;IACpB,CAAC;CACF,CAAA;AAlCY,4CAAgB;AAKrB;IAFL,IAAA,aAAI,EAAC,MAAM,CAAC;IACZ,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAE/C,WAAA,IAAA,YAAG,GAAE,CAAA;IACL,WAAA,IAAA,aAAI,GAAE,CAAA;;6CAAM,6BAAY;;iDAa1B;AAIK;IAFL,IAAA,YAAG,EAAC,MAAM,CAAC;IACX,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,+CAA+C,EAAE,CAAC;IAC5D,WAAA,IAAA,YAAG,GAAE,CAAA;;;;+CAGnB;AAIK;IAFL,IAAA,YAAG,EAAC,IAAI,CAAC;IACT,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,uCAAuC,EAAE,CAAC;IACtD,WAAA,IAAA,YAAG,GAAE,CAAA;;;;6CAEjB;2BAjCU,gBAAgB;IAJ5B,IAAA,iBAAO,EAAC,MAAM,CAAC;IACf,IAAA,uBAAa,GAAE;IACf,IAAA,kBAAS,EAAC,uCAAiB,CAAC;IAC5B,IAAA,mBAAU,EAAC,iBAAiB,CAAC;qCAEc,0BAAW;GAD1C,gBAAgB,CAkC5B"}
+36
View File
@@ -0,0 +1,36 @@
import { BillingService } from './billing.service';
import { PayMobProvider } from './providers/paymob.provider';
import { BinanceProvider } from './providers/binance.provider';
import { PaymentProvider } from './entities/transaction.entity';
export declare class BillingController {
private billingService;
private paymobProvider;
private binanceProvider;
private readonly logger;
constructor(billingService: BillingService, paymobProvider: PayMobProvider, binanceProvider: BinanceProvider);
getSubscription(req: any): Promise<import("./entities/subscription.entity").Subscription>;
checkout(req: any, body: {
plan: string;
provider: PaymentProvider;
}): Promise<{
checkoutUrl: any;
orderId: string;
prepayId: any;
} | {
checkoutUrl: string;
orderId: string;
}>;
handlePaymobCallback(query: any, req: any): Promise<string>;
handlePaymobWebhook(body: any, hmac: string): Promise<{
status: string;
message: string;
} | {
status: string;
message?: undefined;
}>;
handleBinanceWebhook(body: any, req: any): Promise<{
returnCode: string;
returnMessage: any;
}>;
getInvoices(req: any): Promise<import("./entities/transaction.entity").Transaction[]>;
}
+259
View File
@@ -0,0 +1,259 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var BillingController_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BillingController = void 0;
const common_1 = require("@nestjs/common");
const billing_service_1 = require("./billing.service");
const paymob_provider_1 = require("./providers/paymob.provider");
const binance_provider_1 = require("./providers/binance.provider");
const firebase_auth_guard_1 = require("../auth/guards/firebase-auth.guard");
const swagger_1 = require("@nestjs/swagger");
const transaction_entity_1 = require("./entities/transaction.entity");
let BillingController = BillingController_1 = class BillingController {
billingService;
paymobProvider;
binanceProvider;
logger = new common_1.Logger(BillingController_1.name);
constructor(billingService, paymobProvider, binanceProvider) {
this.billingService = billingService;
this.paymobProvider = paymobProvider;
this.binanceProvider = binanceProvider;
}
async getSubscription(req) {
return this.billingService.getSubscription(req.tenant.id);
}
async checkout(req, body) {
const tenantId = req.tenant.id;
const plan = body.plan;
const pricing = {
'STARTER': 29,
'PRO': 89,
};
const amount = pricing[plan] || 0;
if (amount === 0 && plan !== 'FREE') {
throw new common_1.BadRequestException('Invalid plan or price not configured');
}
if (body.provider === transaction_entity_1.PaymentProvider.PAYMOB) {
const { paymentKey, orderId } = await this.paymobProvider.createPaymentKey(tenantId, amount, plan);
const iframeId = this.billingService.getIframeId();
const checkoutUrl = `https://accept.paymob.com/api/acceptance/iframes/${iframeId}?payment_token=${paymentKey}`;
return { checkoutUrl, orderId };
}
if (body.provider === transaction_entity_1.PaymentProvider.BINANCE) {
return this.binanceProvider.createOrder(tenantId, amount, plan);
}
throw new common_1.BadRequestException('Invalid payment provider');
}
async handlePaymobCallback(query, req) {
this.logger.log(`🔄 PayMob Redirect Callback: ID ${query.id}, Success: ${query.success}`);
if (query.success === 'true' && query.id) {
try {
const txDetails = await this.paymobProvider.getTransactionDetails(query.id);
if (txDetails && txDetails.success === true) {
const extraDesc = txDetails.order?.shipping_data?.extra_description || "";
const [tenantId, plan] = extraDesc.split('|');
if (tenantId) {
await this.billingService.processSuccessfulPayment(query.id.toString(), transaction_entity_1.PaymentProvider.PAYMOB, txDetails.amount_cents / 100, { tenantId, plan: plan || 'PRO' });
this.logger.log(`🚀 Immediate Activation triggered via Callback for Tenant ${tenantId}`);
}
}
}
catch (e) {
this.logger.error(`Failed during immediate activation fallback: ${e.message}`);
}
}
const targetUrl = `https://map-dashboard.intaleqapp.com/dashboard.html#billing?payment_status=${query.success === 'true' ? 'success' : 'failed'}&id=${query.id}`;
return `
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<title>Intaleq Maps | تمت العملية بنجاح</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;700;900&display=swap" rel="stylesheet">
<style>
body { font-family: 'Cairo', sans-serif; background: #050505; color: white; overflow: hidden; }
.pulse { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .7; transform: scale(0.95); } }
</style>
</head>
<body class="flex items-center justify-center h-screen">
<div class="text-center space-y-8 max-w-md p-10 bg-white shadow-2xl rounded-[3rem] border border-white/10 relative overflow-hidden">
<!-- Animated Background Glow -->
<div class="absolute -top-20 -left-20 w-40 h-40 bg-blue-600/20 blur-[80px] rounded-full"></div>
<div class="absolute -bottom-20 -right-20 w-40 h-40 bg-emerald-600/20 blur-[80px] rounded-full"></div>
<div class="relative z-10">
<div class="w-24 h-24 bg-emerald-500 rounded-full mx-auto flex items-center justify-center shadow-[0_0_50px_rgba(16,185,129,0.4)] pulse mb-8">
<svg class="w-12 h-12 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path>
</svg>
</div>
<h1 class="text-3xl font-black text-slate-900 mb-4">شكراً لك، حمزة!</h1>
<p class="text-slate-500 font-bold mb-8">تم تفعيل خطة <span class="text-blue-600">PRO</span> بنجاح. يتم الآن توجيهك إلى لوحة التحكم...</p>
<div class="flex items-center justify-center gap-2">
<div class="w-2 h-2 bg-blue-600 rounded-full animate-bounce"></div>
<div class="w-2 h-2 bg-blue-600 rounded-full animate-bounce [animation-delay:-0.15s]"></div>
<div class="w-2 h-2 bg-blue-600 rounded-full animate-bounce [animation-delay:-0.3s]"></div>
</div>
</div>
<script>
setTimeout(() => {
window.location.href = "${targetUrl}";
}, 2500);
</script>
</div>
</body>
</html>
`;
}
async handlePaymobWebhook(body, hmac) {
this.logger.log(`📥 PayMob Webhook Received: Transaction ID ${body.obj?.id}`);
if (!this.paymobProvider.verifyHmac(body.obj, hmac)) {
this.logger.error('❌ PayMob HMAC Verification Failed');
throw new common_1.BadRequestException('Invalid signature');
}
if (body.obj.success === true) {
const extraDesc = body.obj.order?.shipping_data?.extra_description || "";
const [tenantId, plan] = extraDesc.split('|');
if (!tenantId) {
this.logger.error(`❌ PayMob Webhook failed: No tenantId in metadata. Raw: ${extraDesc}`);
return { status: 'error', message: 'No tenantId found' };
}
await this.billingService.processSuccessfulPayment(body.obj.id.toString(), transaction_entity_1.PaymentProvider.PAYMOB, body.obj.amount_cents / 100, {
tenantId,
plan: plan || 'PRO'
});
}
return { status: 'success' };
}
async handleBinanceWebhook(body, req) {
const timestamp = req.headers['binancepay-timestamp'];
const nonce = req.headers['binancepay-nonce'];
const signature = req.headers['binancepay-signature'];
this.logger.log(`📥 Binance Webhook Received: Transaction ID ${body.bizId || 'UNKNOWN'}`);
if (!timestamp || !nonce || !signature) {
this.logger.error('❌ Binance Webhook: Missing required headers');
throw new common_1.BadRequestException('Missing headers');
}
if (!this.binanceProvider.verifySignature(timestamp, nonce, signature, body)) {
this.logger.error('❌ Binance Signature Verification Failed');
throw new common_1.BadRequestException('Invalid signature');
}
if (body.bizStatus === 'PAY_SUCCESS') {
try {
let dataObj = {};
if (body.data) {
dataObj = JSON.parse(body.data);
}
let tenantId = '';
let plan = 'PRO';
if (dataObj.passThroughInfo) {
const passThrough = JSON.parse(dataObj.passThroughInfo);
tenantId = passThrough.tenantId;
plan = passThrough.plan;
}
if (!tenantId) {
this.logger.error(`❌ Binance Webhook failed: No tenantId found. Body: ${JSON.stringify(body)}`);
return { returnCode: 'FAIL', returnMessage: 'No tenantId found' };
}
const externalTxId = dataObj.merchantTradeNo || body.bizId?.toString();
await this.billingService.processSuccessfulPayment(externalTxId, transaction_entity_1.PaymentProvider.BINANCE, 0, { tenantId, plan });
this.logger.log(`✅ Binance Payment Processed Successfully for Tenant ${tenantId}`);
}
catch (err) {
this.logger.error(`❌ Failed to process Binance payment: ${err.message}`);
return { returnCode: 'FAIL', returnMessage: err.message };
}
}
return {
returnCode: 'SUCCESS',
returnMessage: null,
};
}
async getInvoices(req) {
return this.billingService.getTransactionHistory(req.tenant.id);
}
};
exports.BillingController = BillingController;
__decorate([
(0, swagger_1.ApiBearerAuth)(),
(0, common_1.UseGuards)(firebase_auth_guard_1.FirebaseAuthGuard),
(0, common_1.Get)('subscription'),
(0, swagger_1.ApiOperation)({ summary: 'Get current subscription details' }),
__param(0, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], BillingController.prototype, "getSubscription", null);
__decorate([
(0, swagger_1.ApiBearerAuth)(),
(0, common_1.UseGuards)(firebase_auth_guard_1.FirebaseAuthGuard),
(0, common_1.Post)('checkout'),
(0, swagger_1.ApiOperation)({ summary: 'Initialize a checkout session' }),
__param(0, (0, common_1.Req)()),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], BillingController.prototype, "checkout", null);
__decorate([
(0, common_1.Get)('callback/paymob'),
(0, swagger_1.ApiOperation)({ summary: 'PayMob Redirection Handler' }),
__param(0, (0, common_1.Query)()),
__param(1, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], BillingController.prototype, "handlePaymobCallback", null);
__decorate([
(0, common_1.Post)('webhooks/paymob'),
(0, swagger_1.ApiOperation)({ summary: 'PayMob Payment Webhook' }),
__param(0, (0, common_1.Body)()),
__param(1, (0, common_1.Query)('hmac')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, String]),
__metadata("design:returntype", Promise)
], BillingController.prototype, "handlePaymobWebhook", null);
__decorate([
(0, common_1.Post)('webhooks/binance'),
(0, swagger_1.ApiOperation)({ summary: 'Binance Payment Webhook' }),
__param(0, (0, common_1.Body)()),
__param(1, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], BillingController.prototype, "handleBinanceWebhook", null);
__decorate([
(0, swagger_1.ApiBearerAuth)(),
(0, common_1.UseGuards)(firebase_auth_guard_1.FirebaseAuthGuard),
(0, common_1.Get)('invoices'),
(0, swagger_1.ApiOperation)({ summary: 'Get payment history' }),
__param(0, (0, common_1.Req)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], BillingController.prototype, "getInvoices", null);
exports.BillingController = BillingController = BillingController_1 = __decorate([
(0, swagger_1.ApiTags)('billing'),
(0, common_1.Controller)('billing'),
__metadata("design:paramtypes", [billing_service_1.BillingService,
paymob_provider_1.PayMobProvider,
binance_provider_1.BinanceProvider])
], BillingController);
//# sourceMappingURL=billing.controller.js.map
File diff suppressed because one or more lines are too long
+2
View File
@@ -0,0 +1,2 @@
export declare class BillingModule {
}
+32
View File
@@ -0,0 +1,32 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BillingModule = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const subscription_entity_1 = require("./entities/subscription.entity");
const transaction_entity_1 = require("./entities/transaction.entity");
const billing_service_1 = require("./billing.service");
const billing_controller_1 = require("./billing.controller");
const paymob_provider_1 = require("./providers/paymob.provider");
const binance_provider_1 = require("./providers/binance.provider");
const tenant_entity_1 = require("../auth/entities/tenant.entity");
let BillingModule = class BillingModule {
};
exports.BillingModule = BillingModule;
exports.BillingModule = BillingModule = __decorate([
(0, common_1.Module)({
imports: [
typeorm_1.TypeOrmModule.forFeature([subscription_entity_1.Subscription, transaction_entity_1.Transaction, tenant_entity_1.Tenant]),
],
providers: [billing_service_1.BillingService, paymob_provider_1.PayMobProvider, binance_provider_1.BinanceProvider],
controllers: [billing_controller_1.BillingController],
exports: [billing_service_1.BillingService],
})
], BillingModule);
//# sourceMappingURL=billing.module.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"billing.module.js","sourceRoot":"","sources":["../../src/billing/billing.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,6CAAgD;AAChD,wEAA8D;AAC9D,sEAA4D;AAC5D,uDAAmD;AACnD,6DAAyD;AACzD,iEAA6D;AAC7D,mEAA+D;AAC/D,kEAAwD;AAUjD,IAAM,aAAa,GAAnB,MAAM,aAAa;CAAG,CAAA;AAAhB,sCAAa;wBAAb,aAAa;IARzB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,uBAAa,CAAC,UAAU,CAAC,CAAC,kCAAY,EAAE,gCAAW,EAAE,sBAAM,CAAC,CAAC;SAC9D;QACD,SAAS,EAAE,CAAC,gCAAc,EAAE,gCAAc,EAAE,kCAAe,CAAC;QAC5D,WAAW,EAAE,CAAC,sCAAiB,CAAC;QAChC,OAAO,EAAE,CAAC,gCAAc,CAAC;KAC1B,CAAC;GACW,aAAa,CAAG"}
+20
View File
@@ -0,0 +1,20 @@
import { ConfigService } from '@nestjs/config';
import { Repository } from 'typeorm';
import { Subscription } from './entities/subscription.entity';
import { Transaction, PaymentProvider } from './entities/transaction.entity';
import { Tenant } from '../auth/entities/tenant.entity';
import { MailService } from '../common/mail.service';
export declare class BillingService {
private subscriptionRepository;
private transactionRepository;
private tenantRepository;
private configService;
private mailService;
private readonly logger;
constructor(subscriptionRepository: Repository<Subscription>, transactionRepository: Repository<Transaction>, tenantRepository: Repository<Tenant>, configService: ConfigService, mailService: MailService);
getIframeId(): string;
getSubscription(tenantId: string): Promise<Subscription>;
processSuccessfulPayment(externalTxId: string, provider: PaymentProvider, amount: number, metadata: any): Promise<void>;
private upgradeTenantPlan;
getTransactionHistory(tenantId: string): Promise<Transaction[]>;
}
+131
View File
@@ -0,0 +1,131 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var BillingService_1;
var _a, _b, _c, _d;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BillingService = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const subscription_entity_1 = require("./entities/subscription.entity");
const transaction_entity_1 = require("./entities/transaction.entity");
const tenant_entity_1 = require("../auth/entities/tenant.entity");
const mail_service_1 = require("../common/mail.service");
let BillingService = BillingService_1 = class BillingService {
subscriptionRepository;
transactionRepository;
tenantRepository;
configService;
mailService;
logger = new common_1.Logger(BillingService_1.name);
constructor(subscriptionRepository, transactionRepository, tenantRepository, configService, mailService) {
this.subscriptionRepository = subscriptionRepository;
this.transactionRepository = transactionRepository;
this.tenantRepository = tenantRepository;
this.configService = configService;
this.mailService = mailService;
}
getIframeId() {
return this.configService.get('PAYMOB_IFRAME_ID', '837992');
}
async getSubscription(tenantId) {
let sub = await this.subscriptionRepository.findOne({ where: { tenantId } });
if (!sub) {
sub = await this.subscriptionRepository.save({
tenantId,
plan: 'FREE',
monthlyRequestLimit: 5000,
status: subscription_entity_1.SubscriptionStatus.ACTIVE,
});
}
return sub;
}
async processSuccessfulPayment(externalTxId, provider, amount, metadata) {
let txn = await this.transactionRepository.findOne({ where: { externalTransactionId: externalTxId } });
if (txn && txn.status === transaction_entity_1.PaymentStatus.SUCCESS) {
this.logger.warn(`Transaction ${externalTxId} already processed.`);
return;
}
if (!txn) {
const tenantId = metadata.tenantId;
if (!tenantId)
throw new common_1.BadRequestException('No tenantId found in payment metadata');
txn = await this.transactionRepository.save({
tenantId,
externalTransactionId: externalTxId,
amount,
provider,
status: transaction_entity_1.PaymentStatus.SUCCESS,
metadata,
});
}
else {
txn.status = transaction_entity_1.PaymentStatus.SUCCESS;
txn.metadata = { ...txn.metadata, ...metadata };
await this.transactionRepository.save(txn);
}
const tenantId = txn.tenantId;
const plan = metadata.plan || 'PRO';
await this.upgradeTenantPlan(tenantId, plan);
try {
const tenant = await this.tenantRepository.findOne({ where: { id: tenantId } });
if (tenant && tenant.email) {
await this.mailService.sendInvoiceEmail(tenant.email, {
tenantName: tenant.name,
plan: plan,
amount: `${amount} EGP`,
transactionId: externalTxId,
});
}
}
catch (err) {
this.logger.error(`Failed to send invoice email for tx ${externalTxId}: ${err.message}`);
}
this.logger.log(`✅ Tenant ${tenantId} upgraded to ${plan} after payment ${externalTxId}`);
}
async upgradeTenantPlan(tenantId, plan) {
await this.tenantRepository.update(tenantId, { plan });
const limits = {
[tenant_entity_1.TenantPlan.FREE]: 5000,
[tenant_entity_1.TenantPlan.STARTER]: 25000,
[tenant_entity_1.TenantPlan.PRO]: 100000,
[tenant_entity_1.TenantPlan.ENTERPRISE]: 500000,
};
const sub = await this.getSubscription(tenantId);
sub.plan = plan;
sub.monthlyRequestLimit = limits[plan] || 8000;
sub.status = subscription_entity_1.SubscriptionStatus.ACTIVE;
sub.currentPeriodStart = new Date();
const nextMonth = new Date();
nextMonth.setMonth(nextMonth.getMonth() + 1);
sub.currentPeriodEnd = nextMonth;
await this.subscriptionRepository.save(sub);
}
async getTransactionHistory(tenantId) {
return this.transactionRepository.find({
where: { tenantId },
order: { createdAt: 'DESC' },
});
}
};
exports.BillingService = BillingService;
exports.BillingService = BillingService = BillingService_1 = __decorate([
(0, common_1.Injectable)(),
__param(0, (0, typeorm_1.InjectRepository)(subscription_entity_1.Subscription)),
__param(1, (0, typeorm_1.InjectRepository)(transaction_entity_1.Transaction)),
__param(2, (0, typeorm_1.InjectRepository)(tenant_entity_1.Tenant)),
__metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object, typeof (_b = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _b : Object, typeof (_c = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _c : Object, typeof (_d = typeof config_1.ConfigService !== "undefined" && config_1.ConfigService) === "function" ? _d : Object, mail_service_1.MailService])
], BillingService);
//# sourceMappingURL=billing.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"billing.service.js","sourceRoot":"","sources":["../../src/billing/billing.service.ts"],"names":[],"mappings":"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"}
+18
View File
@@ -0,0 +1,18 @@
export declare enum SubscriptionStatus {
ACTIVE = "ACTIVE",
PAST_DUE = "PAST_DUE",
CANCELED = "CANCELED",
TRIALING = "TRIALING"
}
export declare class Subscription {
id: string;
tenantId: string;
plan: string;
status: SubscriptionStatus;
monthlyRequestLimit: number;
currentPeriodStart: Date;
currentPeriodEnd: Date;
canceledAt: Date;
createdAt: Date;
updatedAt: Date;
}
+82
View File
@@ -0,0 +1,82 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Subscription = exports.SubscriptionStatus = void 0;
const typeorm_1 = require("typeorm");
var SubscriptionStatus;
(function (SubscriptionStatus) {
SubscriptionStatus["ACTIVE"] = "ACTIVE";
SubscriptionStatus["PAST_DUE"] = "PAST_DUE";
SubscriptionStatus["CANCELED"] = "CANCELED";
SubscriptionStatus["TRIALING"] = "TRIALING";
})(SubscriptionStatus || (exports.SubscriptionStatus = SubscriptionStatus = {}));
let Subscription = class Subscription {
id;
tenantId;
plan;
status;
monthlyRequestLimit;
currentPeriodStart;
currentPeriodEnd;
canceledAt;
createdAt;
updatedAt;
};
exports.Subscription = Subscription;
__decorate([
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
__metadata("design:type", String)
], Subscription.prototype, "id", void 0);
__decorate([
(0, typeorm_1.Index)(),
(0, typeorm_1.Column)(),
__metadata("design:type", String)
], Subscription.prototype, "tenantId", void 0);
__decorate([
(0, typeorm_1.Column)({ default: 'FREE' }),
__metadata("design:type", String)
], Subscription.prototype, "plan", void 0);
__decorate([
(0, typeorm_1.Column)({
type: 'enum',
enum: SubscriptionStatus,
default: SubscriptionStatus.ACTIVE,
}),
__metadata("design:type", String)
], Subscription.prototype, "status", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'int', default: 8000 }),
__metadata("design:type", Number)
], Subscription.prototype, "monthlyRequestLimit", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'timestamp', nullable: true }),
__metadata("design:type", Date)
], Subscription.prototype, "currentPeriodStart", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'timestamp', nullable: true }),
__metadata("design:type", Date)
], Subscription.prototype, "currentPeriodEnd", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'timestamp', nullable: true }),
__metadata("design:type", Date)
], Subscription.prototype, "canceledAt", void 0);
__decorate([
(0, typeorm_1.CreateDateColumn)(),
__metadata("design:type", Date)
], Subscription.prototype, "createdAt", void 0);
__decorate([
(0, typeorm_1.UpdateDateColumn)(),
__metadata("design:type", Date)
], Subscription.prototype, "updatedAt", void 0);
exports.Subscription = Subscription = __decorate([
(0, typeorm_1.Entity)('subscriptions')
], Subscription);
//# sourceMappingURL=subscription.entity.js.map
@@ -0,0 +1 @@
{"version":3,"file":"subscription.entity.js","sourceRoot":"","sources":["../../../src/billing/entities/subscription.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAQiB;AAGjB,IAAY,kBAKX;AALD,WAAY,kBAAkB;IAC5B,uCAAiB,CAAA;IACjB,2CAAqB,CAAA;IACrB,2CAAqB,CAAA;IACrB,2CAAqB,CAAA;AACvB,CAAC,EALW,kBAAkB,kCAAlB,kBAAkB,QAK7B;AAGM,IAAM,YAAY,GAAlB,MAAM,YAAY;IAEvB,EAAE,CAAS;IAIX,QAAQ,CAAS;IAGjB,IAAI,CAAS;IAOb,MAAM,CAAqB;IAG3B,mBAAmB,CAAS;IAG5B,kBAAkB,CAAO;IAGzB,gBAAgB,CAAO;IAGvB,UAAU,CAAO;IAGjB,SAAS,CAAO;IAGhB,SAAS,CAAO;CACjB,CAAA;AAnCY,oCAAY;AAEvB;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;wCACpB;AAIX;IAFC,IAAA,eAAK,GAAE;IACP,IAAA,gBAAM,GAAE;;8CACQ;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;;0CACf;AAOb;IALC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,kBAAkB,CAAC,MAAM;KACnC,CAAC;;4CACyB;AAG3B;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;;yDACX;AAG5B;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BAC1B,IAAI;wDAAC;AAGzB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BAC5B,IAAI;sDAAC;AAGvB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BAClC,IAAI;gDAAC;AAGjB;IADC,IAAA,0BAAgB,GAAE;8BACR,IAAI;+CAAC;AAGhB;IADC,IAAA,0BAAgB,GAAE;8BACR,IAAI;+CAAC;uBAlCL,YAAY;IADxB,IAAA,gBAAM,EAAC,eAAe,CAAC;GACX,YAAY,CAmCxB"}
+23
View File
@@ -0,0 +1,23 @@
export declare enum PaymentStatus {
PENDING = "PENDING",
SUCCESS = "SUCCESS",
FAILED = "FAILED",
REFUNDED = "REFUNDED"
}
export declare enum PaymentProvider {
PAYMOB = "PAYMOB",
BINANCE = "BINANCE",
MANUAL = "MANUAL"
}
export declare class Transaction {
id: string;
tenantId: string;
subscriptionId: string;
amount: number;
currency: string;
provider: PaymentProvider;
externalTransactionId: string;
status: PaymentStatus;
metadata: Record<string, any>;
createdAt: Date;
}
+92
View File
@@ -0,0 +1,92 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Transaction = exports.PaymentProvider = exports.PaymentStatus = void 0;
const typeorm_1 = require("typeorm");
var PaymentStatus;
(function (PaymentStatus) {
PaymentStatus["PENDING"] = "PENDING";
PaymentStatus["SUCCESS"] = "SUCCESS";
PaymentStatus["FAILED"] = "FAILED";
PaymentStatus["REFUNDED"] = "REFUNDED";
})(PaymentStatus || (exports.PaymentStatus = PaymentStatus = {}));
var PaymentProvider;
(function (PaymentProvider) {
PaymentProvider["PAYMOB"] = "PAYMOB";
PaymentProvider["BINANCE"] = "BINANCE";
PaymentProvider["MANUAL"] = "MANUAL";
})(PaymentProvider || (exports.PaymentProvider = PaymentProvider = {}));
let Transaction = class Transaction {
id;
tenantId;
subscriptionId;
amount;
currency;
provider;
externalTransactionId;
status;
metadata;
createdAt;
};
exports.Transaction = Transaction;
__decorate([
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
__metadata("design:type", String)
], Transaction.prototype, "id", void 0);
__decorate([
(0, typeorm_1.Index)(),
(0, typeorm_1.Column)(),
__metadata("design:type", String)
], Transaction.prototype, "tenantId", void 0);
__decorate([
(0, typeorm_1.Column)({ nullable: true }),
__metadata("design:type", String)
], Transaction.prototype, "subscriptionId", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'decimal', precision: 10, scale: 2 }),
__metadata("design:type", Number)
], Transaction.prototype, "amount", void 0);
__decorate([
(0, typeorm_1.Column)({ default: 'USD' }),
__metadata("design:type", String)
], Transaction.prototype, "currency", void 0);
__decorate([
(0, typeorm_1.Column)({
type: 'enum',
enum: PaymentProvider,
}),
__metadata("design:type", String)
], Transaction.prototype, "provider", void 0);
__decorate([
(0, typeorm_1.Index)(),
(0, typeorm_1.Column)({ nullable: true }),
__metadata("design:type", String)
], Transaction.prototype, "externalTransactionId", void 0);
__decorate([
(0, typeorm_1.Column)({
type: 'enum',
enum: PaymentStatus,
default: PaymentStatus.PENDING,
}),
__metadata("design:type", String)
], Transaction.prototype, "status", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'jsonb', nullable: true }),
__metadata("design:type", Object)
], Transaction.prototype, "metadata", void 0);
__decorate([
(0, typeorm_1.CreateDateColumn)(),
__metadata("design:type", Date)
], Transaction.prototype, "createdAt", void 0);
exports.Transaction = Transaction = __decorate([
(0, typeorm_1.Entity)('transactions')
], Transaction);
//# sourceMappingURL=transaction.entity.js.map
@@ -0,0 +1 @@
{"version":3,"file":"transaction.entity.js","sourceRoot":"","sources":["../../../src/billing/entities/transaction.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAMiB;AAEjB,IAAY,aAKX;AALD,WAAY,aAAa;IACvB,oCAAmB,CAAA;IACnB,oCAAmB,CAAA;IACnB,kCAAiB,CAAA;IACjB,sCAAqB,CAAA;AACvB,CAAC,EALW,aAAa,6BAAb,aAAa,QAKxB;AAED,IAAY,eAIX;AAJD,WAAY,eAAe;IACzB,oCAAiB,CAAA;IACjB,sCAAmB,CAAA;IACnB,oCAAiB,CAAA;AACnB,CAAC,EAJW,eAAe,+BAAf,eAAe,QAI1B;AAGM,IAAM,WAAW,GAAjB,MAAM,WAAW;IAEtB,EAAE,CAAS;IAIX,QAAQ,CAAS;IAGjB,cAAc,CAAS;IAGvB,MAAM,CAAS;IAGf,QAAQ,CAAS;IAMjB,QAAQ,CAAkB;IAI1B,qBAAqB,CAAS;IAO9B,MAAM,CAAgB;IAGtB,QAAQ,CAAsB;IAG9B,SAAS,CAAO;CACjB,CAAA;AAvCY,kCAAW;AAEtB;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;uCACpB;AAIX;IAFC,IAAA,eAAK,GAAE;IACP,IAAA,gBAAM,GAAE;;6CACQ;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mDACJ;AAGvB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;;2CACtC;AAGf;IADC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;;6CACV;AAMjB;IAJC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,eAAe;KACtB,CAAC;;6CACwB;AAI1B;IAFC,IAAA,eAAK,GAAE;IACP,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;0DACG;AAO9B;IALC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,aAAa,CAAC,OAAO;KAC/B,CAAC;;2CACoB;AAGtB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;6CACZ;AAG9B;IADC,IAAA,0BAAgB,GAAE;8BACR,IAAI;8CAAC;sBAtCL,WAAW;IADvB,IAAA,gBAAM,EAAC,cAAc,CAAC;GACV,WAAW,CAuCvB"}
+16
View File
@@ -0,0 +1,16 @@
import { ConfigService } from '@nestjs/config';
export declare class BinanceProvider {
private configService;
private readonly logger;
private readonly apiUrl;
constructor(configService: ConfigService);
private get apiKey();
private get secretKey();
private generateSignature;
createOrder(tenantId: string, amount: number, plan: string): Promise<{
checkoutUrl: any;
orderId: string;
prepayId: any;
}>;
verifySignature(timestamp: string, nonce: string, signature: string, payloadBody: any): boolean;
}
+150
View File
@@ -0,0 +1,150 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var BinanceProvider_1;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BinanceProvider = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const axios_1 = __importDefault(require("axios"));
const crypto = __importStar(require("crypto"));
let BinanceProvider = BinanceProvider_1 = class BinanceProvider {
configService;
logger = new common_1.Logger(BinanceProvider_1.name);
apiUrl = 'https://bpay.binanceapi.com/binancepay/openapi/v2/order';
constructor(configService) {
this.configService = configService;
}
get apiKey() {
return this.configService.get('BINANCE_PAY_API_KEY') || '';
}
get secretKey() {
return this.configService.get('BINANCE_PAY_SECRET_KEY') || '';
}
generateSignature(timestamp, nonce, body) {
const payload = timestamp + '\n' + nonce + '\n' + JSON.stringify(body) + '\n';
return crypto
.createHmac('sha512', this.secretKey)
.update(payload)
.digest('hex')
.toUpperCase();
}
async createOrder(tenantId, amount, plan) {
this.logger.log(`Creating Binance Pay order for ${tenantId} - ${plan}`);
if (!this.apiKey || !this.secretKey) {
this.logger.error('Binance Pay API keys are not configured');
throw new common_1.InternalServerErrorException('Payment provider is not configured properly');
}
const nonce = crypto.randomBytes(16).toString('hex');
const timestamp = Date.now().toString();
const merchantTradeNo = `txn_${Date.now()}_${Math.floor(Math.random() * 10000)}`;
const body = {
env: {
terminalType: 'WEB',
},
merchantTradeNo: merchantTradeNo,
orderAmount: amount,
currency: 'USDT',
goods: {
goodsType: '01',
goodsCategory: 'Z000',
referenceGoodsId: plan,
goodsName: `${plan} Plan Subscription`,
goodsDetail: `Subscription to ${plan} plan for Maps SaaS`,
},
passThroughInfo: JSON.stringify({ tenantId, plan }),
returnUrl: `https://map-dashboard.intaleqapp.com/dashboard.html#billing`,
};
const signature = this.generateSignature(timestamp, nonce, body);
try {
const response = await axios_1.default.post(this.apiUrl, body, {
headers: {
'Content-Type': 'application/json',
'BinancePay-Timestamp': timestamp,
'BinancePay-Nonce': nonce,
'BinancePay-Certificate-SN': this.apiKey,
'BinancePay-Signature': signature,
},
});
if (response.data && response.data.status === 'SUCCESS') {
return {
checkoutUrl: response.data.data.checkoutUrl,
orderId: merchantTradeNo,
prepayId: response.data.data.prepayId,
};
}
else {
this.logger.error(`Binance API Error: ${JSON.stringify(response.data)}`);
throw new common_1.InternalServerErrorException('Failed to create Binance order');
}
}
catch (error) {
this.logger.error(`Error communicating with Binance API: ${error.message}`);
throw new common_1.InternalServerErrorException('Failed to communicate with payment provider');
}
}
verifySignature(timestamp, nonce, signature, payloadBody) {
const payload = timestamp + '\n' + nonce + '\n' + JSON.stringify(payloadBody) + '\n';
const expectedSignature = crypto
.createHmac('sha512', this.secretKey)
.update(payload)
.digest('hex')
.toUpperCase();
try {
return crypto.timingSafeEqual(Buffer.from(signature || ''), Buffer.from(expectedSignature));
}
catch (e) {
return false;
}
}
};
exports.BinanceProvider = BinanceProvider;
exports.BinanceProvider = BinanceProvider = BinanceProvider_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [typeof (_a = typeof config_1.ConfigService !== "undefined" && config_1.ConfigService) === "function" ? _a : Object])
], BinanceProvider);
//# sourceMappingURL=binance.provider.js.map
@@ -0,0 +1 @@
{"version":3,"file":"binance.provider.js","sourceRoot":"","sources":["../../../src/billing/providers/binance.provider.ts"],"names":[],"mappings":"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"}
+14
View File
@@ -0,0 +1,14 @@
import { ConfigService } from '@nestjs/config';
export declare class PayMobProvider {
private configService;
private readonly logger;
private readonly baseUrl;
constructor(configService: ConfigService);
createPaymentKey(tenantId: string, amount: number, plan: string): Promise<{
paymentKey: string;
orderId: string;
}>;
getTransactionDetails(transactionId: string): Promise<any>;
private getAuthToken;
verifyHmac(payload: any, hmac: string): boolean;
}
+179
View File
@@ -0,0 +1,179 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var PayMobProvider_1;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PayMobProvider = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const axios_1 = __importDefault(require("axios"));
const crypto = __importStar(require("crypto"));
let PayMobProvider = PayMobProvider_1 = class PayMobProvider {
configService;
logger = new common_1.Logger(PayMobProvider_1.name);
baseUrl = 'https://accept.paymob.com/api';
constructor(configService) {
this.configService = configService;
}
async createPaymentKey(tenantId, amount, plan) {
try {
const authToken = await this.getAuthToken();
const orderRes = await axios_1.default.post(`${this.baseUrl}/ecommerce/orders`, {
auth_token: authToken,
delivery_needed: "false",
amount_cents: amount * 50 * 100,
currency: "EGP",
items: [{
name: `${plan} Subscription`,
amount_cents: amount * 50 * 100,
description: `Intaleq Maps ${plan} Plan`
}],
shipping_data: {
first_name: "Intaleq",
last_name: "User",
email: "user@intaleq.com",
phone_number: "+201000000000",
extra_description: `${tenantId}|${plan}`
}
});
const orderId = orderRes.data.id;
const keyRes = await axios_1.default.post(`${this.baseUrl}/acceptance/payment_keys`, {
auth_token: authToken,
amount_cents: amount * 50 * 100,
expiration: 3600,
order_id: orderId,
billing_data: {
apartment: "NA",
email: "user@intaleq.com",
floor: "NA",
first_name: "Intaleq",
street: "NA",
building: "NA",
phone_number: "+201000000000",
shipping_method: "NA",
postal_code: "NA",
city: "NA",
country: "NA",
last_name: "User",
state: "NA"
},
currency: "EGP",
integration_id: this.configService.get('PAYMOB_INTEGRATION_ID') || 4556055,
lock_order_when_paid: "false"
});
return {
paymentKey: keyRes.data.token,
orderId: orderId.toString()
};
}
catch (error) {
this.logger.error(`PayMob Payment Key failed: ${error.response?.data ? JSON.stringify(error.response.data) : error.message}`);
throw new common_1.BadRequestException('Failed to initialize PayMob payment');
}
}
async getTransactionDetails(transactionId) {
try {
const authToken = await this.getAuthToken();
const res = await axios_1.default.get(`${this.baseUrl}/acceptance/transactions/${transactionId}`, {
headers: { Authorization: `Bearer ${authToken}` }
});
return res.data;
}
catch (error) {
this.logger.error(`Failed to fetch PayMob transaction ${transactionId}: ${error.message}`);
return null;
}
}
async getAuthToken() {
const authRes = await axios_1.default.post(`${this.baseUrl}/auth/tokens`, {
api_key: this.configService.get('PAYMOB_API_KEY'),
});
return authRes.data.token;
}
verifyHmac(payload, hmac) {
const secret = this.configService.get('PAYMOB_HMAC_SECRET');
if (!secret)
return false;
const { amount_cents, created_at, currency, error_occured, has_parent_transaction, id, integration_id, is_3d_secure, is_auth, is_capture, is_refunded, is_standalone_payment, is_voided, order, owner, pending, success } = payload;
const source_pan = payload.source_data?.pan || "";
const source_sub_type = payload.source_data?.sub_type || "";
const source_type = payload.source_data?.type || "";
const data = [
amount_cents,
created_at,
currency,
error_occured,
has_parent_transaction,
id,
integration_id,
is_3d_secure,
is_auth,
is_capture,
is_refunded,
is_standalone_payment,
is_voided,
order.id || order,
owner,
pending,
source_pan,
source_sub_type,
source_type,
success
].join("");
const hash = crypto
.createHmac('sha512', secret)
.update(data)
.digest('hex');
return hash === hmac;
}
};
exports.PayMobProvider = PayMobProvider;
exports.PayMobProvider = PayMobProvider = PayMobProvider_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [typeof (_a = typeof config_1.ConfigService !== "undefined" && config_1.ConfigService) === "function" ? _a : Object])
], PayMobProvider);
//# sourceMappingURL=paymob.provider.js.map
@@ -0,0 +1 @@
{"version":3,"file":"paymob.provider.js","sourceRoot":"","sources":["../../../src/billing/providers/paymob.provider.ts"],"names":[],"mappings":"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"}
+2 -1
View File
@@ -8,6 +8,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
var __metadata = (this && this.__metadata) || function (k, v) { var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}; };
var _a;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.CacheService = void 0; exports.CacheService = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
@@ -38,6 +39,6 @@ let CacheService = class CacheService {
exports.CacheService = CacheService; exports.CacheService = CacheService;
exports.CacheService = CacheService = __decorate([ exports.CacheService = CacheService = __decorate([
(0, common_1.Injectable)(), (0, common_1.Injectable)(),
__metadata("design:paramtypes", [config_1.ConfigService]) __metadata("design:paramtypes", [typeof (_a = typeof config_1.ConfigService !== "undefined" && config_1.ConfigService) === "function" ? _a : Object])
], CacheService); ], CacheService);
//# sourceMappingURL=cache.service.js.map //# sourceMappingURL=cache.service.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"cache.service.js","sourceRoot":"","sources":["../../src/common/cache.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAoD;AACpD,iCAAqC;AACrC,2CAA+C;AAGxC,IAAM,YAAY,GAAlB,MAAM,YAAY;IAGH;IAFZ,MAAM,CAAC;IAEf,YAAoB,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,GAAG,IAAA,oBAAY,EAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAU,EAAE,aAAqB,IAAI;QAG1D,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE;YAChD,EAAE,EAAE,UAAU;SACf,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QAGnB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;CACF,CAAA;AA3BY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;qCAIwB,sBAAa;GAHrC,YAAY,CA2BxB"} {"version":3,"file":"cache.service.js","sourceRoot":"","sources":["../../src/common/cache.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAoD;AACpD,iCAAqC;AACrC,2CAA+C;AAGxC,IAAM,YAAY,GAAlB,MAAM,YAAY;IAGH;IAFZ,MAAM,CAAC;IAEf,YAAoB,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,GAAG,IAAA,oBAAY,EAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAU,EAAE,aAAqB,IAAI;QAG1D,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE;YAChD,EAAE,EAAE,UAAU;SACf,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QAGnB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;CACF,CAAA;AA3BY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;yDAIwB,sBAAa,oBAAb,sBAAa;GAHrC,YAAY,CA2BxB"}
+4
View File
@@ -0,0 +1,4 @@
import { CanActivate, ExecutionContext } from '@nestjs/common';
export declare class AdminGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean;
}
+29
View File
@@ -0,0 +1,29 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminGuard = void 0;
const common_1 = require("@nestjs/common");
const tenant_entity_1 = require("../../auth/entities/tenant.entity");
let AdminGuard = class AdminGuard {
canActivate(context) {
const request = context.switchToHttp().getRequest();
const tenant = request['tenant'];
if (!tenant) {
throw new common_1.UnauthorizedException('Tenant not found in request');
}
if (tenant.plan !== tenant_entity_1.TenantPlan.ENTERPRISE) {
throw new common_1.ForbiddenException('Admin access required. Your tenant plan must be ENTERPRISE.');
}
return true;
}
};
exports.AdminGuard = AdminGuard;
exports.AdminGuard = AdminGuard = __decorate([
(0, common_1.Injectable)()
], AdminGuard);
//# sourceMappingURL=admin.guard.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"admin.guard.js","sourceRoot":"","sources":["../../../src/common/guards/admin.guard.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAsH;AACtH,qEAA+D;AAGxD,IAAM,UAAU,GAAhB,MAAM,UAAU;IACrB,WAAW,CAAC,OAAyB;QACnC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QAEjC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,8BAAqB,CAAC,6BAA6B,CAAC,CAAC;QACjE,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,0BAAU,CAAC,UAAU,EAAE,CAAC;YAC1C,MAAM,IAAI,2BAAkB,CAAC,6DAA6D,CAAC,CAAC;QAC9F,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AAfY,gCAAU;qBAAV,UAAU;IADtB,IAAA,mBAAU,GAAE;GACA,UAAU,CAetB"}
+1
View File
@@ -1,5 +1,6 @@
import { ThrottlerGuard, ThrottlerRequest } from '@nestjs/throttler'; import { ThrottlerGuard, ThrottlerRequest } from '@nestjs/throttler';
export declare class TenantThrottlerGuard extends ThrottlerGuard { export declare class TenantThrottlerGuard extends ThrottlerGuard {
private readonly logger;
protected getTracker(req: Record<string, any>): Promise<string>; protected getTracker(req: Record<string, any>): Promise<string>;
protected handleRequest(requestProps: ThrottlerRequest): Promise<boolean>; protected handleRequest(requestProps: ThrottlerRequest): Promise<boolean>;
} }
+12 -4
View File
@@ -5,25 +5,33 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r; return c > 3 && r && Object.defineProperty(target, key, r), r;
}; };
var TenantThrottlerGuard_1;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.TenantThrottlerGuard = void 0; exports.TenantThrottlerGuard = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
const throttler_1 = require("@nestjs/throttler"); const throttler_1 = require("@nestjs/throttler");
let TenantThrottlerGuard = class TenantThrottlerGuard extends throttler_1.ThrottlerGuard { let TenantThrottlerGuard = TenantThrottlerGuard_1 = class TenantThrottlerGuard extends throttler_1.ThrottlerGuard {
logger = new common_1.Logger(TenantThrottlerGuard_1.name);
async getTracker(req) { async getTracker(req) {
const apiKeyId = req['apiKey']?.id || req.ip; const apiKeyId = req['apiKey']?.id || req.ip;
return `throttler:key:${apiKeyId}`; return `throttler:key:${apiKeyId}`;
} }
async handleRequest(requestProps) { async handleRequest(requestProps) {
const { context, limit } = requestProps; const { context, limit, ttl } = requestProps;
const request = context.switchToHttp().getRequest(); const request = context.switchToHttp().getRequest();
const dynamicLimit = request['rateLimit'] || limit; const dynamicLimit = request['rateLimit'];
if (dynamicLimit) {
this.logger.debug(`Applying dynamic rate limit: ${dynamicLimit} req/min for key ${request['apiKey']?.id}`);
requestProps.limit = dynamicLimit; requestProps.limit = dynamicLimit;
}
else {
this.logger.debug(`Applying default rate limit: ${limit} req/min`);
}
return super.handleRequest(requestProps); return super.handleRequest(requestProps);
} }
}; };
exports.TenantThrottlerGuard = TenantThrottlerGuard; exports.TenantThrottlerGuard = TenantThrottlerGuard;
exports.TenantThrottlerGuard = TenantThrottlerGuard = __decorate([ exports.TenantThrottlerGuard = TenantThrottlerGuard = TenantThrottlerGuard_1 = __decorate([
(0, common_1.Injectable)() (0, common_1.Injectable)()
], TenantThrottlerGuard); ], TenantThrottlerGuard);
//# sourceMappingURL=rate-limiter.guard.js.map //# sourceMappingURL=rate-limiter.guard.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"rate-limiter.guard.js","sourceRoot":"","sources":["../../../src/common/guards/rate-limiter.guard.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA8D;AAC9D,iDAAqE;AAG9D,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,0BAAc;IAK5C,KAAK,CAAC,UAAU,CAAC,GAAwB;QAEjD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC;QAC7C,OAAO,iBAAiB,QAAQ,EAAE,CAAC;IACrC,CAAC;IAKS,KAAK,CAAC,aAAa,CAC3B,YAA8B;QAE9B,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC;QACxC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAGpD,MAAM,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC;QAGnD,YAAY,CAAC,KAAK,GAAG,YAAY,CAAC;QAGlC,OAAO,KAAK,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;IAC3C,CAAC;CACF,CAAA;AA7BY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;GACA,oBAAoB,CA6BhC"} {"version":3,"file":"rate-limiter.guard.js","sourceRoot":"","sources":["../../../src/common/guards/rate-limiter.guard.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAsE;AACtE,iDAAqE;AAG9D,IAAM,oBAAoB,4BAA1B,MAAM,oBAAqB,SAAQ,0BAAc;IACrC,MAAM,GAAG,IAAI,eAAM,CAAC,sBAAoB,CAAC,IAAI,CAAC,CAAC;IAEtD,KAAK,CAAC,UAAU,CAAC,GAAwB;QACjD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC;QAC7C,OAAO,iBAAiB,QAAQ,EAAE,CAAC;IACrC,CAAC;IAES,KAAK,CAAC,aAAa,CAC3B,YAA8B;QAE9B,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,YAAY,CAAC;QAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAE,CAAC;QAGpD,MAAM,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QAE1C,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,YAAY,oBAAoB,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC3G,YAAY,CAAC,KAAK,GAAG,YAAY,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,KAAK,UAAU,CAAC,CAAC;QACrE,CAAC;QAED,OAAO,KAAK,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;IAC3C,CAAC;CACF,CAAA;AA1BY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;GACA,oBAAoB,CA0BhC"}
+2
View File
@@ -0,0 +1,2 @@
export declare class MailModule {
}
+22
View File
@@ -0,0 +1,22 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MailModule = void 0;
const common_1 = require("@nestjs/common");
const mail_service_1 = require("./mail.service");
let MailModule = class MailModule {
};
exports.MailModule = MailModule;
exports.MailModule = MailModule = __decorate([
(0, common_1.Global)(),
(0, common_1.Module)({
providers: [mail_service_1.MailService],
exports: [mail_service_1.MailService],
})
], MailModule);
//# sourceMappingURL=mail.module.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"mail.module.js","sourceRoot":"","sources":["../../src/common/mail.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAgD;AAChD,iDAA6C;AAOtC,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IALtB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE,CAAC,0BAAW,CAAC;QACxB,OAAO,EAAE,CAAC,0BAAW,CAAC;KACvB,CAAC;GACW,UAAU,CAAG"}
+13
View File
@@ -0,0 +1,13 @@
import { ConfigService } from '@nestjs/config';
export declare class MailService {
private configService;
private readonly logger;
private transporter;
constructor(configService: ConfigService);
sendInvoiceEmail(to: string, data: {
tenantName: string;
plan: string;
amount: string;
transactionId: string;
}): Promise<boolean>;
}
+122
View File
@@ -0,0 +1,122 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var MailService_1;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MailService = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const nodemailer = __importStar(require("nodemailer"));
let MailService = MailService_1 = class MailService {
configService;
logger = new common_1.Logger(MailService_1.name);
transporter;
constructor(configService) {
this.configService = configService;
const host = this.configService.get('SMTP_HOST');
const port = this.configService.get('SMTP_PORT') || 587;
const user = this.configService.get('SMTP_USER');
const pass = this.configService.get('SMTP_PASS');
if (host && user && pass) {
this.transporter = nodemailer.createTransport({
host,
port,
secure: port === 465,
auth: {
user,
pass,
},
});
this.logger.log(`📧 MailService initialized with host: ${host}`);
}
else {
this.logger.warn('⚠️ SMTP settings not fully configured. MailService will run in mock mode.');
}
}
async sendInvoiceEmail(to, data) {
const from = this.configService.get('SMTP_FROM') || 'support@intaleqapp.com';
const htmlContent = `
<div style="font-family: sans-serif; max-width: 600px; margin: auto; border: 1px solid #eee; padding: 20px; border-radius: 10px;">
<h2 style="color: #2563eb;">Intaleq Maps - Payment Successful</h2>
<p>Hello <b>${data.tenantName}</b>,</p>
<p>Thank you for subscribing to our <b>${data.plan}</b> plan. Your payment has been processed successfully.</p>
<div style="background: #f8fafc; padding: 15px; border-radius: 8px; margin: 20px 0;">
<p style="margin: 5px 0;"><b>Plan:</b> ${data.plan}</p>
<p style="margin: 5px 0;"><b>Amount:</b> ${data.amount}</p>
<p style="margin: 5px 0;"><b>Transaction ID:</b> ${data.transactionId}</p>
<p style="margin: 5px 0;"><b>Date:</b> ${new Date().toLocaleDateString()}</p>
</div>
<p>You can now access all your premium features from your dashboard.</p>
<hr style="border: none; border-top: 1px solid #eee; margin: 20px 0;">
<p style="font-size: 12px; color: #64748b;">If you have any questions, contact us at ${from}</p>
</div>
`;
if (!this.transporter) {
this.logger.warn(`[Mock Email] To: ${to}, Plan: ${data.plan}, Amount: ${data.amount}`);
return true;
}
try {
await this.transporter.sendMail({
from: `"Intaleq Support" <${from}>`,
to,
subject: `Invoice: ${data.plan} Subscription - Intaleq Maps`,
html: htmlContent,
});
this.logger.log(`✅ Invoice email sent to ${to}`);
return true;
}
catch (error) {
this.logger.error(`❌ Failed to send email: ${error.message}`);
return false;
}
}
};
exports.MailService = MailService;
exports.MailService = MailService = MailService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [typeof (_a = typeof config_1.ConfigService !== "undefined" && config_1.ConfigService) === "function" ? _a : Object])
], MailService);
//# sourceMappingURL=mail.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"mail.service.js","sourceRoot":"","sources":["../../src/common/mail.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,2CAA+C;AAC/C,uDAAyC;AAGlC,IAAM,WAAW,mBAAjB,MAAM,WAAW;IAIF;IAHH,MAAM,GAAG,IAAI,eAAM,CAAC,aAAW,CAAC,IAAI,CAAC,CAAC;IAC/C,WAAW,CAAyB;IAE5C,YAAoB,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;QAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,CAAC,IAAI,GAAG,CAAC;QAChE,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,CAAC,CAAC;QAEzD,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;YACzB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC,eAAe,CAAC;gBAC5C,IAAI;gBACJ,IAAI;gBACJ,MAAM,EAAE,IAAI,KAAK,GAAG;gBACpB,IAAI,EAAE;oBACJ,IAAI;oBACJ,IAAI;iBACL;aACF,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yCAAyC,IAAI,EAAE,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2EAA2E,CAAC,CAAC;QAChG,CAAC;IACH,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,EAAU,EAAE,IAKlC;QACC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,WAAW,CAAC,IAAI,wBAAwB,CAAC;QAErF,MAAM,WAAW,GAAG;;;sBAGF,IAAI,CAAC,UAAU;iDACY,IAAI,CAAC,IAAI;;;mDAGP,IAAI,CAAC,IAAI;qDACP,IAAI,CAAC,MAAM;6DACH,IAAI,CAAC,aAAa;mDAC5B,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE;;;;;+FAKa,IAAI;;KAE9F,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,WAAW,IAAI,CAAC,IAAI,aAAa,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YACvF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;gBAC9B,IAAI,EAAE,sBAAsB,IAAI,GAAG;gBACnC,EAAE;gBACF,OAAO,EAAE,YAAY,IAAI,CAAC,IAAI,8BAA8B;gBAC5D,IAAI,EAAE,WAAW;aAClB,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;YACjD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAC9D,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF,CAAA;AAxEY,kCAAW;sBAAX,WAAW;IADvB,IAAA,mBAAU,GAAE;yDAKwB,sBAAa,oBAAb,sBAAa;GAJrC,WAAW,CAwEvB"}
+1
View File
@@ -3,6 +3,7 @@ import type { RedisClientType } from 'redis';
export declare class RedisService implements OnModuleDestroy { export declare class RedisService implements OnModuleDestroy {
private readonly redisClient; private readonly redisClient;
constructor(redisClient: RedisClientType); constructor(redisClient: RedisClientType);
getClient(): RedisClientType;
set(key: string, value: any, ttlSeconds?: number): Promise<void>; set(key: string, value: any, ttlSeconds?: number): Promise<void>;
get<T>(key: string): Promise<T | null>; get<T>(key: string): Promise<T | null>;
del(key: string): Promise<void>; del(key: string): Promise<void>;
+3
View File
@@ -19,6 +19,9 @@ let RedisService = class RedisService {
constructor(redisClient) { constructor(redisClient) {
this.redisClient = redisClient; this.redisClient = redisClient;
} }
getClient() {
return this.redisClient;
}
async set(key, value, ttlSeconds) { async set(key, value, ttlSeconds) {
const stringValue = typeof value === 'string' ? value : JSON.stringify(value); const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
if (ttlSeconds) { if (ttlSeconds) {
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"redis.service.js","sourceRoot":"","sources":["../../src/common/redis.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAqE;AAS9D,IAAM,YAAY,GAAlB,MAAM,YAAY;IAEoB;IAD3C,YAC2C,WAA4B;QAA5B,gBAAW,GAAX,WAAW,CAAiB;IACpE,CAAC;IAMJ,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAU,EAAE,UAAmB;QACpD,MAAM,WAAW,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9E,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAMD,KAAK,CAAC,GAAG,CAAI,GAAW;QACtB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAM,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAqB,CAAC;QAC/B,CAAC;IACH,CAAC;IAMD,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;CACF,CAAA;AA5CY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;IAGR,WAAA,IAAA,eAAM,EAAC,cAAc,CAAC,CAAA;;GAFd,YAAY,CA4CxB"} {"version":3,"file":"redis.service.js","sourceRoot":"","sources":["../../src/common/redis.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAqE;AAS9D,IAAM,YAAY,GAAlB,MAAM,YAAY;IAEoB;IAD3C,YAC2C,WAA4B;QAA5B,gBAAW,GAAX,WAAW,CAAiB;IACpE,CAAC;IAKJ,SAAS;QACP,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAMD,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAU,EAAE,UAAmB;QACpD,MAAM,WAAW,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9E,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAMD,KAAK,CAAC,GAAG,CAAI,GAAW;QACtB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAM,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAqB,CAAC;QAC/B,CAAC;IACH,CAAC;IAMD,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;CACF,CAAA;AAnDY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;IAGR,WAAA,IAAA,eAAM,EAAC,cAAc,CAAC,CAAA;;GAFd,YAAY,CAmDxB"}
+2 -1
View File
@@ -12,6 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
var TelegramService_1; var TelegramService_1;
var _a;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.TelegramService = void 0; exports.TelegramService = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
@@ -70,6 +71,6 @@ let TelegramService = TelegramService_1 = class TelegramService {
exports.TelegramService = TelegramService; exports.TelegramService = TelegramService;
exports.TelegramService = TelegramService = TelegramService_1 = __decorate([ exports.TelegramService = TelegramService = TelegramService_1 = __decorate([
(0, common_1.Injectable)(), (0, common_1.Injectable)(),
__metadata("design:paramtypes", [config_1.ConfigService]) __metadata("design:paramtypes", [typeof (_a = typeof config_1.ConfigService !== "undefined" && config_1.ConfigService) === "function" ? _a : Object])
], TelegramService); ], TelegramService);
//# sourceMappingURL=telegram.service.js.map //# sourceMappingURL=telegram.service.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"telegram.service.js","sourceRoot":"","sources":["../../src/common/telegram.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,2CAA+C;AAC/C,kDAA0B;AAGnB,IAAM,eAAe,uBAArB,MAAM,eAAe;IAKN;IAJH,MAAM,GAAG,IAAI,eAAM,CAAC,iBAAe,CAAC,IAAI,CAAC,CAAC;IAC1C,QAAQ,CAAS;IACjB,MAAM,CAAS;IAEhC,YAAoB,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;QAC9C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,oBAAoB,CAAC,IAAI,EAAE,CAAC;QAC3E,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,kBAAkB,CAAC,IAAI,EAAE,CAAC;IACzE,CAAC;IAMD,KAAK,CAAC,WAAW,CAAC,IAAY;QAC5B,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC/E,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;YACzF,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;YACjD,MAAM,GAAG,GAAG,+BAA+B,IAAI,CAAC,QAAQ,cAAc,CAAC;YACvE,MAAM,eAAK,CAAC,IAAI,CAAC,GAAG,EAAE;gBACpB,OAAO,EAAE,IAAI,CAAC,MAAM;gBACpB,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,MAAM;aACnB,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACzE,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,KAAK,CAAC,QAAQ,CAAC,MAAM,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtG,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAKD,KAAK,CAAC,sBAAsB,CAAC,KAO5B;QACC,MAAM,OAAO,GAAG;;;yBAGK,KAAK,CAAC,IAAI;6BACN,KAAK,CAAC,UAAU;4BACjB,KAAK,CAAC,eAAe;4BACrB,KAAK,CAAC,eAAe;2BACtB,KAAK,CAAC,YAAY,IAAI,CAAC;4BACtB,KAAK,CAAC,WAAW;;;KAGxC,CAAC;QACF,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;CACF,CAAA;AAhEY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;qCAMwB,sBAAa;GALrC,eAAe,CAgE3B"} {"version":3,"file":"telegram.service.js","sourceRoot":"","sources":["../../src/common/telegram.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,2CAA+C;AAC/C,kDAA0B;AAGnB,IAAM,eAAe,uBAArB,MAAM,eAAe;IAKN;IAJH,MAAM,GAAG,IAAI,eAAM,CAAC,iBAAe,CAAC,IAAI,CAAC,CAAC;IAC1C,QAAQ,CAAS;IACjB,MAAM,CAAS;IAEhC,YAAoB,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;QAC9C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,oBAAoB,CAAC,IAAI,EAAE,CAAC;QAC3E,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAS,kBAAkB,CAAC,IAAI,EAAE,CAAC;IACzE,CAAC;IAMD,KAAK,CAAC,WAAW,CAAC,IAAY;QAC5B,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC/E,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;YACzF,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;YACjD,MAAM,GAAG,GAAG,+BAA+B,IAAI,CAAC,QAAQ,cAAc,CAAC;YACvE,MAAM,eAAK,CAAC,IAAI,CAAC,GAAG,EAAE;gBACpB,OAAO,EAAE,IAAI,CAAC,MAAM;gBACpB,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,MAAM;aACnB,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACzE,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,KAAK,CAAC,QAAQ,CAAC,MAAM,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtG,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAKD,KAAK,CAAC,sBAAsB,CAAC,KAO5B;QACC,MAAM,OAAO,GAAG;;;yBAGK,KAAK,CAAC,IAAI;6BACN,KAAK,CAAC,UAAU;4BACjB,KAAK,CAAC,eAAe;4BACrB,KAAK,CAAC,eAAe;2BACtB,KAAK,CAAC,YAAY,IAAI,CAAC;4BACtB,KAAK,CAAC,WAAW;;;KAGxC,CAAC;QACF,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;CACF,CAAA;AAhEY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;yDAMwB,sBAAa,oBAAb,sBAAa;GALrC,eAAe,CAgE3B"}
+2 -1
View File
@@ -12,6 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); } return function (target, key) { decorator(target, key, paramIndex); }
}; };
var AdminBoundariesService_1; var AdminBoundariesService_1;
var _a;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.AdminBoundariesService = void 0; exports.AdminBoundariesService = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
@@ -132,6 +133,6 @@ exports.AdminBoundariesService = AdminBoundariesService;
exports.AdminBoundariesService = AdminBoundariesService = AdminBoundariesService_1 = __decorate([ exports.AdminBoundariesService = AdminBoundariesService = AdminBoundariesService_1 = __decorate([
(0, common_1.Injectable)(), (0, common_1.Injectable)(),
__param(0, (0, typeorm_1.InjectRepository)(admin_boundary_entity_1.AdminBoundary)), __param(0, (0, typeorm_1.InjectRepository)(admin_boundary_entity_1.AdminBoundary)),
__metadata("design:paramtypes", [typeorm_2.Repository]) __metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object])
], AdminBoundariesService); ], AdminBoundariesService);
//# sourceMappingURL=admin-boundaries.service.js.map //# sourceMappingURL=admin-boundaries.service.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"admin-boundaries.service.js","sourceRoot":"","sources":["../../src/geocoding/admin-boundaries.service.ts"],"names":[],"mappings":"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"} {"version":3,"file":"admin-boundaries.service.js","sourceRoot":"","sources":["../../src/geocoding/admin-boundaries.service.ts"],"names":[],"mappings":"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"}
+2 -4
View File
@@ -15,6 +15,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
var AdministrativeLinkingService_1; var AdministrativeLinkingService_1;
var _a, _b, _c, _d;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.AdministrativeLinkingService = void 0; exports.AdministrativeLinkingService = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
@@ -277,9 +278,6 @@ exports.AdministrativeLinkingService = AdministrativeLinkingService = Administra
__param(1, (0, typeorm_1.InjectRepository)(neighborhood_point_entity_1.NeighborhoodPoint)), __param(1, (0, typeorm_1.InjectRepository)(neighborhood_point_entity_1.NeighborhoodPoint)),
__param(2, (0, typeorm_1.InjectRepository)(neighborhood_polygon_entity_1.NeighborhoodPolygon)), __param(2, (0, typeorm_1.InjectRepository)(neighborhood_polygon_entity_1.NeighborhoodPolygon)),
__param(3, (0, typeorm_1.InjectRepository)(admin_boundary_entity_1.AdminBoundary)), __param(3, (0, typeorm_1.InjectRepository)(admin_boundary_entity_1.AdminBoundary)),
__metadata("design:paramtypes", [typeorm_2.DataSource, __metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.DataSource !== "undefined" && typeorm_2.DataSource) === "function" ? _a : Object, typeof (_b = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _b : Object, typeof (_c = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _c : Object, typeof (_d = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _d : Object])
typeorm_2.Repository,
typeorm_2.Repository,
typeorm_2.Repository])
], AdministrativeLinkingService); ], AdministrativeLinkingService);
//# sourceMappingURL=administrative-linking.service.js.map //# sourceMappingURL=administrative-linking.service.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,21 @@
import { BasePlace } from './base-place.entity';
export declare enum CandidateStatus {
PENDING = "PENDING",
APPROVED = "APPROVED",
REJECTED = "REJECTED"
}
export declare enum CountryCode {
JORDAN = "JORDAN",
SYRIA = "SYRIA",
EGYPT = "EGYPT"
}
export declare class MapCandidate extends BasePlace {
status: CandidateStatus;
submittedBy: string;
rejectionReason: string;
country: CountryCode;
metadata: any;
verified_name: string;
confidence_score: number;
verification_metadata: any;
}
@@ -0,0 +1,84 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MapCandidate = exports.CountryCode = exports.CandidateStatus = void 0;
const typeorm_1 = require("typeorm");
const base_place_entity_1 = require("./base-place.entity");
var CandidateStatus;
(function (CandidateStatus) {
CandidateStatus["PENDING"] = "PENDING";
CandidateStatus["APPROVED"] = "APPROVED";
CandidateStatus["REJECTED"] = "REJECTED";
})(CandidateStatus || (exports.CandidateStatus = CandidateStatus = {}));
var CountryCode;
(function (CountryCode) {
CountryCode["JORDAN"] = "JORDAN";
CountryCode["SYRIA"] = "SYRIA";
CountryCode["EGYPT"] = "EGYPT";
})(CountryCode || (exports.CountryCode = CountryCode = {}));
let MapCandidate = class MapCandidate extends base_place_entity_1.BasePlace {
status;
submittedBy;
rejectionReason;
country;
metadata;
verified_name;
confidence_score;
verification_metadata;
};
exports.MapCandidate = MapCandidate;
__decorate([
(0, typeorm_1.Column)({
type: 'enum',
enum: CandidateStatus,
default: CandidateStatus.PENDING
}),
(0, typeorm_1.Index)(),
__metadata("design:type", String)
], MapCandidate.prototype, "status", void 0);
__decorate([
(0, typeorm_1.Column)({ nullable: true }),
(0, typeorm_1.Index)(),
__metadata("design:type", String)
], MapCandidate.prototype, "submittedBy", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'text', nullable: true }),
__metadata("design:type", String)
], MapCandidate.prototype, "rejectionReason", void 0);
__decorate([
(0, typeorm_1.Column)({
type: 'enum',
enum: CountryCode,
default: CountryCode.JORDAN
}),
(0, typeorm_1.Index)(),
__metadata("design:type", String)
], MapCandidate.prototype, "country", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'jsonb', nullable: true }),
__metadata("design:type", Object)
], MapCandidate.prototype, "metadata", void 0);
__decorate([
(0, typeorm_1.Column)({ nullable: true }),
__metadata("design:type", String)
], MapCandidate.prototype, "verified_name", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'int', default: 0 }),
__metadata("design:type", Number)
], MapCandidate.prototype, "confidence_score", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'jsonb', nullable: true }),
__metadata("design:type", Object)
], MapCandidate.prototype, "verification_metadata", void 0);
exports.MapCandidate = MapCandidate = __decorate([
(0, typeorm_1.Entity)('map_candidates')
], MapCandidate);
//# sourceMappingURL=map-candidate.entity.js.map
@@ -0,0 +1 @@
{"version":3,"file":"map-candidate.entity.js","sourceRoot":"","sources":["../../../src/geocoding/entities/map-candidate.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAAgD;AAChD,2DAAgD;AAEhD,IAAY,eAIX;AAJD,WAAY,eAAe;IACzB,sCAAmB,CAAA;IACnB,wCAAqB,CAAA;IACrB,wCAAqB,CAAA;AACvB,CAAC,EAJW,eAAe,+BAAf,eAAe,QAI1B;AAED,IAAY,WAIX;AAJD,WAAY,WAAW;IACrB,gCAAiB,CAAA;IACjB,8BAAe,CAAA;IACf,8BAAe,CAAA;AACjB,CAAC,EAJW,WAAW,2BAAX,WAAW,QAItB;AAGM,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,6BAAS;IAOzC,MAAM,CAAkB;IAIxB,WAAW,CAAS;IAGpB,eAAe,CAAS;IAQxB,OAAO,CAAc;IAGrB,QAAQ,CAAM;IAGd,aAAa,CAAS;IAGtB,gBAAgB,CAAS;IAGzB,qBAAqB,CAAM;CAC5B,CAAA;AAnCY,oCAAY;AAOvB;IANC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,eAAe,CAAC,OAAO;KACjC,CAAC;IACD,IAAA,eAAK,GAAE;;4CACgB;AAIxB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,eAAK,GAAE;;iDACY;AAGpB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;qDACjB;AAQxB;IANC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,WAAW,CAAC,MAAM;KAC5B,CAAC;IACD,IAAA,eAAK,GAAE;;6CACa;AAGrB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;8CAC5B;AAGd;IADC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mDACL;AAGtB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;sDACX;AAGzB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;2DACf;uBAlChB,YAAY;IADxB,IAAA,gBAAM,EAAC,gBAAgB,CAAC;GACZ,YAAY,CAmCxB"}
+2 -1
View File
@@ -12,6 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); } return function (target, key) { decorator(target, key, paramIndex); }
}; };
var GeocodingInitService_1; var GeocodingInitService_1;
var _a;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.GeocodingInitService = void 0; exports.GeocodingInitService = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
@@ -99,6 +100,6 @@ exports.GeocodingInitService = GeocodingInitService;
exports.GeocodingInitService = GeocodingInitService = GeocodingInitService_1 = __decorate([ exports.GeocodingInitService = GeocodingInitService = GeocodingInitService_1 = __decorate([
(0, common_1.Injectable)(), (0, common_1.Injectable)(),
__param(0, (0, typeorm_1.InjectRepository)(place_syria_entity_1.PlaceSyria)), __param(0, (0, typeorm_1.InjectRepository)(place_syria_entity_1.PlaceSyria)),
__metadata("design:paramtypes", [typeorm_2.Repository]) __metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object])
], GeocodingInitService); ], GeocodingInitService);
//# sourceMappingURL=geocoding-init.service.js.map //# sourceMappingURL=geocoding-init.service.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"geocoding-init.service.js","sourceRoot":"","sources":["../../src/geocoding/geocoding-init.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAkE;AAClE,6CAAmD;AACnD,qCAAqC;AACrC,sEAA2D;AAGpD,IAAM,oBAAoB,4BAA1B,MAAM,oBAAoB;IAKZ;IAJF,MAAM,GAAG,IAAI,eAAM,CAAC,sBAAoB,CAAC,IAAI,CAAC,CAAC;IAEhE,YAEmB,IAA4B;QAA5B,SAAI,GAAJ,IAAI,CAAwB;IAC5C,CAAC;IAEJ,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;QACnE,IAAI,CAAC;YAEH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACjE,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YAGjE,MAAM,MAAM,GAAG,CAAC,eAAe,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;YACjE,MAAM,aAAa,GAAG;gBACpB,EAAE,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,EAAE;gBACjD,EAAE,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE,aAAa,EAAE;gBAC9C,EAAE,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE,iBAAiB,EAAE;gBAClD,EAAE,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,iBAAiB,EAAE;aACpD,CAAC;YAEF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;oBACpC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;;wFAGwD,KAAK,wBAAwB,OAAO,CAAC,GAAG;8BAClG,KAAK,kBAAkB,OAAO,CAAC,GAAG,OAAO,OAAO,CAAC,GAAG;;;WAGvE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAGD,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;OAiBrB,CAAC,CAAC;YAEH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;OAKrB,CAAC,CAAC;YAGH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;OAKrB,CAAC,CAAC;YAEH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;OAKrB,CAAC,CAAC;YAGH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,+FAA+F,CAAC,CAAC;YACvH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,6FAA6F,CAAC,CAAC;YAGrH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,qIAAqI,CAAC,CAAC;YAC7J,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,mIAAmI,CAAC,CAAC;YAE3J,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,6FAA6F,CAAC,CAAC;QACjH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mDAAmD,EAAE,GAAG,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;CACF,CAAA;AA5FY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,0BAAgB,EAAC,+BAAU,CAAC,CAAA;qCACN,oBAAU;GALxB,oBAAoB,CA4FhC"} {"version":3,"file":"geocoding-init.service.js","sourceRoot":"","sources":["../../src/geocoding/geocoding-init.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,2CAAkE;AAClE,6CAAmD;AACnD,qCAAqC;AACrC,sEAA2D;AAGpD,IAAM,oBAAoB,4BAA1B,MAAM,oBAAoB;IAKZ;IAJF,MAAM,GAAG,IAAI,eAAM,CAAC,sBAAoB,CAAC,IAAI,CAAC,CAAC;IAEhE,YAEmB,IAA4B;QAA5B,SAAI,GAAJ,IAAI,CAAwB;IAC5C,CAAC;IAEJ,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;QACnE,IAAI,CAAC;YAEH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YACjE,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;YAGjE,MAAM,MAAM,GAAG,CAAC,eAAe,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;YACjE,MAAM,aAAa,GAAG;gBACpB,EAAE,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE,gBAAgB,EAAE;gBACjD,EAAE,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE,aAAa,EAAE;gBAC9C,EAAE,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE,iBAAiB,EAAE;gBAClD,EAAE,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,iBAAiB,EAAE;aACpD,CAAC;YAEF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;oBACpC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;;wFAGwD,KAAK,wBAAwB,OAAO,CAAC,GAAG;8BAClG,KAAK,kBAAkB,OAAO,CAAC,GAAG,OAAO,OAAO,CAAC,GAAG;;;WAGvE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAGD,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;OAiBrB,CAAC,CAAC;YAEH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;OAKrB,CAAC,CAAC;YAGH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;OAKrB,CAAC,CAAC;YAEH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;;;;OAKrB,CAAC,CAAC;YAGH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,+FAA+F,CAAC,CAAC;YACvH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,6FAA6F,CAAC,CAAC;YAGrH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,qIAAqI,CAAC,CAAC;YAC7J,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,mIAAmI,CAAC,CAAC;YAE3J,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,6FAA6F,CAAC,CAAC;QACjH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mDAAmD,EAAE,GAAG,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;CACF,CAAA;AA5FY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,0BAAgB,EAAC,+BAAU,CAAC,CAAA;yDACN,oBAAU,oBAAV,oBAAU;GALxB,oBAAoB,CA4FhC"}
+19 -23
View File
@@ -2,6 +2,7 @@ import { GeocodingService } from './geocoding.service';
import { AdminBoundariesService } from './admin-boundaries.service'; import { AdminBoundariesService } from './admin-boundaries.service';
import { JordanResearchService } from './jordan-research.service'; import { JordanResearchService } from './jordan-research.service';
import { AdministrativeLinkingService } from './administrative-linking.service'; import { AdministrativeLinkingService } from './administrative-linking.service';
import { MapRefinementService } from './map-refinement.service';
import { SearchQueryDto } from './dto/search-query.dto'; import { SearchQueryDto } from './dto/search-query.dto';
import { ReverseGeocodeDto } from './dto/reverse-geocode.dto'; import { ReverseGeocodeDto } from './dto/reverse-geocode.dto';
export declare class GeocodingController { export declare class GeocodingController {
@@ -9,38 +10,33 @@ export declare class GeocodingController {
private readonly adminBoundariesService; private readonly adminBoundariesService;
private readonly jordanResearchService; private readonly jordanResearchService;
private readonly adminLinkingService; private readonly adminLinkingService;
constructor(geocodingService: GeocodingService, adminBoundariesService: AdminBoundariesService, jordanResearchService: JordanResearchService, adminLinkingService: AdministrativeLinkingService); private readonly refinementService;
constructor(geocodingService: GeocodingService, adminBoundariesService: AdminBoundariesService, jordanResearchService: JordanResearchService, adminLinkingService: AdministrativeLinkingService, refinementService: MapRefinementService);
search(queryDto: SearchQueryDto): Promise<{ search(queryDto: SearchQueryDto): Promise<{
results: any; results: any;
source: string; source: string;
did_you_mean?: undefined;
} | {
results: never[];
did_you_mean: any;
source?: undefined;
} | { } | {
results: any[]; results: any[];
source?: undefined; source?: undefined;
did_you_mean?: undefined;
}>; }>;
reverse(reverseDto: ReverseGeocodeDto): Promise<any>; autocomplete(q: string, country?: string): Promise<{
addPlace(placeData: any): Promise<{ results: any;
latitude: number;
longitude: number;
location: string;
id: number;
name: string;
name_ar: string;
name_en: string;
address: string;
category: string;
neighbourhood: string;
city: string;
description: string;
created_at: Date;
source: string; source: string;
governorate_id: number; } | {
district_id: number; results: any;
sub_district_id: number; source?: undefined;
neighborhood_id: number;
}>; }>;
reverse(reverseDto: ReverseGeocodeDto): Promise<any[]>;
addPlace(req: any, placeData: any): Promise<import("./entities/map-candidate.entity").MapCandidate>;
deletePlace(country: string, name?: string, id?: string): Promise<{ deletePlace(country: string, name?: string, id?: string): Promise<{
success: boolean; success: boolean;
affected: number | null | undefined; affected: any;
}>; }>;
upsertPlace(placeData: any): Promise<{ upsertPlace(placeData: any): Promise<{
id: any; id: any;
@@ -54,7 +50,7 @@ export declare class GeocodingController {
created: number; created: number;
updated: number; updated: number;
}>; }>;
getPlaces(limit?: string): Promise<(import("./entities/place-syria.entity").PlaceSyria | import("./entities/place-jordan.entity").PlaceJordan | import("./entities/place-egypt.entity").PlaceEgypt)[]>; getPlaces(limit?: string): Promise<any[]>;
getGeoJSON(): Promise<{ getGeoJSON(): Promise<{
type: string; type: string;
features: any; features: any;
@@ -72,7 +68,7 @@ export declare class GeocodingController {
osm: any; osm: any;
overture: any; overture: any;
wikidata: any; wikidata: any;
static_files: {}; static_files: any;
hdx: string; hdx: string;
gadm: string; gadm: string;
}; };
+37 -7
View File
@@ -19,7 +19,9 @@ const geocoding_service_1 = require("./geocoding.service");
const admin_boundaries_service_1 = require("./admin-boundaries.service"); const admin_boundaries_service_1 = require("./admin-boundaries.service");
const jordan_research_service_1 = require("./jordan-research.service"); const jordan_research_service_1 = require("./jordan-research.service");
const administrative_linking_service_1 = require("./administrative-linking.service"); const administrative_linking_service_1 = require("./administrative-linking.service");
const map_refinement_service_1 = require("./map-refinement.service");
const api_key_guard_1 = require("../common/guards/api-key.guard"); const api_key_guard_1 = require("../common/guards/api-key.guard");
const admin_guard_1 = require("../common/guards/admin.guard");
const rate_limiter_guard_1 = require("../common/guards/rate-limiter.guard"); const rate_limiter_guard_1 = require("../common/guards/rate-limiter.guard");
const search_query_dto_1 = require("./dto/search-query.dto"); const search_query_dto_1 = require("./dto/search-query.dto");
const reverse_geocode_dto_1 = require("./dto/reverse-geocode.dto"); const reverse_geocode_dto_1 = require("./dto/reverse-geocode.dto");
@@ -28,22 +30,30 @@ let GeocodingController = class GeocodingController {
adminBoundariesService; adminBoundariesService;
jordanResearchService; jordanResearchService;
adminLinkingService; adminLinkingService;
constructor(geocodingService, adminBoundariesService, jordanResearchService, adminLinkingService) { refinementService;
constructor(geocodingService, adminBoundariesService, jordanResearchService, adminLinkingService, refinementService) {
this.geocodingService = geocodingService; this.geocodingService = geocodingService;
this.adminBoundariesService = adminBoundariesService; this.adminBoundariesService = adminBoundariesService;
this.jordanResearchService = jordanResearchService; this.jordanResearchService = jordanResearchService;
this.adminLinkingService = adminLinkingService; this.adminLinkingService = adminLinkingService;
this.refinementService = refinementService;
} }
async search(queryDto) { async search(queryDto) {
const { q, lat, lng, radius, country } = queryDto; const { q, lat, lng, radius, country } = queryDto;
return this.geocodingService.searchPlaces(q, lat, lng, radius, country); return this.geocodingService.searchPlaces(q, lat, lng, radius, country);
} }
async autocomplete(q, country) {
if (!q || q.trim().length < 2)
return { results: [] };
return this.geocodingService.autocomplete(q, country);
}
async reverse(reverseDto) { async reverse(reverseDto) {
const { lat, lng } = reverseDto; const { lat, lng } = reverseDto;
return this.geocodingService.reverseGeocode(lat, lng); return this.geocodingService.reverseGeocode(lat, lng);
} }
async addPlace(placeData) { async addPlace(req, placeData) {
return this.geocodingService.addPlace(placeData); const userId = req.user?.uid || req.tenant?.id || 'api_key_user';
return this.refinementService.suggestPlace(placeData, userId);
} }
async deletePlace(country, name, id) { async deletePlace(country, name, id) {
if (id) { if (id) {
@@ -91,6 +101,17 @@ __decorate([
__metadata("design:paramtypes", [search_query_dto_1.SearchQueryDto]), __metadata("design:paramtypes", [search_query_dto_1.SearchQueryDto]),
__metadata("design:returntype", Promise) __metadata("design:returntype", Promise)
], GeocodingController.prototype, "search", null); ], GeocodingController.prototype, "search", null);
__decorate([
(0, common_1.Get)('autocomplete'),
(0, swagger_1.ApiOperation)({ summary: 'Fast autocomplete for live typing' }),
(0, swagger_1.ApiQuery)({ name: 'q', required: true }),
(0, swagger_1.ApiQuery)({ name: 'country', required: false }),
__param(0, (0, common_1.Query)('q')),
__param(1, (0, common_1.Query)('country')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, String]),
__metadata("design:returntype", Promise)
], GeocodingController.prototype, "autocomplete", null);
__decorate([ __decorate([
(0, common_1.Get)('reverse'), (0, common_1.Get)('reverse'),
(0, swagger_1.ApiOperation)({ summary: 'Reverse Geocoding (Lat/Lng to Address)' }), (0, swagger_1.ApiOperation)({ summary: 'Reverse Geocoding (Lat/Lng to Address)' }),
@@ -101,14 +122,16 @@ __decorate([
], GeocodingController.prototype, "reverse", null); ], GeocodingController.prototype, "reverse", null);
__decorate([ __decorate([
(0, common_1.Post)('places'), (0, common_1.Post)('places'),
(0, swagger_1.ApiOperation)({ summary: 'Add a new location (User Submitted)' }), (0, swagger_1.ApiOperation)({ summary: 'Add a new location (User Submitted - Goes to Audit)' }),
__param(0, (0, common_1.Body)()), __param(0, (0, common_1.Req)()),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function), __metadata("design:type", Function),
__metadata("design:paramtypes", [Object]), __metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise) __metadata("design:returntype", Promise)
], GeocodingController.prototype, "addPlace", null); ], GeocodingController.prototype, "addPlace", null);
__decorate([ __decorate([
(0, common_1.Delete)('places'), (0, common_1.Delete)('places'),
(0, common_1.UseGuards)(admin_guard_1.AdminGuard),
(0, swagger_1.ApiOperation)({ summary: 'Delete a place by name or ID' }), (0, swagger_1.ApiOperation)({ summary: 'Delete a place by name or ID' }),
(0, swagger_1.ApiQuery)({ name: 'name', required: false }), (0, swagger_1.ApiQuery)({ name: 'name', required: false }),
(0, swagger_1.ApiQuery)({ name: 'id', required: false, type: Number }), (0, swagger_1.ApiQuery)({ name: 'id', required: false, type: Number }),
@@ -122,6 +145,7 @@ __decorate([
], GeocodingController.prototype, "deletePlace", null); ], GeocodingController.prototype, "deletePlace", null);
__decorate([ __decorate([
(0, common_1.Post)('upsert-place'), (0, common_1.Post)('upsert-place'),
(0, common_1.UseGuards)(admin_guard_1.AdminGuard),
(0, swagger_1.ApiOperation)({ summary: 'Add or Update a location (Automated Scraper)' }), (0, swagger_1.ApiOperation)({ summary: 'Add or Update a location (Automated Scraper)' }),
__param(0, (0, common_1.Body)()), __param(0, (0, common_1.Body)()),
__metadata("design:type", Function), __metadata("design:type", Function),
@@ -130,6 +154,7 @@ __decorate([
], GeocodingController.prototype, "upsertPlace", null); ], GeocodingController.prototype, "upsertPlace", null);
__decorate([ __decorate([
(0, common_1.Post)('upsert-batch'), (0, common_1.Post)('upsert-batch'),
(0, common_1.UseGuards)(admin_guard_1.AdminGuard),
(0, swagger_1.ApiOperation)({ summary: 'Add or Update multiple locations in bulk' }), (0, swagger_1.ApiOperation)({ summary: 'Add or Update multiple locations in bulk' }),
__param(0, (0, common_1.Body)()), __param(0, (0, common_1.Body)()),
__metadata("design:type", Function), __metadata("design:type", Function),
@@ -153,6 +178,7 @@ __decorate([
], GeocodingController.prototype, "getGeoJSON", null); ], GeocodingController.prototype, "getGeoJSON", null);
__decorate([ __decorate([
(0, common_1.Post)('import-boundaries'), (0, common_1.Post)('import-boundaries'),
(0, common_1.UseGuards)(admin_guard_1.AdminGuard),
(0, swagger_1.ApiOperation)({ summary: 'Import administrative boundaries from a local GeoJSON file on the server' }), (0, swagger_1.ApiOperation)({ summary: 'Import administrative boundaries from a local GeoJSON file on the server' }),
(0, swagger_1.ApiQuery)({ name: 'country', required: true }), (0, swagger_1.ApiQuery)({ name: 'country', required: true }),
(0, swagger_1.ApiQuery)({ name: 'filePath', required: true }), (0, swagger_1.ApiQuery)({ name: 'filePath', required: true }),
@@ -171,6 +197,7 @@ __decorate([
], GeocodingController.prototype, "zarqaResearch", null); ], GeocodingController.prototype, "zarqaResearch", null);
__decorate([ __decorate([
(0, common_1.Post)('admin/sync-neighborhoods'), (0, common_1.Post)('admin/sync-neighborhoods'),
(0, common_1.UseGuards)(admin_guard_1.AdminGuard),
(0, swagger_1.ApiOperation)({ summary: 'Sync neighborhood points from OSM for a bbox' }), (0, swagger_1.ApiOperation)({ summary: 'Sync neighborhood points from OSM for a bbox' }),
(0, swagger_1.ApiQuery)({ name: 'bbox', required: false }), (0, swagger_1.ApiQuery)({ name: 'bbox', required: false }),
(0, swagger_1.ApiQuery)({ name: 'country', required: false, enum: ['jordan', 'syria', 'egypt'] }), (0, swagger_1.ApiQuery)({ name: 'country', required: false, enum: ['jordan', 'syria', 'egypt'] }),
@@ -182,6 +209,7 @@ __decorate([
], GeocodingController.prototype, "syncNeighborhoods", null); ], GeocodingController.prototype, "syncNeighborhoods", null);
__decorate([ __decorate([
(0, common_1.Post)('admin/generate-voronoi'), (0, common_1.Post)('admin/generate-voronoi'),
(0, common_1.UseGuards)(admin_guard_1.AdminGuard),
(0, swagger_1.ApiOperation)({ summary: 'Generate Voronoi polygons for neighborhoods' }), (0, swagger_1.ApiOperation)({ summary: 'Generate Voronoi polygons for neighborhoods' }),
(0, swagger_1.ApiQuery)({ name: 'country', required: false, enum: ['jordan', 'syria', 'egypt'] }), (0, swagger_1.ApiQuery)({ name: 'country', required: false, enum: ['jordan', 'syria', 'egypt'] }),
__param(0, (0, common_1.Query)('country')), __param(0, (0, common_1.Query)('country')),
@@ -191,6 +219,7 @@ __decorate([
], GeocodingController.prototype, "generateVoronoi", null); ], GeocodingController.prototype, "generateVoronoi", null);
__decorate([ __decorate([
(0, common_1.Post)('admin/link-places'), (0, common_1.Post)('admin/link-places'),
(0, common_1.UseGuards)(admin_guard_1.AdminGuard),
(0, swagger_1.ApiOperation)({ summary: 'Link places to administrative hierarchy' }), (0, swagger_1.ApiOperation)({ summary: 'Link places to administrative hierarchy' }),
(0, swagger_1.ApiQuery)({ name: 'country', required: true, enum: ['jordan', 'syria', 'egypt'] }), (0, swagger_1.ApiQuery)({ name: 'country', required: true, enum: ['jordan', 'syria', 'egypt'] }),
__param(0, (0, common_1.Query)('country')), __param(0, (0, common_1.Query)('country')),
@@ -206,6 +235,7 @@ exports.GeocodingController = GeocodingController = __decorate([
__metadata("design:paramtypes", [geocoding_service_1.GeocodingService, __metadata("design:paramtypes", [geocoding_service_1.GeocodingService,
admin_boundaries_service_1.AdminBoundariesService, admin_boundaries_service_1.AdminBoundariesService,
jordan_research_service_1.JordanResearchService, jordan_research_service_1.JordanResearchService,
administrative_linking_service_1.AdministrativeLinkingService]) administrative_linking_service_1.AdministrativeLinkingService,
map_refinement_service_1.MapRefinementService])
], GeocodingController); ], GeocodingController);
//# sourceMappingURL=geocoding.controller.js.map //# sourceMappingURL=geocoding.controller.js.map
File diff suppressed because one or more lines are too long
+11 -4
View File
@@ -56,8 +56,12 @@ const jordan_research_service_1 = require("./jordan-research.service");
const administrative_linking_service_1 = require("./administrative-linking.service"); const administrative_linking_service_1 = require("./administrative-linking.service");
const neighborhood_point_entity_1 = require("./entities/neighborhood-point.entity"); const neighborhood_point_entity_1 = require("./entities/neighborhood-point.entity");
const neighborhood_polygon_entity_1 = require("./entities/neighborhood-polygon.entity"); const neighborhood_polygon_entity_1 = require("./entities/neighborhood-polygon.entity");
const map_candidate_entity_1 = require("./entities/map-candidate.entity");
const map_refinement_service_1 = require("./map-refinement.service");
const map_refinement_controller_1 = require("./map-refinement.controller");
const cache_manager_1 = require("@nestjs/cache-manager"); const cache_manager_1 = require("@nestjs/cache-manager");
const redisStore = __importStar(require("cache-manager-redis-store")); const redisStore = __importStar(require("cache-manager-redis-store"));
const index_refresh_service_1 = require("./index-refresh.service");
let GeocodingModule = class GeocodingModule { let GeocodingModule = class GeocodingModule {
}; };
exports.GeocodingModule = GeocodingModule; exports.GeocodingModule = GeocodingModule;
@@ -72,7 +76,8 @@ exports.GeocodingModule = GeocodingModule = __decorate([
osm_point_with_area_entity_1.OsmPointWithArea, osm_point_with_area_entity_1.OsmPointWithArea,
admin_boundary_entity_1.AdminBoundary, admin_boundary_entity_1.AdminBoundary,
neighborhood_point_entity_1.NeighborhoodPoint, neighborhood_point_entity_1.NeighborhoodPoint,
neighborhood_polygon_entity_1.NeighborhoodPolygon neighborhood_polygon_entity_1.NeighborhoodPolygon,
map_candidate_entity_1.MapCandidate
]), ]),
cache_manager_1.CacheModule.register({ cache_manager_1.CacheModule.register({
store: redisStore, store: redisStore,
@@ -81,15 +86,17 @@ exports.GeocodingModule = GeocodingModule = __decorate([
ttl: 3600, ttl: 3600,
}), }),
], ],
controllers: [geocoding_controller_1.GeocodingController], controllers: [geocoding_controller_1.GeocodingController, map_refinement_controller_1.MapRefinementController],
providers: [ providers: [
geocoding_service_1.GeocodingService, geocoding_service_1.GeocodingService,
geocoding_init_service_1.GeocodingInitService, geocoding_init_service_1.GeocodingInitService,
admin_boundaries_service_1.AdminBoundariesService, admin_boundaries_service_1.AdminBoundariesService,
jordan_research_service_1.JordanResearchService, jordan_research_service_1.JordanResearchService,
administrative_linking_service_1.AdministrativeLinkingService administrative_linking_service_1.AdministrativeLinkingService,
map_refinement_service_1.MapRefinementService,
index_refresh_service_1.IndexRefreshService
], ],
exports: [geocoding_service_1.GeocodingService], exports: [geocoding_service_1.GeocodingService, map_refinement_service_1.MapRefinementService],
}) })
], GeocodingModule); ], GeocodingModule);
//# sourceMappingURL=geocoding.module.js.map //# sourceMappingURL=geocoding.module.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"geocoding.module.js","sourceRoot":"","sources":["../../src/geocoding/geocoding.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAwC;AACxC,6CAAgD;AAChD,2DAAuD;AACvD,qEAAgE;AAChE,iEAA6D;AAC7D,sEAA2D;AAC3D,wEAA6D;AAC7D,sEAA2D;AAC3D,gEAAqD;AACrD,sFAAyE;AACzE,4EAAiE;AACjE,yEAAoE;AACpE,uEAAkE;AAClE,qFAAgF;AAChF,oFAAyE;AACzE,wFAA6E;AAC7E,yDAAoD;AACpD,sEAAwD;AA+BjD,IAAM,eAAe,GAArB,MAAM,eAAe;CAAG,CAAA;AAAlB,0CAAe;0BAAf,eAAe;IA7B3B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,uBAAa,CAAC,UAAU,CAAC;gBACvB,+BAAU;gBACV,iCAAW;gBACX,+BAAU;gBACV,yBAAO;gBACP,6CAAgB;gBAChB,qCAAa;gBACb,6CAAiB;gBACjB,iDAAmB;aACpB,CAAC;YACF,2BAAW,CAAC,QAAQ,CAAC;gBACnB,KAAK,EAAE,UAAU;gBACjB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,WAAW;gBAC3C,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,MAAM,EAAE,EAAE,CAAC;gBACpD,GAAG,EAAE,IAAI;aACV,CAAC;SACH;QACD,WAAW,EAAE,CAAC,0CAAmB,CAAC;QAClC,SAAS,EAAE;YACT,oCAAgB;YAChB,6CAAoB;YACpB,iDAAsB;YACtB,+CAAqB;YACrB,6DAA4B;SAC7B;QACD,OAAO,EAAE,CAAC,oCAAgB,CAAC;KAC5B,CAAC;GACW,eAAe,CAAG"} {"version":3,"file":"geocoding.module.js","sourceRoot":"","sources":["../../src/geocoding/geocoding.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAwC;AACxC,6CAAgD;AAChD,2DAAuD;AACvD,qEAAgE;AAChE,iEAA6D;AAC7D,sEAA2D;AAC3D,wEAA6D;AAC7D,sEAA2D;AAC3D,gEAAqD;AACrD,sFAAyE;AACzE,4EAAiE;AACjE,yEAAoE;AACpE,uEAAkE;AAClE,qFAAgF;AAChF,oFAAyE;AACzE,wFAA6E;AAC7E,0EAA+D;AAC/D,qEAAgE;AAChE,2EAAsE;AACtE,yDAAoD;AACpD,sEAAwD;AACxD,mEAA8D;AAkCvD,IAAM,eAAe,GAArB,MAAM,eAAe;CAAG,CAAA;AAAlB,0CAAe;0BAAf,eAAe;IAhC3B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,uBAAa,CAAC,UAAU,CAAC;gBACvB,+BAAU;gBACV,iCAAW;gBACX,+BAAU;gBACV,yBAAO;gBACP,6CAAgB;gBAChB,qCAAa;gBACb,6CAAiB;gBACjB,iDAAmB;gBACnB,mCAAY;aACb,CAAC;YACF,2BAAW,CAAC,QAAQ,CAAC;gBACnB,KAAK,EAAE,UAAU;gBACjB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,WAAW;gBAC3C,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,MAAM,EAAE,EAAE,CAAC;gBACpD,GAAG,EAAE,IAAI;aACV,CAAC;SACH;QACD,WAAW,EAAE,CAAC,0CAAmB,EAAE,mDAAuB,CAAC;QAC3D,SAAS,EAAE;YACT,oCAAgB;YAChB,6CAAoB;YACpB,iDAAsB;YACtB,+CAAqB;YACrB,6DAA4B;YAC5B,6CAAoB;YACpB,2CAAmB;SACpB;QACD,OAAO,EAAE,CAAC,oCAAgB,EAAE,6CAAoB,CAAC;KAClD,CAAC;GACW,eAAe,CAAG"}
+17 -22
View File
@@ -22,33 +22,28 @@ export declare class GeocodingService {
searchPlaces(query: string, lat?: number, lon?: number, radius?: number, country?: string): Promise<{ searchPlaces(query: string, lat?: number, lon?: number, radius?: number, country?: string): Promise<{
results: any; results: any;
source: string; source: string;
did_you_mean?: undefined;
} | {
results: never[];
did_you_mean: any;
source?: undefined;
} | { } | {
results: any[]; results: any[];
source?: undefined; source?: undefined;
did_you_mean?: undefined;
}>; }>;
private formatResults; private formatResults;
private getRepoByTableName; private getRepoByTableName;
reverseGeocode(lat: number, lng: number): Promise<any>; private logFailedSearch;
addPlace(data: Partial<BasePlace>): Promise<{ autocomplete(query: string, country?: string): Promise<{
latitude: number; results: any;
longitude: number;
location: string;
id: number;
name: string;
name_ar: string;
name_en: string;
address: string;
category: string;
neighbourhood: string;
city: string;
description: string;
created_at: Date;
source: string; source: string;
governorate_id: number; } | {
district_id: number; results: any;
sub_district_id: number; source?: undefined;
neighborhood_id: number;
}>; }>;
reverseGeocode(lat: number, lng: number): Promise<any[]>;
addPlace(data: Partial<BasePlace>): Promise<any>;
upsertPlace(data: Partial<BasePlace>): Promise<{ upsertPlace(data: Partial<BasePlace>): Promise<{
id: any; id: any;
action: string; action: string;
@@ -59,18 +54,18 @@ export declare class GeocodingService {
created: number; created: number;
updated: number; updated: number;
}>; }>;
getRecentPlaces(limit?: number): Promise<(PlaceSyria | PlaceJordan | PlaceEgypt)[]>; getRecentPlaces(limit?: number): Promise<any[]>;
getAllPlacesGeoJSON(): Promise<{ getAllPlacesGeoJSON(): Promise<{
type: string; type: string;
features: any; features: any;
}>; }>;
deletePlacesByName(name: string, country: string): Promise<{ deletePlacesByName(name: string, country: string): Promise<{
success: boolean; success: boolean;
affected: number; affected: any;
}>; }>;
deletePlaceById(id: number, country: string): Promise<{ deletePlaceById(id: number, country: string): Promise<{
success: boolean; success: boolean;
affected: number | null | undefined; affected: any;
}>; }>;
private getRepoByCountry; private getRepoByCountry;
} }
+239 -51
View File
@@ -12,6 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); } return function (target, key) { decorator(target, key, paramIndex); }
}; };
var GeocodingService_1; var GeocodingService_1;
var _a, _b, _c, _d, _e;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.GeocodingService = void 0; exports.GeocodingService = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
@@ -73,9 +74,16 @@ let GeocodingService = GeocodingService_1 = class GeocodingService {
} }
async searchPlaces(query, lat, lon, radius = 20000, country) { async searchPlaces(query, lat, lon, radius = 20000, country) {
try { try {
const cleanQuery = query.trim(); let cleanQuery = query.trim();
if (!cleanQuery) if (!cleanQuery)
return { results: [] }; return { results: [] };
let relativePrefix = '';
const relativeQueryRegex = /^(قرب|بالقرب من|قريب من|عند|بجانب|جنب|حد|بجوار|مقابل|قبال|خلف|ورا|وراء)\s+(.+)$/i;
const match = cleanQuery.match(relativeQueryRegex);
if (match) {
relativePrefix = match[1];
cleanQuery = match[2];
}
const hasLocation = lat !== undefined && lon !== undefined; const hasLocation = lat !== undefined && lon !== undefined;
const geoSegment = hasLocation ? `${lat.toFixed(2)}_${lon.toFixed(2)}` : 'global'; const geoSegment = hasLocation ? `${lat.toFixed(2)}_${lon.toFixed(2)}` : 'global';
const cacheKey = `geo_search:${country || 'auto'}:${geoSegment}:${cleanQuery.toLowerCase()}`; const cacheKey = `geo_search:${country || 'auto'}:${geoSegment}:${cleanQuery.toLowerCase()}`;
@@ -83,56 +91,93 @@ let GeocodingService = GeocodingService_1 = class GeocodingService {
if (cached) if (cached)
return { results: cached, source: 'cache_hit' }; return { results: cached, source: 'cache_hit' };
let targetRegion = country?.toLowerCase() || this.identifyRegion(lat, lon); let targetRegion = country?.toLowerCase() || this.identifyRegion(lat, lon);
const primaryTables = targetRegion && ['syria', 'egypt', 'jordan'].includes(targetRegion) const [normalizedQueryRes] = await this.osmPointsRepository.query(`SELECT normalize_arabic($1) as nq`, [cleanQuery]);
? [`places_${targetRegion}`] : ['places_jordan', 'places_syria', 'places_egypt']; const normalizedQuery = normalizedQueryRes?.nq || cleanQuery.toLowerCase();
const queryPromises = []; let queryParams = [normalizedQuery];
primaryTables.forEach(tableName => { let locationCondition = '';
const repo = this.getRepoByTableName(tableName); if (hasLocation) {
queryPromises.push(repo.query(` locationCondition = `AND ST_DistanceSphere(location, ST_SetSRID(ST_MakePoint($3::float, $2::float), 4326)) <= $4`;
queryParams.push(lat, lon, radius);
}
let regionCondition = '';
if (targetRegion && ['syria', 'jordan', 'egypt'].includes(targetRegion)) {
regionCondition = `AND (region = '${targetRegion}' OR region = 'global')`;
}
const sqlQuery = `
SELECT SELECT
p.id, p.name, p.name_ar, p.name_en, p.category, id, name, name_ar, category,
n.name_ar as neighbourhood, d.name_ar as district, g.name_ar as governorate, '' as neighbourhood, '' as district, '' as governorate,
p.latitude, p.longitude, p.address, '${tableName.replace('places_', '')}' as region, 'user_place' as source, latitude, longitude, address, region, source, popularity_score,
CASE WHEN $2::float IS NOT NULL THEN ST_DistanceSphere(p.location, ST_SetSRID(ST_MakePoint($3::float, $2::float), 4326)) ELSE 0 END as distance, ${hasLocation ? 'ST_DistanceSphere(location, ST_SetSRID(ST_MakePoint($3::float, $2::float), 4326))' : '0'} as distance,
GREATEST(similarity(COALESCE(p.name_ar, ''), $1), similarity(COALESCE(p.name, ''), $1)) as relevance similarity(normalized_name, $1) as relevance
FROM ${tableName} p FROM unified_search_index
LEFT JOIN neighborhood_polygons n ON p.neighborhood_id = n.id WHERE normalized_name % $1
LEFT JOIN admin_boundaries d ON p.district_id = d.id ${locationCondition}
LEFT JOIN admin_boundaries g ON p.governorate_id = g.id ${regionCondition}
WHERE (p.name_ar % $1 OR p.name % $1) ORDER BY (normalized_name <-> $1) ASC
AND ($2::float IS NULL OR ST_DistanceSphere(p.location, ST_SetSRID(ST_MakePoint($3::float, $2::float), 4326)) <= $4) LIMIT 50
ORDER BY (p.name_ar <-> $1) ASC LIMIT 10 `;
`, [cleanQuery, lat || null, lon || null, radius])); const allResults = await Promise.race([
}); this.osmPointsRepository.query(sqlQuery, queryParams),
queryPromises.push(this.osmPointsRepository.query(`
SELECT
o.osm_id as id, o.name, o.name_ar, o.name_en, COALESCE(o.amenity, o.shop, 'place') as category,
o.latitude, o.longitude, o.addr_street as address, 'osm_global' as source,
CASE WHEN $2::float IS NOT NULL THEN ST_DistanceSphere(o.geom, ST_SetSRID(ST_MakePoint($3::float, $2::float), 4326)) ELSE 0 END as distance,
GREATEST(similarity(COALESCE(o.name, ''), $1), similarity(COALESCE(o.name_ar, ''), $1)) as relevance
FROM osm_points_with_area o
WHERE (o.name % $1 OR o.name_ar % $1)
AND ($2::float IS NULL OR ST_DistanceSphere(o.geom, ST_SetSRID(ST_MakePoint($3::float, $2::float), 4326)) <= $4)
ORDER BY (o.name <-> $1) ASC LIMIT 10
`, [cleanQuery, lat || null, lon || null, radius]));
const executionResults = await Promise.race([
Promise.allSettled(queryPromises),
new Promise((_, reject) => setTimeout(() => reject(new Error('QUERY_TIMEOUT')), this.DB_TIMEOUT_MS)) new Promise((_, reject) => setTimeout(() => reject(new Error('QUERY_TIMEOUT')), this.DB_TIMEOUT_MS))
]).catch(e => { ]).catch(e => {
this.logger.warn(`Search optimization threshold hit: ${e.message}`); this.logger.warn(`Search optimization threshold hit: ${e.message}`);
return []; return [];
}); });
let allResults = []; const formatted = this.formatResults(allResults, hasLocation, relativePrefix);
if (Array.isArray(executionResults)) { const placeIds = formatted.map(r => r.id);
executionResults.forEach(res => { if (placeIds.length > 0) {
if (res.status === 'fulfilled' && res.value) try {
allResults.push(...res.value); const gates = await this.osmPointsRepository.query(`SELECT place_id, gate_name_ar, gate_name_en, latitude, longitude, is_main_gate
FROM place_gates
WHERE place_id = ANY($1)`, [placeIds]);
if (gates.length > 0) {
formatted.forEach(r => {
const placeGates = gates.filter((g) => g.place_id === r.id).map((g) => ({
name_ar: g.gate_name_ar,
name_en: g.gate_name_en,
latitude: parseFloat(g.latitude),
longitude: parseFloat(g.longitude),
is_main_gate: g.is_main_gate
}));
if (placeGates.length > 0) {
r.gates = placeGates;
}
}); });
} }
const formatted = this.formatResults(allResults, hasLocation); }
catch (err) {
this.logger.warn('Failed to fetch POI gates, table might not exist yet.');
}
}
if (formatted.length > 0) { if (formatted.length > 0) {
await this.cacheManager.set(cacheKey, formatted, 3600000); await this.cacheManager.set(cacheKey, formatted, 3600000);
} }
else {
this.logFailedSearch(cleanQuery, normalizedQuery, targetRegion, lat, lon).catch(err => {
this.logger.error('Failed to log zero-result search:', err);
});
try {
const whereClause = regionCondition ? `WHERE ${regionCondition.substring(4)}` : '';
const fallbackQuery = `
SELECT name_ar, name, (normalized_name <-> $1) as dist
FROM unified_search_index
${whereClause}
ORDER BY normalized_name <-> $1 ASC
LIMIT 1
`;
const suggestions = await this.osmPointsRepository.query(fallbackQuery, [normalizedQuery]);
if (suggestions.length > 0 && suggestions[0].dist < 0.6) {
return {
results: [],
did_you_mean: suggestions[0].name_ar || suggestions[0].name
};
}
}
catch (err) {
this.logger.warn('Did You Mean fallback failed: ' + err.message);
}
}
return { results: formatted }; return { results: formatted };
} }
catch (e) { catch (e) {
@@ -140,12 +185,15 @@ let GeocodingService = GeocodingService_1 = class GeocodingService {
return { results: [] }; return { results: [] };
} }
} }
formatResults(results, hasLocation) { formatResults(results, hasLocation, relativePrefix = '') {
const seenStreets = new Set(); const seenStreets = new Set();
const maxPopularity = Math.max(...results.map(r => r.popularity_score || 10), 100);
return results return results
.map(r => { .map(r => {
const textScore = Number(r.relevance);
const popularityScore = (r.popularity_score || 10) / maxPopularity;
const proximityBonus = hasLocation ? Math.max(0, 1 - (Number(r.distance) / 10000)) : 0; const proximityBonus = hasLocation ? Math.max(0, 1 - (Number(r.distance) / 10000)) : 0;
const totalScore = (Number(r.relevance) * 0.7) + (proximityBonus * 0.3); const totalScore = (textScore * 0.5) + (popularityScore * 0.3) + (proximityBonus * 0.2);
return { ...r, totalScore }; return { ...r, totalScore };
}) })
.sort((a, b) => b.totalScore - a.totalScore) .sort((a, b) => b.totalScore - a.totalScore)
@@ -162,8 +210,12 @@ let GeocodingService = GeocodingService_1 = class GeocodingService {
.map(r => { .map(r => {
const addressParts = [r.neighbourhood, r.district, r.governorate].filter(Boolean); const addressParts = [r.neighbourhood, r.district, r.governorate].filter(Boolean);
const full_address = addressParts.length > 0 ? addressParts.join('، ') : (r.address || ''); const full_address = addressParts.length > 0 ? addressParts.join('، ') : (r.address || '');
const nameAr = r.name_ar || r.name;
const displayName = relativePrefix ? `${relativePrefix} ${nameAr}` : nameAr;
return { return {
...r, ...r,
name: displayName,
name_ar: displayName,
latitude: parseFloat(r.latitude), latitude: parseFloat(r.latitude),
longitude: parseFloat(r.longitude), longitude: parseFloat(r.longitude),
distance_km: r.distance ? (Number(r.distance) / 1000).toFixed(2) : null, distance_km: r.distance ? (Number(r.distance) / 1000).toFixed(2) : null,
@@ -179,11 +231,78 @@ let GeocodingService = GeocodingService_1 = class GeocodingService {
return this.placesJordanRepository; return this.placesJordanRepository;
return this.placesSyriaRepository; return this.placesSyriaRepository;
} }
async logFailedSearch(query, normalizedQuery, country, lat, lon) {
const q = `
INSERT INTO failed_searches (query_text, normalized_query, country, latitude, longitude)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (normalized_query, COALESCE(country, 'global'))
DO UPDATE SET search_count = failed_searches.search_count + 1, last_seen_at = CURRENT_TIMESTAMP;
`;
await this.osmPointsRepository.query(q, [query, normalizedQuery, country || null, lat || null, lon || null]);
}
async autocomplete(query, country) {
try {
let cleanQuery = query.trim();
if (cleanQuery.length < 2)
return { results: [] };
let relativePrefix = '';
const relativeQueryRegex = /^(قرب|بالقرب من|قريب من|عند|بجانب|جنب|حد|بجوار|مقابل|قبال|خلف|ورا|وراء)\s+(.+)$/i;
const match = cleanQuery.match(relativeQueryRegex);
if (match) {
relativePrefix = match[1];
cleanQuery = match[2];
if (cleanQuery.length < 2)
return { results: [] };
}
const targetRegion = country?.toLowerCase();
const cacheKey = `geo_auto:${targetRegion || 'auto'}:${cleanQuery.toLowerCase()}`;
const cached = await this.cacheManager.get(cacheKey);
if (cached)
return { results: cached, source: 'cache_hit' };
const [normalizedQueryRes] = await this.osmPointsRepository.query(`SELECT normalize_arabic($1) as nq`, [cleanQuery]);
const normalizedQuery = normalizedQueryRes?.nq || cleanQuery.toLowerCase();
let queryParams = [`${normalizedQuery}%`];
let regionCondition = '';
if (targetRegion && ['syria', 'jordan', 'egypt'].includes(targetRegion)) {
regionCondition = `AND (region = '${targetRegion}' OR region = 'global')`;
}
const sqlQuery = `
SELECT
id, name, name_ar, category, region, source, address
FROM unified_search_index
WHERE normalized_name LIKE $1
${regionCondition}
ORDER BY LENGTH(normalized_name) ASC
LIMIT 7
`;
const results = await this.osmPointsRepository.query(sqlQuery, queryParams);
const formatted = results.map(r => {
const nameAr = r.name_ar || r.name;
const displayName = relativePrefix ? `${relativePrefix} ${nameAr}` : nameAr;
return {
id: r.id,
name: displayName,
category: r.category,
region: r.region,
address: r.address
};
});
if (formatted.length > 0) {
await this.cacheManager.set(cacheKey, formatted, 3600000);
}
return { results: formatted };
}
catch (e) {
this.logger.error('Autocomplete failed:', e);
return { results: [] };
}
}
async reverseGeocode(lat, lng) { async reverseGeocode(lat, lng) {
try { try {
const repo = this.getRepositoryForCoords(lat, lng); const repo = this.getRepositoryForCoords(lat, lng);
const tableName = this.getTableNameForRepo(repo); const tableName = this.getTableNameForRepo(repo);
const query = ` const queryPromises = [];
queryPromises.push(repo.query(`
SELECT SELECT
p.id, p.name, p.name_ar, p.category, p.id, p.name, p.name_ar, p.category,
n.name_ar as neighbourhood, n.name_ar as neighbourhood,
@@ -196,9 +315,81 @@ let GeocodingService = GeocodingService_1 = class GeocodingService {
LEFT JOIN admin_boundaries d ON p.sub_district_id = d.id LEFT JOIN admin_boundaries d ON p.sub_district_id = d.id
LEFT JOIN admin_boundaries g ON p.governorate_id = g.id LEFT JOIN admin_boundaries g ON p.governorate_id = g.id
WHERE p.location IS NOT NULL WHERE p.location IS NOT NULL
ORDER BY p.location::geometry <-> ST_SetSRID(ST_MakePoint($1::float, $2::float), 4326) ASC LIMIT 3 ORDER BY p.location::geometry <-> ST_SetSRID(ST_MakePoint($1::float, $2::float), 4326) ASC LIMIT 5
`; `, [lng, lat]));
return await repo.query(query, [lng, lat]); queryPromises.push(repo.query(`
SELECT
o.osm_id::text as id, o.name, o.name_ar, COALESCE(o.amenity, o.shop, 'place') as category,
'' as neighbourhood, '' as district, '' as governorate,
o.latitude, o.longitude, o.addr_street as address, 'osm_global' as source,
ST_DistanceSphere(o.geom, ST_SetSRID(ST_MakePoint($1::float, $2::float), 4326)) as distance
FROM osm_points_with_area o
WHERE o.geom IS NOT NULL AND (o.name IS NOT NULL OR o.name_ar IS NOT NULL)
ORDER BY o.geom <-> ST_SetSRID(ST_MakePoint($1::float, $2::float), 4326) ASC LIMIT 5
`, [lng, lat]));
queryPromises.push(repo.query(`
SELECT
id::text, COALESCE(names->>'primary', names->>'common', 'Street') as name, COALESCE(names->>'primary', names->>'common', 'Street') as name_ar, 'street' as category,
'' as neighbourhood, '' as district, '' as governorate,
ST_Y(ST_Centroid(location))::text as latitude, ST_X(ST_Centroid(location))::text as longitude, '' as address, 'overture_global' as source,
ST_DistanceSphere(location, ST_SetSRID(ST_MakePoint($1::float, $2::float), 4326)) as distance
FROM overture_segment
WHERE location IS NOT NULL AND (names->>'primary' IS NOT NULL OR names->>'common' IS NOT NULL)
ORDER BY location <-> ST_SetSRID(ST_MakePoint($1::float, $2::float), 4326) ASC LIMIT 5
`, [lng, lat]));
queryPromises.push(repo.query(`
SELECT
id::text, COALESCE(names->>'primary', names->>'common', 'Building') as name, COALESCE(names->>'primary', names->>'common', 'Building') as name_ar, 'building' as category,
'' as neighbourhood, '' as district, '' as governorate,
ST_Y(ST_Centroid(location))::text as latitude, ST_X(ST_Centroid(location))::text as longitude, '' as address, 'overture_global' as source,
ST_DistanceSphere(location, ST_SetSRID(ST_MakePoint($1::float, $2::float), 4326)) as distance
FROM overture_building
WHERE location IS NOT NULL AND (names->>'primary' IS NOT NULL OR names->>'common' IS NOT NULL)
ORDER BY location <-> ST_SetSRID(ST_MakePoint($1::float, $2::float), 4326) ASC LIMIT 5
`, [lng, lat]));
queryPromises.push(repo.query(`
SELECT
id::text, COALESCE(names->>'primary', names->>'common', 'Place') as name, COALESCE(names->>'primary', names->>'common', 'Place') as name_ar, 'place' as category,
'' as neighbourhood, '' as district, '' as governorate,
ST_Y(ST_Centroid(location))::text as latitude, ST_X(ST_Centroid(location))::text as longitude, '' as address, 'overture_global' as source,
ST_DistanceSphere(location, ST_SetSRID(ST_MakePoint($1::float, $2::float), 4326)) as distance
FROM overture_place
WHERE location IS NOT NULL AND (names->>'primary' IS NOT NULL OR names->>'common' IS NOT NULL)
ORDER BY location <-> ST_SetSRID(ST_MakePoint($1::float, $2::float), 4326) ASC LIMIT 5
`, [lng, lat]));
const results = await Promise.allSettled(queryPromises);
let allResults = [];
results.forEach(res => {
if (res.status === 'fulfilled' && res.value)
allResults.push(...res.value);
});
return allResults
.sort((a, b) => Number(a.distance) - Number(b.distance))
.slice(0, 5)
.map(r => {
const distance = Number(r.distance);
const fullAddressParts = [r.name_ar || r.name, r.address, r.neighbourhood, r.district, r.governorate].filter(Boolean);
let humanReadable = r.name_ar || r.name;
if (distance <= 20) {
humanReadable = r.name_ar || r.name;
}
else if (distance <= 70 && r.category !== 'street') {
const streetName = r.address ? `، ${r.address}` : '';
humanReadable = `أمام ${r.name_ar || r.name}${streetName}`;
}
else if (r.category === 'street' || distance > 70) {
const streetPart = r.category === 'street' ? (r.name_ar || r.name) : (r.address || r.name_ar || r.name);
const districtPart = r.neighbourhood || r.district || '';
humanReadable = [streetPart, districtPart].filter(Boolean).join('، ');
}
return {
...r,
latitude: parseFloat(r.latitude),
longitude: parseFloat(r.longitude),
human_readable_address: humanReadable,
full_address: fullAddressParts.join('، ')
};
});
} }
catch (error) { catch (error) {
this.logger.error('Reverse geocoding error:', error); this.logger.error('Reverse geocoding error:', error);
@@ -259,6 +450,7 @@ let GeocodingService = GeocodingService_1 = class GeocodingService {
UNION ALL SELECT id::text, name_ar as name, category, latitude, longitude, address, 'user' as region FROM places_egypt UNION ALL SELECT id::text, name_ar as name, category, latitude, longitude, address, 'user' as region FROM places_egypt
UNION ALL SELECT id::text, COALESCE(names->>'primary', names->>'common', 'Building') as name, 'building' as category, ST_Y(ST_Centroid(location)) as latitude, ST_X(ST_Centroid(location)) as longitude, '' as address, 'overture' as region FROM overture_building WHERE names->>'primary' IS NOT NULL LIMIT 500 UNION ALL SELECT id::text, COALESCE(names->>'primary', names->>'common', 'Building') as name, 'building' as category, ST_Y(ST_Centroid(location)) as latitude, ST_X(ST_Centroid(location)) as longitude, '' as address, 'overture' as region FROM overture_building WHERE names->>'primary' IS NOT NULL LIMIT 500
UNION ALL SELECT id::text, COALESCE(names->>'primary', names->>'common', 'Street') as name, 'street' as category, ST_Y(ST_Centroid(location)) as latitude, ST_X(ST_Centroid(location)) as longitude, '' as address, 'overture' as region FROM overture_segment WHERE names->>'primary' IS NOT NULL LIMIT 500 UNION ALL SELECT id::text, COALESCE(names->>'primary', names->>'common', 'Street') as name, 'street' as category, ST_Y(ST_Centroid(location)) as latitude, ST_X(ST_Centroid(location)) as longitude, '' as address, 'overture' as region FROM overture_segment WHERE names->>'primary' IS NOT NULL LIMIT 500
UNION ALL SELECT id::text, COALESCE(names->>'primary', names->>'common', 'Place') as name, 'place' as category, ST_Y(ST_Centroid(location)) as latitude, ST_X(ST_Centroid(location)) as longitude, '' as address, 'overture' as region FROM overture_place WHERE names->>'primary' IS NOT NULL LIMIT 500
`; `;
const res = await this.placesSyriaRepository.query(q); const res = await this.placesSyriaRepository.query(q);
const features = res.map(p => ({ const features = res.map(p => ({
@@ -299,10 +491,6 @@ exports.GeocodingService = GeocodingService = GeocodingService_1 = __decorate([
__param(3, (0, typeorm_1.InjectRepository)(osm_area_entity_1.OsmArea)), __param(3, (0, typeorm_1.InjectRepository)(osm_area_entity_1.OsmArea)),
__param(4, (0, typeorm_1.InjectRepository)(osm_point_with_area_entity_1.OsmPointWithArea)), __param(4, (0, typeorm_1.InjectRepository)(osm_point_with_area_entity_1.OsmPointWithArea)),
__param(5, (0, common_1.Inject)(cache_manager_1.CACHE_MANAGER)), __param(5, (0, common_1.Inject)(cache_manager_1.CACHE_MANAGER)),
__metadata("design:paramtypes", [typeorm_2.Repository, __metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object, typeof (_b = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _b : Object, typeof (_c = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _c : Object, typeof (_d = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _d : Object, typeof (_e = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _e : Object, Object])
typeorm_2.Repository,
typeorm_2.Repository,
typeorm_2.Repository,
typeorm_2.Repository, Object])
], GeocodingService); ], GeocodingService);
//# sourceMappingURL=geocoding.service.js.map //# sourceMappingURL=geocoding.service.js.map
File diff suppressed because one or more lines are too long
+8
View File
@@ -0,0 +1,8 @@
import { Repository } from 'typeorm';
import { OsmPointWithArea } from './entities/osm-point-with-area.entity';
export declare class IndexRefreshService {
private readonly repo;
private readonly logger;
constructor(repo: Repository<OsmPointWithArea>);
handleCron(): Promise<void>;
}
+60
View File
@@ -0,0 +1,60 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var IndexRefreshService_1;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.IndexRefreshService = void 0;
const common_1 = require("@nestjs/common");
const schedule_1 = require("@nestjs/schedule");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const osm_point_with_area_entity_1 = require("./entities/osm-point-with-area.entity");
let IndexRefreshService = IndexRefreshService_1 = class IndexRefreshService {
repo;
logger = new common_1.Logger(IndexRefreshService_1.name);
constructor(repo) {
this.repo = repo;
}
async handleCron() {
this.logger.log('Starting background refresh for unified_search_index...');
try {
await this.repo.query('REFRESH MATERIALIZED VIEW CONCURRENTLY unified_search_index;');
this.logger.log('Successfully refreshed unified_search_index.');
}
catch (error) {
this.logger.error('Failed to refresh unified_search_index', error);
try {
this.logger.log('Attempting standard refresh (blocking)...');
await this.repo.query('REFRESH MATERIALIZED VIEW unified_search_index;');
this.logger.log('Successfully refreshed unified_search_index (standard).');
}
catch (fallbackError) {
this.logger.error('Fallback standard refresh also failed', fallbackError);
}
}
}
};
exports.IndexRefreshService = IndexRefreshService;
__decorate([
(0, schedule_1.Cron)(schedule_1.CronExpression.EVERY_5_MINUTES),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], IndexRefreshService.prototype, "handleCron", null);
exports.IndexRefreshService = IndexRefreshService = IndexRefreshService_1 = __decorate([
(0, common_1.Injectable)(),
__param(0, (0, typeorm_1.InjectRepository)(osm_point_with_area_entity_1.OsmPointWithArea)),
__metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object])
], IndexRefreshService);
//# sourceMappingURL=index-refresh.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index-refresh.service.js","sourceRoot":"","sources":["../../src/geocoding/index-refresh.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,+CAAwD;AACxD,6CAAmD;AACnD,qCAAqC;AACrC,sFAAyE;AAGlE,IAAM,mBAAmB,2BAAzB,MAAM,mBAAmB;IAKX;IAJF,MAAM,GAAG,IAAI,eAAM,CAAC,qBAAmB,CAAC,IAAI,CAAC,CAAC;IAE/D,YAEmB,IAAkC;QAAlC,SAAI,GAAJ,IAAI,CAA8B;IAClD,CAAC;IAIE,AAAN,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;QAC3E,IAAI,CAAC;YAEH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,8DAA8D,CAAC,CAAC;YACtF,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,EAAE,KAAK,CAAC,CAAC;YAGnE,IAAI,CAAC;gBACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;gBAC7D,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;gBACzE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;YAC7E,CAAC;YAAC,OAAO,aAAa,EAAE,CAAC;gBACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uCAAuC,EAAE,aAAa,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAA;AA7BY,kDAAmB;AAUxB;IADL,IAAA,eAAI,EAAC,yBAAc,CAAC,eAAe,CAAC;;;;qDAmBpC;8BA5BU,mBAAmB;IAD/B,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,0BAAgB,EAAC,6CAAgB,CAAC,CAAA;yDACZ,oBAAU,oBAAV,oBAAU;GALxB,mBAAmB,CA6B/B"}
+1 -1
View File
@@ -16,7 +16,7 @@ export declare class JordanResearchService {
osm: any; osm: any;
overture: any; overture: any;
wikidata: any; wikidata: any;
static_files: {}; static_files: any;
hdx: string; hdx: string;
gadm: string; gadm: string;
}; };
+2 -1
View File
@@ -48,6 +48,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
var JordanResearchService_1; var JordanResearchService_1;
var _a;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.JordanResearchService = void 0; exports.JordanResearchService = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
@@ -178,6 +179,6 @@ exports.JordanResearchService = JordanResearchService;
exports.JordanResearchService = JordanResearchService = JordanResearchService_1 = __decorate([ exports.JordanResearchService = JordanResearchService = JordanResearchService_1 = __decorate([
(0, common_1.Injectable)(), (0, common_1.Injectable)(),
__param(0, (0, typeorm_1.InjectRepository)(place_jordan_entity_1.PlaceJordan)), __param(0, (0, typeorm_1.InjectRepository)(place_jordan_entity_1.PlaceJordan)),
__metadata("design:paramtypes", [typeorm_2.Repository]) __metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _a : Object])
], JordanResearchService); ], JordanResearchService);
//# sourceMappingURL=jordan-research.service.js.map //# sourceMappingURL=jordan-research.service.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"jordan-research.service.js","sourceRoot":"","sources":["../../src/geocoding/jordan-research.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAAoD;AACpD,6CAAmD;AACnD,qCAAqC;AACrC,wEAA6D;AAC7D,kDAA0B;AAC1B,uCAAyB;AACzB,2CAA6B;AAGtB,IAAM,qBAAqB,6BAA3B,MAAM,qBAAqB;IAKb;IAJF,MAAM,GAAG,IAAI,eAAM,CAAC,uBAAqB,CAAC,IAAI,CAAC,CAAC;IAEjE,YAEmB,SAAkC;QAAlC,cAAS,GAAT,SAAS,CAAyB;IAClD,CAAC;IAEI,KAAK,CAAC,cAAc,CAAC,GAAW,EAAE,IAAa,EAAE,SAAyB,KAAK,EAAE,OAAO,GAAG,CAAC;QAClG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACD,MAAM,MAAM,GAAG;oBACX,OAAO,EAAE,KAAK;oBACd,OAAO,EAAE;wBACL,YAAY,EAAE,mEAAmE;wBACjF,QAAQ,EAAE,mDAAmD;qBAChE;iBACJ,CAAC;gBACF,MAAM,QAAQ,GAAG,MAAM,KAAK,MAAM;oBAC9B,CAAC,CAAC,MAAM,eAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC;oBACrC,CAAC,CAAC,MAAM,eAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC/F,OAAO,QAAQ,CAAC,IAAI,CAAC;YACzB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;oBAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,GAAG,UAAU,OAAO,aAAa,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC5F,MAAM,KAAK,CAAC;gBAChB,CAAC;gBACD,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;YACpD,CAAC;QACL,CAAC;IACP,CAAC;IAKD,KAAK,CAAC,aAAa;QACjB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,mLAAmL,CAAC;QAClM,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,yCAAyC,EAAE,QAAQ,kBAAkB,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAC/H,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC7B,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;gBAC5C,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;gBACjG,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aAC7G,CAAC,CAAC,CAAC;QACN,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YAAC,OAAO,EAAE,KAAK,EAAE,qBAAqB,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAAC,CAAC;IACrE,CAAC;IAKD,KAAK,CAAC,kBAAkB;QACtB,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,sFAAsF,CAAC,CAAC;YACtI,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;gBAAE,OAAO,EAAE,KAAK,EAAE,wDAAwD,EAAE,CAAC;YAGpH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,0FAA0F,CAAC,CAAC;YACvI,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;YAChD,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAEpH,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;oFAC4C,YAAY;;;;;;OAMzF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YAAC,OAAO,EAAE,KAAK,EAAE,0BAA0B,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAAC,CAAC;IAC1E,CAAC;IAKD,KAAK,CAAC,kBAAkB;QACtB,MAAM,MAAM,GAAG,6IAA6I,CAAC;QAC7J,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,mCAAmC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YAC3F,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC7G,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YAAC,OAAO,EAAE,KAAK,EAAE,0BAA0B,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAAC,CAAC;IAC1E,CAAC;IAKD,KAAK,CAAC,gBAAgB;QAEpB,MAAM,KAAK,GAAG,CAAC,gCAAgC,EAAE,SAAS,EAAE,4BAA4B,CAAC,CAAC;QAC1F,MAAM,KAAK,GAAG,CAAC,gCAAgC,EAAE,mBAAmB,CAAC,CAAC;QACtE,MAAM,OAAO,GAAG,EAAE,CAAC;QAEnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,IAAI,KAAK,GAAG,KAAK,CAAC;YAClB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;gBACpB,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;oBACpC,OAAO,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,EAAE,CAAC;oBAChC,KAAK,GAAG,IAAI,CAAC;oBACb,MAAM;gBACV,CAAC;YACL,CAAC;YACD,IAAI,CAAC,KAAK;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,2EAA2E,CAAC;QAC5G,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,mBAAmB;QACvB,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC/D,IAAI,CAAC,aAAa,EAAE;YACpB,IAAI,CAAC,kBAAkB,EAAE;YACzB,IAAI,CAAC,kBAAkB,EAAE;YACzB,IAAI,CAAC,gBAAgB,EAAE;SACxB,CAAC,CAAC;QAEH,OAAO;YACL,IAAI,EAAE,2BAA2B;YACjC,gBAAgB,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC1C,OAAO,EAAE;gBACP,GAAG;gBACH,QAAQ;gBACR,QAAQ;gBACR,YAAY,EAAE,WAAW;gBACzB,GAAG,EAAE,wDAAwD;gBAC7D,IAAI,EAAE,kCAAkC;aACzC;YACD,kBAAkB,EAAE,oLAAoL;SACzM,CAAC;IACJ,CAAC;CACF,CAAA;AAjIY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,0BAAgB,EAAC,iCAAW,CAAC,CAAA;qCACF,oBAAU;GAL7B,qBAAqB,CAiIjC"} {"version":3,"file":"jordan-research.service.js","sourceRoot":"","sources":["../../src/geocoding/jordan-research.service.ts"],"names":[],"mappings":"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"}
+12
View File
@@ -0,0 +1,12 @@
import { MapRefinementService } from './map-refinement.service';
import { CandidateStatus } from './entities/map-candidate.entity';
export declare class MapRefinementController {
private readonly refinementService;
constructor(refinementService: MapRefinementService);
suggest(req: any, dto: any): Promise<import("./entities/map-candidate.entity").MapCandidate>;
list(status?: CandidateStatus): Promise<any[]>;
approve(id: string): Promise<any>;
reject(id: string, body: {
reason: string;
}): Promise<import("./entities/map-candidate.entity").MapCandidate>;
}
+87
View File
@@ -0,0 +1,87 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MapRefinementController = void 0;
const common_1 = require("@nestjs/common");
const map_refinement_service_1 = require("./map-refinement.service");
const firebase_auth_guard_1 = require("../auth/guards/firebase-auth.guard");
const swagger_1 = require("@nestjs/swagger");
const map_candidate_entity_1 = require("./entities/map-candidate.entity");
let MapRefinementController = class MapRefinementController {
refinementService;
constructor(refinementService) {
this.refinementService = refinementService;
}
async suggest(req, dto) {
const userId = req.user?.uid || req.tenant?.id || 'anonymous';
return this.refinementService.suggestPlace(dto, userId);
}
async list(status) {
return this.refinementService.getCandidates(status);
}
async approve(id) {
return this.refinementService.approveCandidate(parseInt(id, 10));
}
async reject(id, body) {
return this.refinementService.rejectCandidate(parseInt(id, 10), body.reason);
}
};
exports.MapRefinementController = MapRefinementController;
__decorate([
(0, common_1.Post)('suggest'),
(0, swagger_1.ApiOperation)({ summary: 'Suggest a new location for the map (Client App)' }),
(0, swagger_1.ApiHeader)({ name: 'x-api-key', description: 'API Key for usage tracking' }),
__param(0, (0, common_1.Req)()),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], MapRefinementController.prototype, "suggest", null);
__decorate([
(0, swagger_1.ApiBearerAuth)(),
(0, common_1.UseGuards)(firebase_auth_guard_1.FirebaseAuthGuard),
(0, common_1.Get)('candidates'),
(0, swagger_1.ApiOperation)({ summary: 'List suggested places for review (Dashboard)' }),
__param(0, (0, common_1.Query)('status')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", Promise)
], MapRefinementController.prototype, "list", null);
__decorate([
(0, swagger_1.ApiBearerAuth)(),
(0, common_1.UseGuards)(firebase_auth_guard_1.FirebaseAuthGuard),
(0, common_1.Patch)('candidates/:id/approve'),
(0, swagger_1.ApiOperation)({ summary: 'Approve a candidate and move to production (Dashboard)' }),
__param(0, (0, common_1.Param)('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", Promise)
], MapRefinementController.prototype, "approve", null);
__decorate([
(0, swagger_1.ApiBearerAuth)(),
(0, common_1.UseGuards)(firebase_auth_guard_1.FirebaseAuthGuard),
(0, common_1.Patch)('candidates/:id/reject'),
(0, swagger_1.ApiOperation)({ summary: 'Reject a candidate (Dashboard)' }),
__param(0, (0, common_1.Param)('id')),
__param(1, (0, common_1.Body)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", Promise)
], MapRefinementController.prototype, "reject", null);
exports.MapRefinementController = MapRefinementController = __decorate([
(0, swagger_1.ApiTags)('map-refinement-places'),
(0, common_1.Controller)('map-refinement/places'),
__metadata("design:paramtypes", [map_refinement_service_1.MapRefinementService])
], MapRefinementController);
//# sourceMappingURL=map-refinement.controller.js.map
@@ -0,0 +1 @@
{"version":3,"file":"map-refinement.controller.js","sourceRoot":"","sources":["../../src/geocoding/map-refinement.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAkG;AAClG,qEAAgE;AAChE,4EAAuE;AACvE,6CAAkF;AAClF,0EAAkE;AAI3D,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IACL;IAA7B,YAA6B,iBAAuC;QAAvC,sBAAiB,GAAjB,iBAAiB,CAAsB;IAAG,CAAC;IAKlE,AAAN,KAAK,CAAC,OAAO,CAAQ,GAAQ,EAAU,GAAQ;QAE7C,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,GAAG,IAAI,GAAG,CAAC,MAAM,EAAE,EAAE,IAAI,WAAW,CAAC;QAC9D,OAAO,IAAI,CAAC,iBAAiB,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC;IAMK,AAAN,KAAK,CAAC,IAAI,CAAkB,MAAwB;QAClD,OAAO,IAAI,CAAC,iBAAiB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IACtD,CAAC;IAMK,AAAN,KAAK,CAAC,OAAO,CAAc,EAAU;QACnC,OAAO,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IACnE,CAAC;IAMK,AAAN,KAAK,CAAC,MAAM,CAAc,EAAU,EAAU,IAAwB;QACpE,OAAO,IAAI,CAAC,iBAAiB,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/E,CAAC;CACF,CAAA;AAnCY,0DAAuB;AAM5B;IAHL,IAAA,aAAI,EAAC,SAAS,CAAC;IACf,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,iDAAiD,EAAE,CAAC;IAC5E,IAAA,mBAAS,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,4BAA4B,EAAE,CAAC;IAC7D,WAAA,IAAA,YAAG,GAAE,CAAA;IAAY,WAAA,IAAA,aAAI,GAAE,CAAA;;;;sDAIrC;AAMK;IAJL,IAAA,uBAAa,GAAE;IACf,IAAA,kBAAS,EAAC,uCAAiB,CAAC;IAC5B,IAAA,YAAG,EAAC,YAAY,CAAC;IACjB,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,8CAA8C,EAAE,CAAC;IAC9D,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;;;;mDAE1B;AAMK;IAJL,IAAA,uBAAa,GAAE;IACf,IAAA,kBAAS,EAAC,uCAAiB,CAAC;IAC5B,IAAA,cAAK,EAAC,wBAAwB,CAAC;IAC/B,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,wDAAwD,EAAE,CAAC;IACrE,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;;;sDAEzB;AAMK;IAJL,IAAA,uBAAa,GAAE;IACf,IAAA,kBAAS,EAAC,uCAAiB,CAAC;IAC5B,IAAA,cAAK,EAAC,uBAAuB,CAAC;IAC9B,IAAA,sBAAY,EAAC,EAAE,OAAO,EAAE,gCAAgC,EAAE,CAAC;IAC9C,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IAAc,WAAA,IAAA,aAAI,GAAE,CAAA;;;;qDAE5C;kCAlCU,uBAAuB;IAFnC,IAAA,iBAAO,EAAC,uBAAuB,CAAC;IAChC,IAAA,mBAAU,EAAC,uBAAuB,CAAC;qCAEc,6CAAoB;GADzD,uBAAuB,CAmCnC"}
+19
View File
@@ -0,0 +1,19 @@
import { Repository, DataSource } from 'typeorm';
import { MapCandidate, CandidateStatus } from './entities/map-candidate.entity';
import { PlaceJordan } from './entities/place-jordan.entity';
import { PlaceSyria } from './entities/place-syria.entity';
import { PlaceEgypt } from './entities/place-egypt.entity';
export declare class MapRefinementService {
private dataSource;
private candidateRepository;
private jordanRepository;
private syriaRepository;
private egyptRepository;
private readonly logger;
constructor(dataSource: DataSource, candidateRepository: Repository<MapCandidate>, jordanRepository: Repository<PlaceJordan>, syriaRepository: Repository<PlaceSyria>, egyptRepository: Repository<PlaceEgypt>);
suggestPlace(dto: any, submittedBy: string): Promise<MapCandidate>;
runExternalVerification(candidateId: number): Promise<void>;
getCandidates(status?: CandidateStatus): Promise<any[]>;
approveCandidate(id: number): Promise<any>;
rejectCandidate(id: number, reason: string): Promise<MapCandidate>;
}
+208
View File
@@ -0,0 +1,208 @@
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var MapRefinementService_1;
var _a, _b, _c, _d, _e;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MapRefinementService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const map_candidate_entity_1 = require("./entities/map-candidate.entity");
const place_jordan_entity_1 = require("./entities/place-jordan.entity");
const place_syria_entity_1 = require("./entities/place-syria.entity");
const place_egypt_entity_1 = require("./entities/place-egypt.entity");
let MapRefinementService = MapRefinementService_1 = class MapRefinementService {
dataSource;
candidateRepository;
jordanRepository;
syriaRepository;
egyptRepository;
logger = new common_1.Logger(MapRefinementService_1.name);
constructor(dataSource, candidateRepository, jordanRepository, syriaRepository, egyptRepository) {
this.dataSource = dataSource;
this.candidateRepository = candidateRepository;
this.jordanRepository = jordanRepository;
this.syriaRepository = syriaRepository;
this.egyptRepository = egyptRepository;
}
async suggestPlace(dto, submittedBy) {
const lat = parseFloat(dto.lat || dto.latitude);
const lng = parseFloat(dto.lng || dto.longitude);
const country = (dto.country || 'JORDAN').toUpperCase();
if (isNaN(lat) || isNaN(lng)) {
throw new Error('Invalid coordinates: Latitude and Longitude must be numbers');
}
this.logger.log(`📍 Suggesting place: ${dto.name} at [${lat}, ${lng}]. Performing spatial enrichment...`);
const enrichment = await this.dataSource.query(`
SELECT
g.id as gov_id, g.name_ar as gov_name,
d.id as dist_id, d.name_ar as dist_name,
s.id as sub_id, s.name_ar as sub_name,
n.id as neigh_id, n.name_ar as neigh_name
FROM (SELECT ST_SetSRID(ST_MakePoint($1, $2), 4326) as p) p
LEFT JOIN admin_boundaries g ON g.admin_level = 4 AND ST_Within(p.p::geometry, g.geom::geometry)
LEFT JOIN admin_boundaries d ON d.admin_level = 6 AND ST_Within(p.p::geometry, d.geom::geometry)
LEFT JOIN admin_boundaries s ON s.admin_level = 8 AND ST_Within(p.p::geometry, s.geom::geometry)
LEFT JOIN neighborhood_polygons n ON ST_Within(p.p::geometry, n.geometry::geometry)
LIMIT 1
`, [lng, lat]);
const spatialData = enrichment[0] || {};
const isArabic = (text) => /[\u0600-\u06FF]/.test(text);
const nameAr = dto.name_ar || (isArabic(dto.name) ? dto.name : null);
const nameEn = dto.name_en || (!isArabic(dto.name) ? dto.name : null);
const candidate = this.candidateRepository.create({
name: dto.name,
name_ar: nameAr,
name_en: nameEn,
category: dto.category,
address: dto.address,
latitude: lat,
longitude: lng,
submittedBy,
status: map_candidate_entity_1.CandidateStatus.PENDING,
country: country,
location: {
type: 'Point',
coordinates: [lng, lat],
},
governorate_id: spatialData.gov_id,
district_id: spatialData.dist_id,
sub_district_id: spatialData.sub_id,
neighborhood_id: spatialData.neigh_id
});
const saved = await this.candidateRepository.save(candidate);
this.logger.log(`✅ Success: Candidate ${saved.id} enriched with Gov:${saved.governorate_id}, Neigh:${spatialData.neigh_id}`);
this.runExternalVerification(saved.id).catch(err => this.logger.error(`❌ Verification failed for ${saved.id}: ${err.message}`));
return {
...saved,
governorate_name: spatialData.gov_name,
district_name: spatialData.dist_name,
neighborhood_name: spatialData.neigh_name,
location_wkt: `POINT(${lng} ${lat})`
};
}
async runExternalVerification(candidateId) {
const candidate = await this.candidateRepository.findOne({ where: { id: candidateId } });
if (!candidate)
return;
this.logger.log(`🔍 Starting automated verification for candidate ${candidate.id}...`);
try {
const axios = require('axios');
const searchUrl = `https://duckduckgo.com/html/?q=${candidate.latitude},${candidate.longitude}`;
const response = await axios.get(searchUrl, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
},
timeout: 10000
});
const html = response.data;
const titleMatch = html.match(/<title>([^<]+)<\/title>/);
if (titleMatch) {
let officialName = titleMatch[1].replace(' at DuckDuckGo', '').replace(' - DuckDuckGo', '').trim();
const isCoordinates = /^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$/.test(officialName);
if (!isCoordinates && officialName.length > 5) {
candidate.verified_name = officialName;
const cleanUser = candidate.name.toLowerCase().trim();
const cleanOfficial = officialName.toLowerCase();
if (cleanOfficial.includes(cleanUser) || cleanUser.includes(cleanOfficial)) {
candidate.confidence_score = 90;
}
else {
candidate.confidence_score = 60;
}
this.logger.log(`🎯 Verified: Found "${officialName}" near suggestion. Trust: ${candidate.confidence_score}%`);
}
else {
candidate.confidence_score = 10;
this.logger.log(`⚠️ No specific POI name found for coordinates ${candidate.latitude},${candidate.longitude}`);
}
}
candidate.verification_metadata = {
last_check: new Date().toISOString(),
source: 'DDG_SCRAPE'
};
await this.candidateRepository.save(candidate);
}
catch (error) {
this.logger.error(`Automated verification error: ${error.message}`);
}
}
async getCandidates(status) {
const query = `
SELECT
c.*,
g.name_ar as governorate_name,
d.name_ar as district_name,
n.name_ar as neighborhood_name
FROM map_candidates c
LEFT JOIN admin_boundaries g ON c.governorate_id = g.id
LEFT JOIN admin_boundaries d ON c.district_id = d.id
LEFT JOIN neighborhood_polygons n ON c.neighborhood_id = n.id
${status ? 'WHERE c.status = $1' : ''}
ORDER BY c.created_at DESC
`;
return this.candidateRepository.query(query, status ? [status] : []);
}
async approveCandidate(id) {
const candidate = await this.candidateRepository.findOne({ where: { id } });
if (!candidate)
throw new common_1.NotFoundException('Candidate not found');
const placeData = {
latitude: candidate.latitude,
longitude: candidate.longitude,
name: candidate.name,
name_ar: candidate.name_ar,
name_en: candidate.name_en,
category: candidate.category,
address: candidate.address,
description: candidate.description,
location: candidate.location,
source: `suggested_by_${candidate.submittedBy}`,
};
let repo;
switch (candidate.country) {
case map_candidate_entity_1.CountryCode.SYRIA:
repo = this.syriaRepository;
break;
case map_candidate_entity_1.CountryCode.EGYPT:
repo = this.egyptRepository;
break;
default: repo = this.jordanRepository;
}
const approvedPlace = repo.create(placeData);
await repo.save(approvedPlace);
candidate.status = map_candidate_entity_1.CandidateStatus.APPROVED;
await this.candidateRepository.save(candidate);
this.logger.log(`✅ Approved candidate ${id}: ${candidate.name} moved to production.`);
return { success: true, place: approvedPlace };
}
async rejectCandidate(id, reason) {
const candidate = await this.candidateRepository.findOne({ where: { id } });
if (!candidate)
throw new common_1.NotFoundException('Candidate not found');
candidate.status = map_candidate_entity_1.CandidateStatus.REJECTED;
candidate.rejectionReason = reason;
return this.candidateRepository.save(candidate);
}
};
exports.MapRefinementService = MapRefinementService;
exports.MapRefinementService = MapRefinementService = MapRefinementService_1 = __decorate([
(0, common_1.Injectable)(),
__param(1, (0, typeorm_1.InjectRepository)(map_candidate_entity_1.MapCandidate)),
__param(2, (0, typeorm_1.InjectRepository)(place_jordan_entity_1.PlaceJordan)),
__param(3, (0, typeorm_1.InjectRepository)(place_syria_entity_1.PlaceSyria)),
__param(4, (0, typeorm_1.InjectRepository)(place_egypt_entity_1.PlaceEgypt)),
__metadata("design:paramtypes", [typeof (_a = typeof typeorm_2.DataSource !== "undefined" && typeorm_2.DataSource) === "function" ? _a : Object, typeof (_b = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _b : Object, typeof (_c = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _c : Object, typeof (_d = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _d : Object, typeof (_e = typeof typeorm_2.Repository !== "undefined" && typeorm_2.Repository) === "function" ? _e : Object])
], MapRefinementService);
//# sourceMappingURL=map-refinement.service.js.map
File diff suppressed because one or more lines are too long
+14 -2
View File
@@ -9,9 +9,21 @@ const swagger_1 = require("@nestjs/swagger");
const helmet_1 = __importDefault(require("helmet")); const helmet_1 = __importDefault(require("helmet"));
const app_module_1 = require("./app.module"); const app_module_1 = require("./app.module");
async function bootstrap() { async function bootstrap() {
const app = await core_1.NestFactory.create(app_module_1.AppModule); const app = await core_1.NestFactory.create(app_module_1.AppModule, {
logger: ['error', 'warn', 'log', 'debug', 'verbose'],
});
const httpAdapter = app.getHttpAdapter();
if (httpAdapter && httpAdapter.getInstance && typeof httpAdapter.getInstance().set === 'function') {
httpAdapter.getInstance().set('trust proxy', 1);
}
app.use((0, helmet_1.default)()); app.use((0, helmet_1.default)());
app.enableCors(); app.enableCors({
origin: process.env.ALLOWED_ORIGINS
? process.env.ALLOWED_ORIGINS.split(',')
: ['http://localhost:3204', 'http://localhost:5173', 'https://map-saas.intaleqapp.com'],
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
credentials: true,
});
app.setGlobalPrefix('api'); app.setGlobalPrefix('api');
app.useGlobalPipes(new common_1.ValidationPipe({ app.useGlobalPipes(new common_1.ValidationPipe({
whitelist: true, whitelist: true,
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;AAAA,uCAAsD;AACtD,2CAAgD;AAChD,6CAAiE;AACjE,oDAA4B;AAC5B,6CAAyC;AAEzC,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAGhD,GAAG,CAAC,GAAG,CAAC,IAAA,gBAAM,GAAE,CAAC,CAAC;IAGlB,GAAG,CAAC,UAAU,EAAE,CAAC;IAGjB,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAG3B,GAAG,CAAC,cAAc,CAAC,IAAI,uBAAc,CAAC;QACpC,SAAS,EAAE,IAAI;QACf,oBAAoB,EAAE,IAAI;QAC1B,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC,CAAC;IAGJ,MAAM,MAAM,GAAG,IAAI,yBAAe,EAAE;SACjC,QAAQ,CAAC,yBAAyB,CAAC;SACnC,cAAc,CAAC,wEAAwE,CAAC;SACxF,UAAU,CAAC,KAAK,CAAC;SACjB,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,WAAW,CAAC;SAC3E,MAAM,CAAC,MAAM,CAAC;SACd,MAAM,CAAC,WAAW,CAAC;SACnB,MAAM,CAAC,WAAW,CAAC;SACnB,KAAK,EAAE,CAAC;IAEX,MAAM,QAAQ,GAAG,uBAAa,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC3D,uBAAa,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAE3C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC;IAC1C,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,qDAAqD,IAAI,MAAM,CAAC,CAAC;AAC/E,CAAC;AACD,SAAS,EAAE,CAAC"} {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;AAAA,uCAA2C;AAC3C,2CAAgD;AAChD,6CAAiE;AACjE,oDAA4B;AAE5B,6CAAyC;AAEzC,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,EAAE;QAC9C,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC;KACrD,CAAC,CAAC;IAGH,MAAM,WAAW,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;IACzC,IAAI,WAAW,IAAI,WAAW,CAAC,WAAW,IAAI,OAAO,WAAW,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;QAClG,WAAW,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IAClD,CAAC;IAGD,GAAG,CAAC,GAAG,CAAC,IAAA,gBAAM,GAAE,CAAC,CAAC;IAGlB,GAAG,CAAC,UAAU,CAAC;QACb,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe;YACjC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC;YACxC,CAAC,CAAC,CAAC,uBAAuB,EAAE,uBAAuB,EAAE,iCAAiC,CAAC;QACzF,OAAO,EAAE,wCAAwC;QACjD,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IAGH,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAG3B,GAAG,CAAC,cAAc,CAAC,IAAI,uBAAc,CAAC;QACpC,SAAS,EAAE,IAAI;QACf,oBAAoB,EAAE,IAAI;QAC1B,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC,CAAC;IAGJ,MAAM,MAAM,GAAG,IAAI,yBAAe,EAAE;SACjC,QAAQ,CAAC,yBAAyB,CAAC;SACnC,cAAc,CAAC,wEAAwE,CAAC;SACxF,UAAU,CAAC,KAAK,CAAC;SACjB,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,WAAW,CAAC;SAC3E,MAAM,CAAC,MAAM,CAAC;SACd,MAAM,CAAC,WAAW,CAAC;SACnB,MAAM,CAAC,WAAW,CAAC;SACnB,KAAK,EAAE,CAAC;IAEX,MAAM,QAAQ,GAAG,uBAAa,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC3D,uBAAa,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAE3C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC;IAC1C,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,qDAAqD,IAAI,MAAM,CAAC,CAAC;AAC/E,CAAC;AACD,SAAS,EAAE,CAAC"}
+4
View File
@@ -7,6 +7,10 @@ export declare class CandidateRoad {
lengthMeters: number; lengthMeters: number;
confidence: number; confidence: number;
status: string; status: string;
source: string;
name: string;
highway: string;
oneway: number;
discoveredAt: Date; discoveredAt: Date;
reviewedAt: Date; reviewedAt: Date;
} }
+20
View File
@@ -20,6 +20,10 @@ let CandidateRoad = class CandidateRoad {
lengthMeters; lengthMeters;
confidence; confidence;
status; status;
source;
name;
highway;
oneway;
discoveredAt; discoveredAt;
reviewedAt; reviewedAt;
}; };
@@ -62,6 +66,22 @@ __decorate([
(0, typeorm_1.Column)({ default: 'pending' }), (0, typeorm_1.Column)({ default: 'pending' }),
__metadata("design:type", String) __metadata("design:type", String)
], CandidateRoad.prototype, "status", void 0); ], CandidateRoad.prototype, "status", void 0);
__decorate([
(0, typeorm_1.Column)({ default: 'telemetry' }),
__metadata("design:type", String)
], CandidateRoad.prototype, "source", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'varchar', length: 255, nullable: true }),
__metadata("design:type", String)
], CandidateRoad.prototype, "name", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'varchar', length: 32, nullable: true }),
__metadata("design:type", String)
], CandidateRoad.prototype, "highway", void 0);
__decorate([
(0, typeorm_1.Column)({ type: 'smallint', default: 0 }),
__metadata("design:type", Number)
], CandidateRoad.prototype, "oneway", void 0);
__decorate([ __decorate([
(0, typeorm_1.CreateDateColumn)(), (0, typeorm_1.CreateDateColumn)(),
__metadata("design:type", Date) __metadata("design:type", Date)
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"candidate-road.entity.js","sourceRoot":"","sources":["../../src/maps/candidate-road.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAA0F;AASnF,IAAM,aAAa,GAAnB,MAAM,aAAa;IAExB,EAAE,CAAS;IAWX,QAAQ,CAAM;IAKd,iBAAiB,CAAS;IAK1B,WAAW,CAAS;IAKpB,YAAY,CAAS;IAKrB,YAAY,CAAS;IAKrB,UAAU,CAAS;IAKnB,MAAM,CAAS;IAGf,YAAY,CAAO;IAGnB,UAAU,CAAO;CAClB,CAAA;AAlDY,sCAAa;AAExB;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;yCACpB;AAWX;IAPC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,WAAW;QACjB,kBAAkB,EAAE,YAAY;QAChC,IAAI,EAAE,IAAI;QACV,QAAQ,EAAE,KAAK;KAChB,CAAC;IACD,IAAA,eAAK,EAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;;+CACX;AAKd;IADC,IAAA,gBAAM,EAAC,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;wDACJ;AAK1B;IADC,IAAA,gBAAM,EAAC,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;kDACV;AAKpB;IADC,IAAA,gBAAM,EAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;mDACX;AAKrB;IADC,IAAA,gBAAM,EAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;mDACX;AAKrB;IADC,IAAA,gBAAM,EAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;iDACb;AAKnB;IADC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;;6CAChB;AAGf;IADC,IAAA,0BAAgB,GAAE;8BACL,IAAI;mDAAC;AAGnB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BAClC,IAAI;iDAAC;wBAjDN,aAAa;IADzB,IAAA,gBAAM,EAAC,iBAAiB,CAAC;GACb,aAAa,CAkDzB"} {"version":3,"file":"candidate-road.entity.js","sourceRoot":"","sources":["../../src/maps/candidate-road.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAA0F;AASnF,IAAM,aAAa,GAAnB,MAAM,aAAa;IAExB,EAAE,CAAS;IAWX,QAAQ,CAAM;IAKd,iBAAiB,CAAS;IAK1B,WAAW,CAAS;IAKpB,YAAY,CAAS;IAKrB,YAAY,CAAS;IAKrB,UAAU,CAAS;IAKnB,MAAM,CAAS;IAKf,MAAM,CAAS;IAKf,IAAI,CAAS;IAKb,OAAO,CAAS;IAMhB,MAAM,CAAS;IAGf,YAAY,CAAO;IAGnB,UAAU,CAAO;CAClB,CAAA;AAvEY,sCAAa;AAExB;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;yCACpB;AAWX;IAPC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,WAAW;QACjB,kBAAkB,EAAE,YAAY;QAChC,IAAI,EAAE,IAAI;QACV,QAAQ,EAAE,KAAK;KAChB,CAAC;IACD,IAAA,eAAK,EAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;;+CACX;AAKd;IADC,IAAA,gBAAM,EAAC,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;wDACJ;AAK1B;IADC,IAAA,gBAAM,EAAC,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;kDACV;AAKpB;IADC,IAAA,gBAAM,EAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;mDACX;AAKrB;IADC,IAAA,gBAAM,EAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;mDACX;AAKrB;IADC,IAAA,gBAAM,EAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;iDACb;AAKnB;IADC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;;6CAChB;AAKf;IADC,IAAA,gBAAM,EAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;;6CAClB;AAKf;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;2CAC5C;AAKb;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;8CACxC;AAMhB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;6CAC1B;AAGf;IADC,IAAA,0BAAgB,GAAE;8BACL,IAAI;mDAAC;AAGnB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BAClC,IAAI;iDAAC;wBAtEN,aAAa;IADzB,IAAA,gBAAM,EAAC,iBAAiB,CAAC;GACb,aAAa,CAuEzB"}
+10 -2
View File
@@ -1,16 +1,24 @@
import type { Response } from 'express';
import { MapsService } from './maps.service'; import { MapsService } from './maps.service';
export declare class MapsController { export declare class MapsController {
private readonly mapsService; private readonly mapsService;
constructor(mapsService: MapsService); constructor(mapsService: MapsService);
syncRoutes(): Promise<{
success: boolean;
message: string;
}>;
getStyleJson(theme: string, res: Response): Promise<any>;
getRoute(query: any): Promise<{ getRoute(query: any): Promise<{
routeName: any;
tags: any;
distance: any; distance: any;
duration: number; duration: any;
trafficAwareDuration: number;
trafficFactor: number; trafficFactor: number;
startName: string; startName: string;
endName: string; endName: string;
points: any; points: any;
bbox: any; bbox: any;
instructions: any;
alternatives: any; alternatives: any;
}>; }>;
getConfig(): Promise<{ getConfig(): Promise<{
+104 -1
View File
@@ -1,10 +1,43 @@
"use strict"; "use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r; return c > 3 && r && Object.defineProperty(target, key, r), r;
}; };
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __metadata = (this && this.__metadata) || function (k, v) { var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
}; };
@@ -15,6 +48,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.MapsController = void 0; exports.MapsController = void 0;
const common_1 = require("@nestjs/common"); const common_1 = require("@nestjs/common");
const swagger_1 = require("@nestjs/swagger"); const swagger_1 = require("@nestjs/swagger");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const maps_service_1 = require("./maps.service"); const maps_service_1 = require("./maps.service");
const api_key_guard_1 = require("../common/guards/api-key.guard"); const api_key_guard_1 = require("../common/guards/api-key.guard");
let MapsController = class MapsController { let MapsController = class MapsController {
@@ -22,6 +57,55 @@ let MapsController = class MapsController {
constructor(mapsService) { constructor(mapsService) {
this.mapsService = mapsService; this.mapsService = mapsService;
} }
async syncRoutes() {
return this.mapsService.requestRoutingSync();
}
async getStyleJson(theme, res) {
const isDark = theme === 'obsidian';
const filename = isDark ? 'style-dark.json' : 'style.json';
const fallbackFilename = 'style.json';
const pathsToCheck = [
path.join('/data', filename),
path.join(process.cwd(), '../../', filename),
path.join(process.cwd(), filename),
path.join('/data', fallbackFilename),
path.join(process.cwd(), '../../', fallbackFilename),
path.join(process.cwd(), fallbackFilename),
];
let stylePath = '';
for (const p of pathsToCheck) {
if (fs.existsSync(p)) {
stylePath = p;
break;
}
}
if (!stylePath) {
return res.status(404).send('Style not found');
}
try {
const styleRaw = fs.readFileSync(stylePath, 'utf8');
const styleObj = JSON.parse(styleRaw);
if (theme === 'light') {
styleObj.layers.forEach((layer) => {
if (layer.id === 'background') {
layer.paint['background-color'] = '#FFFFFF';
}
});
}
else if (theme === 'obsidian') {
styleObj.layers.forEach((layer) => {
if (layer.id === 'background') {
layer.paint['background-color'] = '#101014';
}
});
}
res.setHeader('Content-Type', 'application/json');
res.send(styleObj);
}
catch (e) {
res.status(500).send('Error parsing style.json');
}
}
async getRoute(query) { async getRoute(query) {
const waypoints = []; const waypoints = [];
if (query.fromLat && query.fromLng) { if (query.fromLat && query.fromLng) {
@@ -45,13 +129,32 @@ let MapsController = class MapsController {
waypoints.push([parseFloat(query.toLat), parseFloat(query.toLng)]); waypoints.push([parseFloat(query.toLat), parseFloat(query.toLng)]);
} }
const profile = query.profile || 'car'; const profile = query.profile || 'car';
return this.mapsService.getRoute(waypoints, profile); const steps = query.steps === 'true';
const locale = query.locale || 'en';
const alternatives = query.alternatives === 'true';
return this.mapsService.getRoute(waypoints, profile, steps, locale, alternatives);
} }
async getConfig() { async getConfig() {
return this.mapsService.getMapConfig(); return this.mapsService.getMapConfig();
} }
}; };
exports.MapsController = MapsController; exports.MapsController = MapsController;
__decorate([
(0, common_1.Post)('sync-routes'),
(0, swagger_1.ApiOperation)({ summary: 'Request GraphHopper routing sync 🔄' }),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", Promise)
], MapsController.prototype, "syncRoutes", null);
__decorate([
(0, common_1.Get)('style.json'),
(0, swagger_1.ApiOperation)({ summary: 'Get MapLibre style JSON 🎨' }),
__param(0, (0, common_1.Query)('theme')),
__param(1, (0, common_1.Res)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object]),
__metadata("design:returntype", Promise)
], MapsController.prototype, "getStyleJson", null);
__decorate([ __decorate([
(0, common_1.Get)('route'), (0, common_1.Get)('route'),
(0, swagger_1.ApiOperation)({ summary: 'Calculate a route with dynamic waypoints 🚗' }), (0, swagger_1.ApiOperation)({ summary: 'Calculate a route with dynamic waypoints 🚗' }),
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"maps.controller.js","sourceRoot":"","sources":["../../src/maps/maps.controller.ts"],"names":[],"mappings":"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"} {"version":3,"file":"maps.controller.js","sourceRoot":"","sources":["../../src/maps/maps.controller.ts"],"names":[],"mappings":"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"}
+15 -5
View File
@@ -1,26 +1,36 @@
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { Repository } from 'typeorm'; import { Repository, DataSource } from 'typeorm';
import { RoadSegmentStat } from './road-stat.entity'; import { RoadSegmentStat } from './road-stat.entity';
import { TrafficGridService } from './traffic-grid.service'; import { TrafficGridService } from './traffic-grid.service';
import { GeocodingService } from '../geocoding/geocoding.service'; import { GeocodingService } from '../geocoding/geocoding.service';
import { RedisService } from '../common/redis.service';
export declare class MapsService { export declare class MapsService {
private configService; private configService;
private roadStatRepo; private roadStatRepo;
private trafficGrid; private trafficGrid;
private geocodingService; private geocodingService;
private dataSource;
private redisService;
private readonly graphHopperUrl; private readonly graphHopperUrl;
constructor(configService: ConfigService, roadStatRepo: Repository<RoadSegmentStat>, trafficGrid: TrafficGridService, geocodingService: GeocodingService); constructor(configService: ConfigService, roadStatRepo: Repository<RoadSegmentStat>, trafficGrid: TrafficGridService, geocodingService: GeocodingService, dataSource: DataSource, redisService: RedisService);
getRoute(waypoints: [number, number][], profile?: string): Promise<{ requestRoutingSync(): Promise<{
success: boolean;
message: string;
}>;
getRoute(waypoints: [number, number][], profile?: string, steps?: boolean, locale?: string, alternatives?: boolean): Promise<{
routeName: any;
tags: any;
distance: any; distance: any;
duration: number; duration: any;
trafficAwareDuration: number;
trafficFactor: number; trafficFactor: number;
startName: string; startName: string;
endName: string; endName: string;
points: any; points: any;
bbox: any; bbox: any;
instructions: any;
alternatives: any; alternatives: any;
}>; }>;
private getRouteName;
private decodePolyline; private decodePolyline;
getMapConfig(): Promise<{ getMapConfig(): Promise<{
center: number[]; center: number[];

Some files were not shown because too many files have changed in this diff Show More