Refactor code structure for improved readability and maintainability
Test Suite / test (24.15.0) (push) Has been cancelled

This commit is contained in:
Nils-Johan Gynther
2026-05-06 07:37:59 +02:00
parent e4f201ea36
commit 969dafdbc6
273 changed files with 11357 additions and 39 deletions
+3
View File
@@ -0,0 +1,3 @@
export declare class QuickImportDto {
input?: string;
}
+23
View File
@@ -0,0 +1,23 @@
"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.QuickImportDto = void 0;
const class_validator_1 = require("class-validator");
class QuickImportDto {
}
exports.QuickImportDto = QuickImportDto;
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.IsString)(),
(0, class_validator_1.MaxLength)(2048),
__metadata("design:type", String)
], QuickImportDto.prototype, "input", void 0);
//# sourceMappingURL=quick-import.dto.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"quick-import.dto.js","sourceRoot":"","sources":["../../../src/quick-import/dto/quick-import.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAAkE;AAElE,MAAa,cAAc;CAK1B;AALD,wCAKC;AADC;IAHC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;IACV,IAAA,2BAAS,EAAC,IAAI,CAAC;;6CACD"}
@@ -0,0 +1,7 @@
import { QuickImportDto } from './dto/quick-import.dto';
import { QuickImportService, QuickImportResult } from './quick-import.service';
export declare class QuickImportController {
private readonly quickImportService;
constructor(quickImportService: QuickImportService);
importFromInput(body: QuickImportDto, file?: Express.Multer.File): Promise<QuickImportResult>;
}
+64
View File
@@ -0,0 +1,64 @@
"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.QuickImportController = void 0;
const common_1 = require("@nestjs/common");
const throttler_1 = require("@nestjs/throttler");
const platform_express_1 = require("@nestjs/platform-express");
const multer_1 = require("multer");
const quick_import_dto_1 = require("./dto/quick-import.dto");
const quick_import_service_1 = require("./quick-import.service");
let QuickImportController = class QuickImportController {
constructor(quickImportService) {
this.quickImportService = quickImportService;
}
async importFromInput(body, file) {
if (file) {
return this.quickImportService.importFromUpload(file);
}
return this.quickImportService.importFromInput(body?.input ?? '');
}
};
exports.QuickImportController = QuickImportController;
__decorate([
(0, common_1.Post)(),
(0, common_1.HttpCode)(200),
(0, throttler_1.Throttle)({ default: { ttl: 60_000, limit: 20 } }),
(0, common_1.UseInterceptors)((0, platform_express_1.FileInterceptor)('file', {
storage: (0, multer_1.memoryStorage)(),
limits: { fileSize: 10 * 1024 * 1024 },
fileFilter: (req, file, callback) => {
if (file.mimetype === 'application/pdf' ||
file.mimetype === 'application/octet-stream' ||
file.mimetype === 'image/jpeg' ||
file.mimetype === 'image/png' ||
file.mimetype === 'image/webp') {
callback(null, true);
}
else {
callback(new Error('Otillåten filtyp. Använd JPEG, PNG, WebP eller PDF.'), false);
}
},
})),
__param(0, (0, common_1.Body)()),
__param(1, (0, common_1.UploadedFile)()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [quick_import_dto_1.QuickImportDto, Object]),
__metadata("design:returntype", Promise)
], QuickImportController.prototype, "importFromInput", null);
exports.QuickImportController = QuickImportController = __decorate([
(0, common_1.Controller)('quick-import'),
__metadata("design:paramtypes", [quick_import_service_1.QuickImportService])
], QuickImportController);
//# sourceMappingURL=quick-import.controller.js.map
@@ -0,0 +1 @@
{"version":3,"file":"quick-import.controller.js","sourceRoot":"","sources":["../../src/quick-import/quick-import.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAiG;AACjG,iDAA6C;AAC7C,+DAA2D;AAC3D,mCAAuC;AACvC,6DAAwD;AACxD,iEAA+E;AAGxE,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAChC,YAA6B,kBAAsC;QAAtC,uBAAkB,GAAlB,kBAAkB,CAAoB;IAAG,CAAC;IAwBjE,AAAN,KAAK,CAAC,eAAe,CACX,IAAoB,EACZ,IAA0B;QAE1C,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,IAAI,CAAC,kBAAkB,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,IAAI,CAAC,kBAAkB,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC;CACF,CAAA;AAnCY,sDAAqB;AAyB1B;IAtBL,IAAA,aAAI,GAAE;IACN,IAAA,iBAAQ,EAAC,GAAG,CAAC;IACb,IAAA,oBAAQ,EAAC,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC;IACjD,IAAA,wBAAe,EACd,IAAA,kCAAe,EAAC,MAAM,EAAE;QACtB,OAAO,EAAE,IAAA,sBAAa,GAAE;QACxB,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE;QACtC,UAAU,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YAClC,IACE,IAAI,CAAC,QAAQ,KAAK,iBAAiB;gBACnC,IAAI,CAAC,QAAQ,KAAK,0BAA0B;gBAC5C,IAAI,CAAC,QAAQ,KAAK,YAAY;gBAC9B,IAAI,CAAC,QAAQ,KAAK,WAAW;gBAC7B,IAAI,CAAC,QAAQ,KAAK,YAAY,EAC9B,CAAC;gBACD,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,EAAE,KAAK,CAAC,CAAC;YACpF,CAAC;QACH,CAAC;KACF,CAAC,CACH;IAEE,WAAA,IAAA,aAAI,GAAE,CAAA;IACN,WAAA,IAAA,qBAAY,GAAE,CAAA;;qCADD,iCAAc;;4DAQ7B;gCAlCU,qBAAqB;IADjC,IAAA,mBAAU,EAAC,cAAc,CAAC;qCAEwB,yCAAkB;GADxD,qBAAqB,CAmCjC"}
+2
View File
@@ -0,0 +1,2 @@
export declare class QuickImportModule {
}
+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.QuickImportModule = void 0;
const common_1 = require("@nestjs/common");
const quick_import_controller_1 = require("./quick-import.controller");
const quick_import_service_1 = require("./quick-import.service");
let QuickImportModule = class QuickImportModule {
};
exports.QuickImportModule = QuickImportModule;
exports.QuickImportModule = QuickImportModule = __decorate([
(0, common_1.Module)({
controllers: [quick_import_controller_1.QuickImportController],
providers: [quick_import_service_1.QuickImportService],
})
], QuickImportModule);
//# sourceMappingURL=quick-import.module.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"quick-import.module.js","sourceRoot":"","sources":["../../src/quick-import/quick-import.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,uEAAkE;AAClE,iEAA4D;AAMrD,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;CAAG,CAAA;AAApB,8CAAiB;4BAAjB,iBAAiB;IAJ7B,IAAA,eAAM,EAAC;QACN,WAAW,EAAE,CAAC,+CAAqB,CAAC;QACpC,SAAS,EAAE,CAAC,yCAAkB,CAAC;KAChC,CAAC;GACW,iBAAiB,CAAG"}
+13
View File
@@ -0,0 +1,13 @@
export interface QuickImportResult {
markdown: string;
source: 'ica' | 'pdf' | 'image' | 'other';
imageUrl?: string;
imageWarning?: string;
}
export declare class QuickImportService {
private readonly logger;
importFromInput(input: string): Promise<QuickImportResult>;
importFromUpload(file: Express.Multer.File): Promise<QuickImportResult>;
private handleImporterResponse;
private downloadImageIfNeeded;
}
+102
View File
@@ -0,0 +1,102 @@
"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 QuickImportService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.QuickImportService = void 0;
const common_1 = require("@nestjs/common");
const download_image_1 = require("../common/utils/download-image");
const IMAGE_DEST_DIR = process.env.IMAGE_DEST_DIR || '/app/recipe-images';
const IMPORTER_SERVICE_URL = process.env.IMPORTER_SERVICE_URL || 'http://importer-api:3001';
let QuickImportService = QuickImportService_1 = class QuickImportService {
constructor() {
this.logger = new common_1.Logger(QuickImportService_1.name);
}
async importFromInput(input) {
const trimmed = input.trim();
this.logger.log(`Delegerar URL-import till microservice: ${trimmed}`);
if (!trimmed) {
throw new common_1.BadRequestException('Du måste ange en URL eller ladda upp en fil');
}
let response;
try {
response = await fetch(`${IMPORTER_SERVICE_URL}/api/quick-import`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ input: trimmed }),
});
}
catch (err) {
this.logger.error(`Kunde inte nå importer-api: ${err}`);
throw new common_1.ServiceUnavailableException('Import-tjänsten är inte tillgänglig. Försök igen senare.');
}
const result = await this.handleImporterResponse(response);
return this.downloadImageIfNeeded(result);
}
async importFromUpload(file) {
this.logger.log(`Delegerar filuploading till microservice: ${file.originalname} (${file.mimetype})`);
const form = new FormData();
form.append('file', new Blob([new Uint8Array(file.buffer)], { type: file.mimetype }), file.originalname);
let response;
try {
response = await fetch(`${IMPORTER_SERVICE_URL}/api/quick-import`, {
method: 'POST',
body: form,
});
}
catch (err) {
this.logger.error(`Kunde inte nå importer-api: ${err}`);
throw new common_1.ServiceUnavailableException('Import-tjänsten är inte tillgänglig. Försök igen senare.');
}
const result = await this.handleImporterResponse(response);
return this.downloadImageIfNeeded(result);
}
async handleImporterResponse(response) {
if (!response.ok) {
let message = `Import-tjänsten svarade ${response.status}`;
try {
const body = (await response.json());
if (body.message)
message = body.message;
}
catch {
}
this.logger.error(`Importer-api fel: ${message}`);
if (response.status >= 400 && response.status < 500) {
throw new common_1.BadRequestException(message);
}
throw new common_1.ServiceUnavailableException(message);
}
return response.json();
}
async downloadImageIfNeeded(result) {
if (!result.imageUrl)
return result;
const imageUrl = result.imageUrl;
if (!imageUrl.startsWith('http://') && !imageUrl.startsWith('https://')) {
return result;
}
this.logger.log(`Laddar ner receptbild: ${imageUrl}`);
try {
const localPath = await (0, download_image_1.downloadAndOptimizeImage)(imageUrl, IMAGE_DEST_DIR);
this.logger.log(`Bild sparad lokalt: ${localPath}`);
return { ...result, imageUrl: localPath };
}
catch (imgErr) {
this.logger.warn(`Kunde inte ladda ner bild: ${imgErr} (källa: ${imageUrl})`);
return {
...result,
imageWarning: result.imageWarning ?? 'Receptbild kunde inte laddas ner lokalt; extern URL används.',
};
}
}
};
exports.QuickImportService = QuickImportService;
exports.QuickImportService = QuickImportService = QuickImportService_1 = __decorate([
(0, common_1.Injectable)()
], QuickImportService);
//# sourceMappingURL=quick-import.service.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"quick-import.service.js","sourceRoot":"","sources":["../../src/quick-import/quick-import.service.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAKwB;AACxB,mEAA0E;AAE1E,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,oBAAoB,CAAC;AAC1E,MAAM,oBAAoB,GACxB,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,0BAA0B,CAAC;AAU1D,IAAM,kBAAkB,0BAAxB,MAAM,kBAAkB;IAAxB;QACY,WAAM,GAAG,IAAI,eAAM,CAAC,oBAAkB,CAAC,IAAI,CAAC,CAAC;IA8FhE,CAAC;IA5FC,KAAK,CAAC,eAAe,CAAC,KAAa;QACjC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2CAA2C,OAAO,EAAE,CAAC,CAAC;QAEtE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,4BAAmB,CAAC,8CAA8C,CAAC,CAAC;QAChF,CAAC;QAED,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,oBAAoB,mBAAmB,EAAE;gBACjE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;aACzC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;YACzD,MAAM,IAAI,oCAA2B,CACnC,+DAA+D,CAChE,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,IAAyB;QAC9C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,6CAA6C,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;QAErG,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CACT,MAAM,EACN,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,EAChE,IAAI,CAAC,YAAY,CAClB,CAAC;QAEF,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,oBAAoB,mBAAmB,EAAE;gBACjE,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,IAAI;aACX,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;YACzD,MAAM,IAAI,oCAA2B,CACnC,+DAA+D,CAChE,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,sBAAsB,CAAC,QAAkB;QACrD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,IAAI,OAAO,GAAG,4BAA4B,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC5D,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB,CAAC;gBAC7D,IAAI,IAAI,CAAC,OAAO;oBAAE,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YAC3C,CAAC;YAAC,MAAM,CAAC;YAET,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,OAAO,EAAE,CAAC,CAAC;YAClD,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;gBACpD,MAAM,IAAI,4BAAmB,CAAC,OAAO,CAAC,CAAC;YACzC,CAAC;YACD,MAAM,IAAI,oCAA2B,CAAC,OAAO,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,QAAQ,CAAC,IAAI,EAAgC,CAAC;IACvD,CAAC;IAEO,KAAK,CAAC,qBAAqB,CAAC,MAAyB;QAC3D,IAAI,CAAC,MAAM,CAAC,QAAQ;YAAE,OAAO,MAAM,CAAC;QAEpC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACxE,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAA,yCAAwB,EAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;YAC3E,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,uBAAuB,SAAS,EAAE,CAAC,CAAC;YACpD,OAAO,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QAC5C,CAAC;QAAC,OAAO,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8BAA8B,MAAM,aAAa,QAAQ,GAAG,CAAC,CAAC;YAC/E,OAAO;gBACL,GAAG,MAAM;gBACT,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,+DAA+D;aACrG,CAAC;QACJ,CAAC;IACH,CAAC;CACF,CAAA;AA/FY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,mBAAU,GAAE;GACA,kBAAkB,CA+F9B"}