@solidxai/core 0.1.12-beta.2 → 0.1.12-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +16 -0
- package/CLAUDE.md +26 -0
- package/dist/commands/seed.command.d.ts.map +1 -1
- package/dist/commands/seed.command.js +15 -2
- package/dist/commands/seed.command.js.map +1 -1
- package/dist/constants/media-file-types.d.ts +5 -0
- package/dist/constants/media-file-types.d.ts.map +1 -0
- package/dist/constants/media-file-types.js +27 -0
- package/dist/constants/media-file-types.js.map +1 -0
- package/dist/controllers/media.controller.d.ts +14 -11
- package/dist/controllers/media.controller.d.ts.map +1 -1
- package/dist/controllers/media.controller.js +72 -33
- package/dist/controllers/media.controller.js.map +1 -1
- package/dist/dtos/create-media.dto.d.ts +1 -0
- package/dist/dtos/create-media.dto.d.ts.map +1 -1
- package/dist/dtos/create-media.dto.js +7 -1
- package/dist/dtos/create-media.dto.js.map +1 -1
- package/dist/dtos/create-role-metadata.dto.d.ts +2 -0
- package/dist/dtos/create-role-metadata.dto.d.ts.map +1 -1
- package/dist/dtos/create-role-metadata.dto.js +3 -1
- package/dist/dtos/create-role-metadata.dto.js.map +1 -1
- package/dist/dtos/update-media.dto.d.ts +1 -0
- package/dist/dtos/update-media.dto.d.ts.map +1 -1
- package/dist/dtos/update-media.dto.js +7 -1
- package/dist/dtos/update-media.dto.js.map +1 -1
- package/dist/entities/media.entity.d.ts +1 -0
- package/dist/entities/media.entity.d.ts.map +1 -1
- package/dist/entities/media.entity.js +9 -1
- package/dist/entities/media.entity.js.map +1 -1
- package/dist/enums/auth-type.enum.d.ts +2 -1
- package/dist/enums/auth-type.enum.d.ts.map +1 -1
- package/dist/enums/auth-type.enum.js +1 -0
- package/dist/enums/auth-type.enum.js.map +1 -1
- package/dist/guards/authentication.guard.d.ts +3 -1
- package/dist/guards/authentication.guard.d.ts.map +1 -1
- package/dist/guards/authentication.guard.js +5 -1
- package/dist/guards/authentication.guard.js.map +1 -1
- package/dist/guards/media-signed-url.guard.d.ts +9 -0
- package/dist/guards/media-signed-url.guard.d.ts.map +1 -0
- package/dist/guards/media-signed-url.guard.js +49 -0
- package/dist/guards/media-signed-url.guard.js.map +1 -0
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js +10 -13
- package/dist/helpers/field-crud-managers/MediaFieldCrudManager.js.map +1 -1
- package/dist/interfaces.d.ts +19 -1
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js +2 -0
- package/dist/interfaces.js.map +1 -1
- package/dist/repository/media.repository.d.ts.map +1 -1
- package/dist/repository/media.repository.js +2 -0
- package/dist/repository/media.repository.js.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts +7 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +87 -3
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/permission-metadata-seeder.service.d.ts +1 -0
- package/dist/seeders/permission-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/permission-metadata-seeder.service.js +6 -1
- package/dist/seeders/permission-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +114 -13
- package/dist/services/authentication.service.d.ts +1 -0
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +19 -1
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/media-download-url.service.d.ts +21 -0
- package/dist/services/media-download-url.service.d.ts.map +1 -0
- package/dist/services/media-download-url.service.js +67 -0
- package/dist/services/media-download-url.service.js.map +1 -0
- package/dist/services/media-storage.utils.d.ts +27 -0
- package/dist/services/media-storage.utils.d.ts.map +1 -0
- package/dist/services/media-storage.utils.js +82 -0
- package/dist/services/media-storage.utils.js.map +1 -0
- package/dist/services/media.service.d.ts +20 -4
- package/dist/services/media.service.d.ts.map +1 -1
- package/dist/services/media.service.js +157 -55
- package/dist/services/media.service.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.d.ts +4 -4
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.d.ts.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +37 -63
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.d.ts +5 -5
- package/dist/services/mediaStorageProviders/file-storage-provider.d.ts.map +1 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.js +37 -38
- package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
- package/dist/services/role-metadata.service.d.ts +1 -0
- package/dist/services/role-metadata.service.d.ts.map +1 -1
- package/dist/services/role-metadata.service.js +8 -5
- package/dist/services/role-metadata.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +11 -1
- package/dist/solid-core.module.js.map +1 -1
- package/dist/subscribers/audit.subscriber.js +1 -1
- package/dist/subscribers/audit.subscriber.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/seed.command.ts +17 -3
- package/src/constants/media-file-types.ts +44 -0
- package/src/controllers/media.controller.ts +44 -24
- package/src/dtos/create-media.dto.ts +8 -3
- package/src/dtos/create-role-metadata.dto.ts +2 -0
- package/src/dtos/update-media.dto.ts +8 -3
- package/src/entities/media.entity.ts +4 -1
- package/src/enums/auth-type.enum.ts +1 -0
- package/src/guards/authentication.guard.ts +3 -0
- package/src/guards/media-signed-url.guard.ts +41 -0
- package/src/helpers/field-crud-managers/MediaFieldCrudManager.ts +12 -24
- package/src/interfaces.ts +20 -0
- package/src/repository/media.repository.ts +2 -0
- package/src/seeders/module-metadata-seeder.service.ts +109 -3
- package/src/seeders/permission-metadata-seeder.service.ts +6 -1
- package/src/seeders/seed-data/solid-core-metadata.json +114 -13
- package/src/services/1.js +6 -0
- package/src/services/authentication.service.ts +24 -1
- package/src/services/media-download-url.service.ts +67 -0
- package/src/services/media-storage.utils.ts +79 -0
- package/src/services/media.service.ts +189 -59
- package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +52 -76
- package/src/services/mediaStorageProviders/file-storage-provider.ts +44 -48
- package/src/services/role-metadata.service.ts +17 -5
- package/src/solid-core.module.ts +21 -2
- package/src/subscribers/audit.subscriber.ts +1 -1
- package/dist-tests/api/authenticate.spec.js +0 -119
- package/dist-tests/api/authenticate.spec.js.map +0 -1
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +0 -97
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +0 -1
- package/dist-tests/api/ping.spec.js +0 -21
- package/dist-tests/api/ping.spec.js.map +0 -1
- package/dist-tests/helpers/auth.js +0 -41
- package/dist-tests/helpers/auth.js.map +0 -1
- package/dist-tests/helpers/env.js +0 -11
- package/dist-tests/helpers/env.js.map +0 -1
- package/docs/agent-builder/notebook-lm-prompt-for-agent-builder.md +0 -136
- package/docs/agent-builder/team-ready-note-agent-builder.md +0 -305
- package/docs/agent-hub-grooming.md +0 -301
- package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +0 -438
- package/docs/dashboards/dashboard-curl-smoke-tests.txt +0 -146
- package/docs/dashboards/delete-legacy-dashboard-metadata.sql +0 -172
- package/docs/datasource-introspection-ddl-analysis.md +0 -326
- package/docs/datasource-introspection-implementation-plan.md +0 -306
- package/docs/grouping-enhancements.md +0 -89
- package/docs/java-spring/README.md +0 -3
- package/docs/java-spring/solid-core-module-deep-dive-report.md +0 -1317
- package/docs/module-package-import-handoff.md +0 -691
- package/docs/seed-changes.md +0 -65
- package/docs/test-data-workflow.md +0 -200
- package/docs/type-declaration-import-issue.md +0 -24
- package/docs/workflow/business-automation-example-notes.md +0 -309
- package/docs/workflow/data-engineering-pipeline-example-notes.md +0 -330
- package/docs/workflow/foreach-example-notes.md +0 -187
- package/docs/workflow/hello-world-example-notes.md +0 -271
- package/docs/workflow/kestra-concepts-plugins-blueprints.md +0 -315
- package/docs/workflow/loop-until-example-notes.md +0 -198
- package/docs/workflow/microservices-and-apis-example-notes.md +0 -264
- package/docs/workflow/samples.md +0 -25
- package/docs/workflow/what-is-kestra.md +0 -79
- package/docs/workflow/workflow-core-module-handoff-summary.md +0 -191
- package/docs/workflow/workflow-module-brd.md +0 -185
- package/docs/workflow/workflow-module-domain-model.md +0 -252
- package/docs/workflow/workflow-module-metadata-dsl.md +0 -302
- package/docs/workflow/workflow-module-technical-spec.md +0 -293
- package/docs/workflow/workflow-node-type-contracts.md +0 -635
- package/docs/workflow/workflow-node-ui-metadata-contract.md +0 -1262
- package/docs/workflow/workflow-solidx-model-field-spec.md +0 -284
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ConfigService } from '@nestjs/config';
|
|
2
|
+
import { JwtService } from '@nestjs/jwt';
|
|
3
|
+
import { MediaStorageProviderMetadata } from '../entities/media-storage-provider-metadata.entity';
|
|
4
|
+
import { S3FileService } from '../services/file';
|
|
5
|
+
import { SettingService } from '../services/setting.service';
|
|
6
|
+
export declare const MEDIA_DOWNLOAD_TOKEN_AUDIENCE = "media-download";
|
|
7
|
+
export interface MediaDownloadTokenPayload {
|
|
8
|
+
mediaId: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class MediaDownloadUrlService {
|
|
11
|
+
private readonly jwtService;
|
|
12
|
+
private readonly s3FileService;
|
|
13
|
+
private readonly settingService;
|
|
14
|
+
private readonly configService;
|
|
15
|
+
private readonly logger;
|
|
16
|
+
constructor(jwtService: JwtService, s3FileService: S3FileService, settingService: SettingService, configService: ConfigService);
|
|
17
|
+
resolveDownloadUrl(mediaId: number, relativeUri: string, storageProvider?: MediaStorageProviderMetadata): Promise<string>;
|
|
18
|
+
verifyDownloadToken(token: string): Promise<MediaDownloadTokenPayload>;
|
|
19
|
+
private mintDownloadToken;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=media-download-url.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-download-url.service.d.ts","sourceRoot":"","sources":["../../src/services/media-download-url.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,4BAA4B,EAAE,MAAM,qDAAqD,CAAC;AACnG,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAG9D,eAAO,MAAM,6BAA6B,mBAAmB,CAAC;AAG9D,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBACa,uBAAuB;IAIhC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa;IANhC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;gBAGhD,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,aAAa,EAC5B,cAAc,EAAE,cAAc,EAC9B,aAAa,EAAE,aAAa;IAGzC,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,4BAA4B,GAAG,OAAO,CAAC,MAAM,CAAC;IAuBzH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAO5E,OAAO,CAAC,iBAAiB;CAQ1B"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var MediaDownloadUrlService_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.MediaDownloadUrlService = exports.MEDIA_DOWNLOAD_TOKEN_AUDIENCE = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const config_1 = require("@nestjs/config");
|
|
16
|
+
const jwt_1 = require("@nestjs/jwt");
|
|
17
|
+
const create_media_storage_provider_metadata_dto_1 = require("../dtos/create-media-storage-provider-metadata.dto");
|
|
18
|
+
const file_1 = require("./file");
|
|
19
|
+
const media_storage_utils_1 = require("./media-storage.utils");
|
|
20
|
+
const setting_service_1 = require("./setting.service");
|
|
21
|
+
exports.MEDIA_DOWNLOAD_TOKEN_AUDIENCE = 'media-download';
|
|
22
|
+
const DEFAULT_SIGNED_URL_EXPIRY_MINUTES = 60;
|
|
23
|
+
let MediaDownloadUrlService = MediaDownloadUrlService_1 = class MediaDownloadUrlService {
|
|
24
|
+
constructor(jwtService, s3FileService, settingService, configService) {
|
|
25
|
+
this.jwtService = jwtService;
|
|
26
|
+
this.s3FileService = s3FileService;
|
|
27
|
+
this.settingService = settingService;
|
|
28
|
+
this.configService = configService;
|
|
29
|
+
this.logger = new common_1.Logger(MediaDownloadUrlService_1.name);
|
|
30
|
+
}
|
|
31
|
+
async resolveDownloadUrl(mediaId, relativeUri, storageProvider) {
|
|
32
|
+
const expiryMinutes = storageProvider?.signedUrlExpiry ?? DEFAULT_SIGNED_URL_EXPIRY_MINUTES;
|
|
33
|
+
if (storageProvider?.type === create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.AwsS3) {
|
|
34
|
+
if (storageProvider?.bucketName) {
|
|
35
|
+
return this.s3FileService.getUrl(`${storageProvider.bucketName}:${relativeUri}`, { region: (0, media_storage_utils_1.getEffectiveS3Region)(this.configService, storageProvider.region), expiresIn: expiryMinutes * 60 });
|
|
36
|
+
}
|
|
37
|
+
this.logger.warn(`Media id ${mediaId}: AwsS3 provider missing bucketName; falling back to app-hosted token URL`);
|
|
38
|
+
}
|
|
39
|
+
const token = await this.mintDownloadToken(mediaId, expiryMinutes);
|
|
40
|
+
const downloadPath = `/api/media/${mediaId}/download?token=${token}`;
|
|
41
|
+
const baseUrl = this.settingService.getConfigValue('baseUrl');
|
|
42
|
+
return `${String(baseUrl).replace(/\/+$/, '')}${downloadPath}`;
|
|
43
|
+
}
|
|
44
|
+
async verifyDownloadToken(token) {
|
|
45
|
+
return this.jwtService.verifyAsync(token, {
|
|
46
|
+
secret: this.settingService.getConfigValue('secret'),
|
|
47
|
+
audience: exports.MEDIA_DOWNLOAD_TOKEN_AUDIENCE,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
mintDownloadToken(mediaId, expiryMinutes) {
|
|
51
|
+
const payload = { mediaId };
|
|
52
|
+
return this.jwtService.signAsync(payload, {
|
|
53
|
+
secret: this.settingService.getConfigValue('secret'),
|
|
54
|
+
audience: exports.MEDIA_DOWNLOAD_TOKEN_AUDIENCE,
|
|
55
|
+
expiresIn: expiryMinutes * 60,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
exports.MediaDownloadUrlService = MediaDownloadUrlService;
|
|
60
|
+
exports.MediaDownloadUrlService = MediaDownloadUrlService = MediaDownloadUrlService_1 = __decorate([
|
|
61
|
+
(0, common_1.Injectable)(),
|
|
62
|
+
__metadata("design:paramtypes", [jwt_1.JwtService,
|
|
63
|
+
file_1.S3FileService,
|
|
64
|
+
setting_service_1.SettingService,
|
|
65
|
+
config_1.ConfigService])
|
|
66
|
+
], MediaDownloadUrlService);
|
|
67
|
+
//# sourceMappingURL=media-download-url.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-download-url.service.js","sourceRoot":"","sources":["../../src/services/media-download-url.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAoD;AACpD,2CAA+C;AAC/C,qCAAyC;AACzC,mHAA+F;AAE/F,iCAAkD;AAClD,+DAAwE;AACxE,uDAA8D;AAGjD,QAAA,6BAA6B,GAAG,gBAAgB,CAAC;AAC9D,MAAM,iCAAiC,GAAG,EAAE,CAAC;AAOtC,IAAM,uBAAuB,+BAA7B,MAAM,uBAAuB;IAGlC,YACmB,UAAsB,EACtB,aAA4B,EAC5B,cAA8B,EAC9B,aAA4B;QAH5B,eAAU,GAAV,UAAU,CAAY;QACtB,kBAAa,GAAb,aAAa,CAAe;QAC5B,mBAAc,GAAd,cAAc,CAAgB;QAC9B,kBAAa,GAAb,aAAa,CAAe;QAN9B,WAAM,GAAG,IAAI,eAAM,CAAC,yBAAuB,CAAC,IAAI,CAAC,CAAC;IAO/D,CAAC;IAEL,KAAK,CAAC,kBAAkB,CAAC,OAAe,EAAE,WAAmB,EAAE,eAA8C;QAC3G,MAAM,aAAa,GAAG,eAAe,EAAE,eAAe,IAAI,iCAAiC,CAAC;QAE5F,IAAK,eAAe,EAAE,IAAiC,KAAK,qEAAwB,CAAC,KAAK,EAAE,CAAC;YAC3F,IAAI,eAAe,EAAE,UAAU,EAAE,CAAC;gBAChC,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAC9B,GAAG,eAAe,CAAC,UAAU,IAAI,WAAW,EAAE,EAC9C,EAAE,MAAM,EAAE,IAAA,0CAAoB,EAAC,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,aAAa,GAAG,EAAE,EAAE,CAC5G,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,OAAO,2EAA2E,CAAC,CAAC;QACnH,CAAC;QAMD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QACnE,MAAM,YAAY,GAAG,cAAc,OAAO,mBAAmB,KAAK,EAAE,CAAC;QACrE,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAmB,SAAS,CAAC,CAAC;QAChF,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,YAAY,EAAE,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,KAAa;QACrC,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,CAA4B,KAAK,EAAE;YACnE,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAmB,QAAQ,CAAC;YACtE,QAAQ,EAAE,qCAA6B;SACxC,CAAC,CAAC;IACL,CAAC;IAEO,iBAAiB,CAAC,OAAe,EAAE,aAAqB;QAC9D,MAAM,OAAO,GAA8B,EAAE,OAAO,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE;YACxC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,cAAc,CAAmB,QAAQ,CAAC;YACtE,QAAQ,EAAE,qCAA6B;YACvC,SAAS,EAAE,aAAa,GAAG,EAAE;SAC9B,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAhDY,0DAAuB;kCAAvB,uBAAuB;IADnC,IAAA,mBAAU,GAAE;qCAKoB,gBAAU;QACP,oBAAa;QACZ,gCAAc;QACf,sBAAa;GAPpC,uBAAuB,CAgDnC","sourcesContent":["import { Injectable, Logger } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { JwtService } from '@nestjs/jwt';\nimport { MediaStorageProviderType } from 'src/dtos/create-media-storage-provider-metadata.dto';\nimport { MediaStorageProviderMetadata } from 'src/entities/media-storage-provider-metadata.entity';\nimport { S3FileService } from 'src/services/file';\nimport { getEffectiveS3Region } from 'src/services/media-storage.utils';\nimport { SettingService } from 'src/services/setting.service';\nimport type { SolidCoreSetting } from 'src/services/settings/default-settings-provider.service';\n\nexport const MEDIA_DOWNLOAD_TOKEN_AUDIENCE = 'media-download';\nconst DEFAULT_SIGNED_URL_EXPIRY_MINUTES = 60;\n\nexport interface MediaDownloadTokenPayload {\n mediaId: number;\n}\n\n@Injectable()\nexport class MediaDownloadUrlService {\n private readonly logger = new Logger(MediaDownloadUrlService.name);\n\n constructor(\n private readonly jwtService: JwtService,\n private readonly s3FileService: S3FileService,\n private readonly settingService: SettingService,\n private readonly configService: ConfigService,\n ) { }\n\n async resolveDownloadUrl(mediaId: number, relativeUri: string, storageProvider?: MediaStorageProviderMetadata): Promise<string> {\n const expiryMinutes = storageProvider?.signedUrlExpiry ?? DEFAULT_SIGNED_URL_EXPIRY_MINUTES;\n\n if ((storageProvider?.type as MediaStorageProviderType) === MediaStorageProviderType.AwsS3) {\n if (storageProvider?.bucketName) {\n return this.s3FileService.getUrl(\n `${storageProvider.bucketName}:${relativeUri}`,\n { region: getEffectiveS3Region(this.configService, storageProvider.region), expiresIn: expiryMinutes * 60 },\n );\n }\n this.logger.warn(`Media id ${mediaId}: AwsS3 provider missing bucketName; falling back to app-hosted token URL`);\n }\n\n // Filesystem (or misconfigured S3) has no native presigned-URL mechanism, so mint our\n // own short-lived token and embed it in the download URL - the token alone authorizes\n // the request (see MediaSignedUrlGuard), so it works in a plain <img src> with no\n // Authorization header needed.\n const token = await this.mintDownloadToken(mediaId, expiryMinutes);\n const downloadPath = `/api/media/${mediaId}/download?token=${token}`;\n const baseUrl = this.settingService.getConfigValue<SolidCoreSetting>('baseUrl');\n return `${String(baseUrl).replace(/\\/+$/, '')}${downloadPath}`;\n }\n\n async verifyDownloadToken(token: string): Promise<MediaDownloadTokenPayload> {\n return this.jwtService.verifyAsync<MediaDownloadTokenPayload>(token, {\n secret: this.settingService.getConfigValue<SolidCoreSetting>('secret'),\n audience: MEDIA_DOWNLOAD_TOKEN_AUDIENCE,\n });\n }\n\n private mintDownloadToken(mediaId: number, expiryMinutes: number): Promise<string> {\n const payload: MediaDownloadTokenPayload = { mediaId };\n return this.jwtService.signAsync(payload, {\n secret: this.settingService.getConfigValue<SolidCoreSetting>('secret'),\n audience: MEDIA_DOWNLOAD_TOKEN_AUDIENCE,\n expiresIn: expiryMinutes * 60,\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ConfigService } from '@nestjs/config';
|
|
2
|
+
import { FieldMetadata } from '../entities/field-metadata.entity';
|
|
3
|
+
import { MediaStorageProviderMetadata } from '../entities/media-storage-provider-metadata.entity';
|
|
4
|
+
import { SettingService } from '../services/setting.service';
|
|
5
|
+
export declare const DEFAULT_PRIVATE_MEDIA_STORAGE_DIR = "media-private-files-storage";
|
|
6
|
+
export interface MediaRecordCreateInput {
|
|
7
|
+
entityId: number;
|
|
8
|
+
modelMetadataId: number;
|
|
9
|
+
mediaStorageProviderMetadataId: number;
|
|
10
|
+
fieldMetadataId: number;
|
|
11
|
+
relativeUri: string;
|
|
12
|
+
mimeType?: string;
|
|
13
|
+
fileSize?: number;
|
|
14
|
+
originalFileName?: string;
|
|
15
|
+
isPublic?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function buildStoredMediaFileName(file: Pick<Express.Multer.File, 'filename' | 'originalname'>): string;
|
|
18
|
+
export declare function buildDiskMediaPath(fileName: string, settingService: Pick<SettingService, 'getConfigValue'>, storageProvider?: Pick<MediaStorageProviderMetadata, 'localPath' | 'isPublic'>): string;
|
|
19
|
+
export declare function getEffectiveS3Region(configService: Pick<ConfigService, 'get'>, providerRegion?: string): string | undefined;
|
|
20
|
+
export declare function resolveMediaIsPublic(storageProvider?: Pick<MediaStorageProviderMetadata, 'isPublic'>): boolean | undefined;
|
|
21
|
+
export declare function resolveStoredMediaIsPublic(currentValue: boolean | undefined, storageProvider?: Pick<MediaStorageProviderMetadata, 'isPublic'>): boolean | undefined;
|
|
22
|
+
export declare function buildMediaRecordCreateInput(entityId: number, mediaFieldMetadata: Pick<FieldMetadata, 'id' | 'model'> & {
|
|
23
|
+
model: {
|
|
24
|
+
id: number;
|
|
25
|
+
};
|
|
26
|
+
}, storageProvider: Pick<MediaStorageProviderMetadata, 'id'>, overrides: Pick<MediaRecordCreateInput, 'relativeUri'> & Partial<Omit<MediaRecordCreateInput, 'entityId' | 'modelMetadataId' | 'mediaStorageProviderMetadataId' | 'fieldMetadataId' | 'relativeUri'>>): MediaRecordCreateInput;
|
|
27
|
+
//# sourceMappingURL=media-storage.utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-storage.utils.d.ts","sourceRoot":"","sources":["../../src/services/media-storage.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,4BAA4B,EAAE,MAAM,qDAAqD,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAI9D,eAAO,MAAM,iCAAiC,gCAAgC,CAAC;AAE/E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,8BAA8B,EAAE,MAAM,CAAC;IACvC,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAGD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,cAAc,CAAC,GAAG,MAAM,CAE7G;AAGD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAC,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,gBAAgB,CAAC,EAAC,eAAe,CAAC,EAAE,IAAI,CAAC,4BAA4B,EAAE,WAAW,GAAG,UAAU,CAAC,GAAI,MAAM,CAUlM;AAGD,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,EAAC,cAAc,CAAC,EAAE,MAAM,GAAI,MAAM,GAAG,SAAS,CAE3H;AAGD,wBAAgB,oBAAoB,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,4BAA4B,EAAE,UAAU,CAAC,GAAI,OAAO,GAAG,SAAS,CAM3H;AAGD,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,OAAO,GAAG,SAAS,EAAC,eAAe,CAAC,EAAC,IAAI,CAAC,4BAA4B,EAAE,UAAU,CAAC,GAAI,OAAO,GAAG,SAAS,CAMlK;AAGD,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG;IAAE,KAAK,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EACnF,eAAe,EAAE,IAAI,CAAC,4BAA4B,EAAE,IAAI,CAAC,EACzD,SAAS,EAAE,IAAI,CAAC,sBAAsB,EAAE,aAAa,CAAC,GAClD,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,UAAU,GAAG,iBAAiB,GAAG,gCAAgC,GAAG,iBAAiB,GAAG,aAAa,CAAC,CAAC,GAC/I,sBAAsB,CAQxB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DEFAULT_PRIVATE_MEDIA_STORAGE_DIR = void 0;
|
|
37
|
+
exports.buildStoredMediaFileName = buildStoredMediaFileName;
|
|
38
|
+
exports.buildDiskMediaPath = buildDiskMediaPath;
|
|
39
|
+
exports.getEffectiveS3Region = getEffectiveS3Region;
|
|
40
|
+
exports.resolveMediaIsPublic = resolveMediaIsPublic;
|
|
41
|
+
exports.resolveStoredMediaIsPublic = resolveStoredMediaIsPublic;
|
|
42
|
+
exports.buildMediaRecordCreateInput = buildMediaRecordCreateInput;
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const default_settings_provider_service_1 = require("./settings/default-settings-provider.service");
|
|
45
|
+
exports.DEFAULT_PRIVATE_MEDIA_STORAGE_DIR = 'media-private-files-storage';
|
|
46
|
+
function buildStoredMediaFileName(file) {
|
|
47
|
+
return `${file.filename}-${file.originalname}`;
|
|
48
|
+
}
|
|
49
|
+
function buildDiskMediaPath(fileName, settingService, storageProvider) {
|
|
50
|
+
const publicBase = settingService.getConfigValue('fileStorageDir') || default_settings_provider_service_1.DEFAULT_MEDIA_FILE_STORAGE_DIR;
|
|
51
|
+
const privateBase = exports.DEFAULT_PRIVATE_MEDIA_STORAGE_DIR;
|
|
52
|
+
const providerBase = storageProvider?.localPath || (storageProvider?.isPublic === false ? privateBase : publicBase);
|
|
53
|
+
if (path.isAbsolute(fileName) || fileName.startsWith(`${publicBase}/`) || fileName.startsWith(`${privateBase}/`) || (!!storageProvider?.localPath && fileName.startsWith(`${storageProvider.localPath}/`))) {
|
|
54
|
+
return fileName;
|
|
55
|
+
}
|
|
56
|
+
return `${providerBase}/${fileName}`;
|
|
57
|
+
}
|
|
58
|
+
function getEffectiveS3Region(configService, providerRegion) {
|
|
59
|
+
return providerRegion || configService.get('S3_AWS_REGION_NAME');
|
|
60
|
+
}
|
|
61
|
+
function resolveMediaIsPublic(storageProvider) {
|
|
62
|
+
if (!storageProvider) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return storageProvider.isPublic !== false;
|
|
66
|
+
}
|
|
67
|
+
function resolveStoredMediaIsPublic(currentValue, storageProvider) {
|
|
68
|
+
if (typeof currentValue === 'boolean') {
|
|
69
|
+
return currentValue;
|
|
70
|
+
}
|
|
71
|
+
return resolveMediaIsPublic(storageProvider);
|
|
72
|
+
}
|
|
73
|
+
function buildMediaRecordCreateInput(entityId, mediaFieldMetadata, storageProvider, overrides) {
|
|
74
|
+
return {
|
|
75
|
+
entityId,
|
|
76
|
+
modelMetadataId: mediaFieldMetadata.model.id,
|
|
77
|
+
mediaStorageProviderMetadataId: storageProvider.id,
|
|
78
|
+
fieldMetadataId: mediaFieldMetadata.id,
|
|
79
|
+
...overrides,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=media-storage.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-storage.utils.js","sourceRoot":"","sources":["../../src/services/media-storage.utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,4DAEC;AAGD,gDAUC;AAGD,oDAEC;AAGD,oDAMC;AAGD,gEAMC;AAGD,kEAcC;AA7ED,2CAA6B;AAI7B,oGAAyG;AAG5F,QAAA,iCAAiC,GAAG,6BAA6B,CAAC;AAe/E,SAAgB,wBAAwB,CAAC,IAA4D;IACnG,OAAO,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;AACjD,CAAC;AAGD,SAAgB,kBAAkB,CAAC,QAAgB,EAAC,cAAsD,EAAC,eAA8E;IACvL,MAAM,UAAU,GAAG,cAAc,CAAC,cAAc,CAAmB,gBAAgB,CAAC,IAAI,kEAA8B,CAAC;IACvH,MAAM,WAAW,GAAG,yCAAiC,CAAC;IACtD,MAAM,YAAY,GAAG,eAAe,EAAE,SAAS,IAAI,CAAC,eAAe,EAAE,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAEpH,IAAK,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,UAAU,GAAG,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,WAAW,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,EAAE,SAAS,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,eAAe,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC;QAC5M,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,GAAG,YAAY,IAAI,QAAQ,EAAE,CAAC;AACvC,CAAC;AAGD,SAAgB,oBAAoB,CAAC,aAAyC,EAAC,cAAuB;IACpG,OAAO,cAAc,IAAI,aAAa,CAAC,GAAG,CAAS,oBAAoB,CAAC,CAAC;AAC3E,CAAC;AAGD,SAAgB,oBAAoB,CAAC,eAAgE;IACnG,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,eAAe,CAAC,QAAQ,KAAK,KAAK,CAAC;AAC5C,CAAC;AAGD,SAAgB,0BAA0B,CAAC,YAAiC,EAAC,eAA+D;IAC1I,IAAI,OAAO,YAAY,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,OAAO,oBAAoB,CAAC,eAAe,CAAC,CAAC;AAC/C,CAAC;AAGD,SAAgB,2BAA2B,CACzC,QAAgB,EAChB,kBAAmF,EACnF,eAAyD,EACzD,SACgJ;IAEhJ,OAAO;QACL,QAAQ;QACR,eAAe,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE;QAC5C,8BAA8B,EAAE,eAAe,CAAC,EAAE;QAClD,eAAe,EAAE,kBAAkB,CAAC,EAAE;QACtC,GAAG,SAAS;KACb,CAAC;AACJ,CAAC","sourcesContent":["import { ConfigService } from '@nestjs/config';\nimport * as path from 'path';\nimport { FieldMetadata } from 'src/entities/field-metadata.entity';\nimport { MediaStorageProviderMetadata } from 'src/entities/media-storage-provider-metadata.entity';\nimport { SettingService } from 'src/services/setting.service';\nimport { DEFAULT_MEDIA_FILE_STORAGE_DIR } from 'src/services/settings/default-settings-provider.service';\nimport type { SolidCoreSetting } from 'src/services/settings/default-settings-provider.service';\n\nexport const DEFAULT_PRIVATE_MEDIA_STORAGE_DIR = 'media-private-files-storage';\n\nexport interface MediaRecordCreateInput {\n entityId: number;\n modelMetadataId: number;\n mediaStorageProviderMetadataId: number;\n fieldMetadataId: number;\n relativeUri: string;\n mimeType?: string;\n fileSize?: number;\n originalFileName?: string;\n isPublic?: boolean;\n}\n\n// Builds the stored file name format shared by media storage implementations.\nexport function buildStoredMediaFileName(file: Pick<Express.Multer.File, 'filename' | 'originalname'>): string {\n return `${file.filename}-${file.originalname}`;\n}\n\n// Resolves the on-disk path for a media file based on settings and provider visibility.\nexport function buildDiskMediaPath(fileName: string,settingService: Pick<SettingService, 'getConfigValue'>,storageProvider?: Pick<MediaStorageProviderMetadata, 'localPath' | 'isPublic'>,): string {\n const publicBase = settingService.getConfigValue<SolidCoreSetting>('fileStorageDir') || DEFAULT_MEDIA_FILE_STORAGE_DIR;\n const privateBase = DEFAULT_PRIVATE_MEDIA_STORAGE_DIR;\n const providerBase = storageProvider?.localPath || (storageProvider?.isPublic === false ? privateBase : publicBase);\n\n if ( path.isAbsolute(fileName) || fileName.startsWith(`${publicBase}/`) || fileName.startsWith(`${privateBase}/`) || (!!storageProvider?.localPath && fileName.startsWith(`${storageProvider.localPath}/`))) {\n return fileName;\n }\n\n return `${providerBase}/${fileName}`;\n}\n\n// Returns the S3 region from the provider when present, otherwise falls back to app config.\nexport function getEffectiveS3Region(configService: Pick<ConfigService, 'get'>,providerRegion?: string,): string | undefined {\n return providerRegion || configService.get<string>('S3_AWS_REGION_NAME');\n}\n\n// Resolves the effective public/private flag for a media storage provider.\nexport function resolveMediaIsPublic(storageProvider?: Pick<MediaStorageProviderMetadata, 'isPublic'>,): boolean | undefined {\n if (!storageProvider) {\n return undefined;\n }\n\n return storageProvider.isPublic !== false;\n}\n\n// Preserves an explicit media visibility value or derives it from the storage provider.\nexport function resolveStoredMediaIsPublic(currentValue: boolean | undefined,storageProvider?:Pick<MediaStorageProviderMetadata, 'isPublic'>,): boolean | undefined {\n if (typeof currentValue === 'boolean') {\n return currentValue;\n }\n\n return resolveMediaIsPublic(storageProvider);\n}\n\n// Builds the shared media record payload used before saving media metadata to the database.\nexport function buildMediaRecordCreateInput(\n entityId: number,\n mediaFieldMetadata: Pick<FieldMetadata, 'id' | 'model'> & { model: { id: number } },\n storageProvider: Pick<MediaStorageProviderMetadata, 'id'>,\n overrides: Pick<MediaRecordCreateInput, 'relativeUri'>\n & Partial<Omit<MediaRecordCreateInput, 'entityId' | 'modelMetadataId' | 'mediaStorageProviderMetadataId' | 'fieldMetadataId' | 'relativeUri'>>,\n): MediaRecordCreateInput {\n return {\n entityId,\n modelMetadataId: mediaFieldMetadata.model.id,\n mediaStorageProviderMetadataId: storageProvider.id,\n fieldMetadataId: mediaFieldMetadata.id,\n ...overrides,\n };\n}\n"]}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ModuleRef } from "@nestjs/core";
|
|
2
2
|
import { EntityManager } from 'typeorm';
|
|
3
|
+
import { Readable } from 'stream';
|
|
3
4
|
import { ConfigService } from '@nestjs/config';
|
|
4
5
|
import { CRUDService } from '../services/crud.service';
|
|
5
6
|
import { DiskFileService, S3FileService } from '../services/file';
|
|
7
|
+
import { MediaDownloadUrlService } from '../services/media-download-url.service';
|
|
6
8
|
import { BasicFilterDto } from '../dtos/basic-filters.dto';
|
|
7
9
|
import { Media } from '../entities/media.entity';
|
|
8
10
|
import { FieldMetadataRepository } from '../repository/field-metadata.repository';
|
|
@@ -13,17 +15,31 @@ export declare class MediaService extends CRUDService<Media> {
|
|
|
13
15
|
readonly configService: ConfigService;
|
|
14
16
|
readonly diskFileService: DiskFileService;
|
|
15
17
|
readonly s3FileService: S3FileService;
|
|
18
|
+
private readonly mediaDownloadUrlService;
|
|
16
19
|
readonly entityManager: EntityManager;
|
|
17
20
|
readonly repo: MediaRepository;
|
|
18
21
|
private readonly modelMetadataRepo;
|
|
19
22
|
private readonly mediaStorageProviderMetadataRepo;
|
|
20
23
|
private readonly fieldMetadataRepo;
|
|
21
24
|
readonly moduleRef: ModuleRef;
|
|
22
|
-
|
|
25
|
+
private readonly logger;
|
|
26
|
+
constructor(configService: ConfigService, diskFileService: DiskFileService, s3FileService: S3FileService, mediaDownloadUrlService: MediaDownloadUrlService, entityManager: EntityManager, repo: MediaRepository, modelMetadataRepo: ModelMetadataRepository, mediaStorageProviderMetadataRepo: MediaStorageProviderMetadataRepository, fieldMetadataRepo: FieldMetadataRepository, moduleRef: ModuleRef);
|
|
23
27
|
find(basicFilterDto: BasicFilterDto, solidRequestContext?: any): Promise<any>;
|
|
24
|
-
|
|
28
|
+
findOne(id: number, query?: any, solidRequestContext?: any): Promise<Media>;
|
|
29
|
+
upload(createDto: any, files: Array<Express.Multer.File>, _solidRequestContext?: any): Promise<any[]>;
|
|
25
30
|
remove(id: number): Promise<Media>;
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
fileDownloadStream(media: Media): Promise<{
|
|
32
|
+
stream: Readable | null;
|
|
33
|
+
fileName: string;
|
|
34
|
+
mimeType: string;
|
|
35
|
+
redirectUrl?: string;
|
|
36
|
+
}>;
|
|
37
|
+
delete(id: number, solidRequestContext?: any): Promise<Media>;
|
|
38
|
+
deleteMany(ids: number[], solidRequestContext?: any): Promise<any>;
|
|
39
|
+
private decorateMediaRecords;
|
|
40
|
+
private decorateMediaRecord;
|
|
41
|
+
private resolveMediaUrl;
|
|
42
|
+
private deletePhysicalFile;
|
|
43
|
+
private resolveMediaStorageProvider;
|
|
28
44
|
}
|
|
29
45
|
//# sourceMappingURL=media.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.service.d.ts","sourceRoot":"","sources":["../../src/services/media.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAM,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"media.service.d.ts","sourceRoot":"","sources":["../../src/services/media.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAM,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAIlF,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAElD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AACnF,OAAO,EAAE,sCAAsC,EAAE,MAAM,2DAA2D,CAAC;AACnH,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0CAA0C,CAAC;AAInF,qBACa,YAAa,SAAQ,WAAW,CAAC,KAAK,CAAC;IAIhD,QAAQ,CAAC,aAAa,EAAE,aAAa;IACrC,QAAQ,CAAC,eAAe,EAAE,eAAe;IACzC,QAAQ,CAAC,aAAa,EAAE,aAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IAExC,QAAQ,CAAC,aAAa,EAAE,aAAa;IAGrC,QAAQ,CAAC,IAAI,EAAE,eAAe;IAQ9B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,gCAAgC;IACjD,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,QAAQ,CAAC,SAAS,EAAE,SAAS;IAtB/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;gBAG7C,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EACpB,uBAAuB,EAAE,uBAAuB,EAExD,aAAa,EAAE,aAAa,EAG5B,IAAI,EAAE,eAAe,EAQb,iBAAiB,EAAE,uBAAuB,EAC1C,gCAAgC,EAAE,sCAAsC,EACxE,iBAAiB,EAAE,uBAAuB,EAClD,SAAS,EAAE,SAAS;IAKzB,IAAI,CAAC,cAAc,EAAE,cAAc,EAAE,mBAAmB,GAAE,GAAQ;IAalE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,GAAQ,EAAE,mBAAmB,GAAE,GAAQ;IAQlE,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,oBAAoB,GAAE,GAAQ;IAmExF,MAAM,CAAC,EAAE,EAAE,MAAM;IAqBjB,kBAAkB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA2BhI,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,mBAAmB,GAAE,GAAQ;IAehD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,mBAAmB,GAAE,GAAQ;YAiB/C,oBAAoB;YAMpB,mBAAmB;YAMnB,eAAe;YAsBf,kBAAkB;YA8BlB,2BAA2B;CAgB1C"}
|
|
@@ -44,6 +44,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
44
44
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
45
45
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
46
46
|
};
|
|
47
|
+
var MediaService_1;
|
|
47
48
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
49
|
exports.MediaService = void 0;
|
|
49
50
|
const common_1 = require("@nestjs/common");
|
|
@@ -51,99 +52,103 @@ const core_1 = require("@nestjs/core");
|
|
|
51
52
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
52
53
|
const typeorm_2 = require("typeorm");
|
|
53
54
|
const path = __importStar(require("path"));
|
|
54
|
-
const default_settings_provider_service_1 = require("./settings/default-settings-provider.service");
|
|
55
55
|
const config_1 = require("@nestjs/config");
|
|
56
56
|
const crud_service_1 = require("./crud.service");
|
|
57
57
|
const file_1 = require("./file");
|
|
58
|
+
const media_download_url_service_1 = require("./media-download-url.service");
|
|
58
59
|
const error_messages_1 = require("../constants/error-messages");
|
|
59
60
|
const create_media_storage_provider_metadata_dto_1 = require("../dtos/create-media-storage-provider-metadata.dto");
|
|
60
61
|
const field_metadata_repository_1 = require("../repository/field-metadata.repository");
|
|
61
62
|
const media_storage_provider_metadata_repository_1 = require("../repository/media-storage-provider-metadata.repository");
|
|
62
63
|
const media_repository_1 = require("../repository/media.repository");
|
|
63
64
|
const model_metadata_repository_1 = require("../repository/model-metadata.repository");
|
|
65
|
+
const media_storage_utils_1 = require("./media-storage.utils");
|
|
64
66
|
const mediaStorageProviders_1 = require("./mediaStorageProviders");
|
|
65
|
-
let MediaService = class MediaService extends crud_service_1.CRUDService {
|
|
66
|
-
constructor(configService, diskFileService, s3FileService, entityManager, repo, modelMetadataRepo, mediaStorageProviderMetadataRepo, fieldMetadataRepo, moduleRef) {
|
|
67
|
+
let MediaService = MediaService_1 = class MediaService extends crud_service_1.CRUDService {
|
|
68
|
+
constructor(configService, diskFileService, s3FileService, mediaDownloadUrlService, entityManager, repo, modelMetadataRepo, mediaStorageProviderMetadataRepo, fieldMetadataRepo, moduleRef) {
|
|
67
69
|
super(entityManager, repo, 'media', 'solid-core', moduleRef);
|
|
68
70
|
this.configService = configService;
|
|
69
71
|
this.diskFileService = diskFileService;
|
|
70
72
|
this.s3FileService = s3FileService;
|
|
73
|
+
this.mediaDownloadUrlService = mediaDownloadUrlService;
|
|
71
74
|
this.entityManager = entityManager;
|
|
72
75
|
this.repo = repo;
|
|
73
76
|
this.modelMetadataRepo = modelMetadataRepo;
|
|
74
77
|
this.mediaStorageProviderMetadataRepo = mediaStorageProviderMetadataRepo;
|
|
75
78
|
this.fieldMetadataRepo = fieldMetadataRepo;
|
|
76
79
|
this.moduleRef = moduleRef;
|
|
80
|
+
this.logger = new common_1.Logger(MediaService_1.name);
|
|
77
81
|
}
|
|
78
82
|
async find(basicFilterDto, solidRequestContext = {}) {
|
|
79
83
|
const data = await super.find(basicFilterDto, solidRequestContext);
|
|
80
84
|
if (data.records) {
|
|
81
|
-
|
|
82
|
-
const mediaStorageProvider = media.mediaStorageProviderMetadata;
|
|
83
|
-
if (mediaStorageProvider?.type === create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.Filesystem) {
|
|
84
|
-
media.relativeUri = await this.diskFileService.getUrl(this.getFullFilePathForDisk(media.relativeUri));
|
|
85
|
-
}
|
|
86
|
-
else if (mediaStorageProvider?.type === create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.AwsS3) {
|
|
87
|
-
media.relativeUri = await this.s3FileService.getUrl(`${mediaStorageProvider.bucketName}:${media.relativeUri}`, { region: mediaStorageProvider.region });
|
|
88
|
-
}
|
|
89
|
-
}
|
|
85
|
+
await this.decorateMediaRecords(data.records);
|
|
90
86
|
}
|
|
91
87
|
if (data.groupRecords) {
|
|
92
88
|
for (const group of data.groupRecords) {
|
|
93
|
-
|
|
94
|
-
const mediaStorageProvider = media.mediaStorageProviderMetadata;
|
|
95
|
-
if (mediaStorageProvider?.type === create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.Filesystem) {
|
|
96
|
-
media.relativeUri = await this.diskFileService.getUrl(this.getFullFilePathForDisk(media.relativeUri));
|
|
97
|
-
}
|
|
98
|
-
else if (mediaStorageProvider?.type === create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.AwsS3) {
|
|
99
|
-
media.relativeUri = await this.s3FileService.getUrl(`${mediaStorageProvider.bucketName}:${media.relativeUri}`, { region: mediaStorageProvider.region });
|
|
100
|
-
}
|
|
101
|
-
}
|
|
89
|
+
await this.decorateMediaRecords(group.groupData.records);
|
|
102
90
|
}
|
|
103
91
|
}
|
|
104
92
|
return data;
|
|
105
93
|
}
|
|
106
|
-
async
|
|
107
|
-
|
|
94
|
+
async findOne(id, query = {}, solidRequestContext = {}) {
|
|
95
|
+
const media = await super.findOne(id, query, solidRequestContext);
|
|
96
|
+
if (media) {
|
|
97
|
+
await this.decorateMediaRecord(media);
|
|
98
|
+
}
|
|
99
|
+
return media;
|
|
100
|
+
}
|
|
101
|
+
async upload(createDto, files, _solidRequestContext = {}) {
|
|
102
|
+
if (!files || files.length === 0) {
|
|
108
103
|
throw new common_1.NotFoundException(error_messages_1.ERROR_MESSAGES.FILE_NOT_FOUND);
|
|
109
104
|
}
|
|
105
|
+
createDto['fieldMetadata'] = await this.fieldMetadataRepo.findOne({
|
|
106
|
+
where: {
|
|
107
|
+
id: createDto['fieldMetadataId']
|
|
108
|
+
},
|
|
109
|
+
relations: ['mediaStorageProvider', 'model'],
|
|
110
|
+
});
|
|
111
|
+
createDto['modelMetadata'] = await this.modelMetadataRepo.findOne({
|
|
112
|
+
where: {
|
|
113
|
+
id: createDto['modelMetadataId']
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
createDto['mediaStorageProviderMetadata'] = await this.mediaStorageProviderMetadataRepo.findOne({
|
|
117
|
+
where: {
|
|
118
|
+
id: createDto['mediaStorageProviderMetadataId']
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
createDto['mediaStorageProviderMetadata'] = createDto['mediaStorageProviderMetadata'] || createDto['fieldMetadata']?.mediaStorageProvider;
|
|
122
|
+
createDto['modelMetadata'] = createDto['modelMetadata'] || createDto['fieldMetadata']?.model;
|
|
123
|
+
if (!createDto['mediaStorageProviderMetadata']) {
|
|
124
|
+
throw new common_1.NotFoundException('Media storage provider metadata not found');
|
|
125
|
+
}
|
|
110
126
|
const savedMedias = [];
|
|
111
127
|
for (let i = 0; i < files.length; i++) {
|
|
112
|
-
createDto['fieldMetadata'] = await this.fieldMetadataRepo.findOne({
|
|
113
|
-
where: {
|
|
114
|
-
id: createDto['fieldMetadataId']
|
|
115
|
-
},
|
|
116
|
-
});
|
|
117
|
-
createDto['modelMetadata'] = await this.modelMetadataRepo.findOne({
|
|
118
|
-
where: {
|
|
119
|
-
id: createDto['modelMetadataId']
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
createDto['mediaStorageProviderMetadata'] = await this.mediaStorageProviderMetadataRepo.findOne({
|
|
123
|
-
where: {
|
|
124
|
-
id: createDto['mediaStorageProviderMetadataId']
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
128
|
const file = files[i];
|
|
128
|
-
|
|
129
|
+
const storageProvider = createDto.mediaStorageProviderMetadata;
|
|
130
|
+
const fileName = (0, media_storage_utils_1.buildStoredMediaFileName)(file);
|
|
131
|
+
switch (storageProvider.type) {
|
|
129
132
|
case create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.Filesystem:
|
|
130
|
-
const fileStoragePath =
|
|
133
|
+
const fileStoragePath = (0, media_storage_utils_1.buildDiskMediaPath)(fileName, this.settingService, storageProvider);
|
|
131
134
|
await this.diskFileService.copy(file.path, fileStoragePath);
|
|
132
|
-
createDto['relativeUri'] =
|
|
135
|
+
createDto['relativeUri'] = fileName;
|
|
133
136
|
break;
|
|
134
137
|
case create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.AwsS3:
|
|
135
|
-
const
|
|
136
|
-
const
|
|
138
|
+
const bucketName = storageProvider.bucketName;
|
|
139
|
+
const region = (0, media_storage_utils_1.getEffectiveS3Region)(this.configService, storageProvider.region);
|
|
137
140
|
const fileData = await this.diskFileService.read(file.path);
|
|
138
|
-
await this.s3FileService.write(`${bucketName}:${fileName}`, fileData, { contentType: file.mimetype });
|
|
141
|
+
await this.s3FileService.write(`${bucketName}:${fileName}`, fileData, { contentType: file.mimetype, region });
|
|
139
142
|
createDto['relativeUri'] = fileName;
|
|
140
143
|
break;
|
|
141
144
|
default:
|
|
142
145
|
break;
|
|
143
146
|
}
|
|
144
147
|
await this.diskFileService.delete(file.path);
|
|
148
|
+
createDto['isPublic'] = (0, media_storage_utils_1.resolveStoredMediaIsPublic)(createDto['isPublic'], storageProvider);
|
|
145
149
|
const media = this.repo.create(createDto);
|
|
146
150
|
const savedMedia = await this.repo.save(media);
|
|
151
|
+
savedMedia.isPublic = (0, media_storage_utils_1.resolveStoredMediaIsPublic)(savedMedia.isPublic, storageProvider);
|
|
147
152
|
savedMedias.push(savedMedia);
|
|
148
153
|
}
|
|
149
154
|
return savedMedias;
|
|
@@ -165,26 +170,123 @@ let MediaService = class MediaService extends crud_service_1.CRUDService {
|
|
|
165
170
|
await storageProvider.delete(modelEntity, media.fieldMetadata);
|
|
166
171
|
return this.repo.remove(media);
|
|
167
172
|
}
|
|
168
|
-
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
async fileDownloadStream(media) {
|
|
174
|
+
const loadedMedia = await this.repo.findOne({
|
|
175
|
+
where: { id: media.id },
|
|
176
|
+
relations: ['mediaStorageProviderMetadata'],
|
|
177
|
+
});
|
|
178
|
+
if (!loadedMedia || !loadedMedia.mediaStorageProviderMetadata) {
|
|
179
|
+
throw new common_1.NotFoundException(`Media with id ${media.id} not found`);
|
|
180
|
+
}
|
|
181
|
+
const fileName = loadedMedia.originalFileName || path.basename(loadedMedia.relativeUri || `${loadedMedia.id}`);
|
|
182
|
+
const mimeType = loadedMedia.mimeType || 'application/octet-stream';
|
|
183
|
+
switch (loadedMedia.mediaStorageProviderMetadata.type) {
|
|
184
|
+
case create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.Filesystem:
|
|
185
|
+
return {
|
|
186
|
+
stream: await this.diskFileService.readStream((0, media_storage_utils_1.buildDiskMediaPath)(loadedMedia.relativeUri, this.settingService, loadedMedia.mediaStorageProviderMetadata)),
|
|
187
|
+
fileName,
|
|
188
|
+
mimeType,
|
|
189
|
+
};
|
|
190
|
+
default:
|
|
191
|
+
throw new Error(`Unsupported media storage provider type ${loadedMedia.mediaStorageProviderMetadata.type}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async delete(id, solidRequestContext = {}) {
|
|
195
|
+
const media = await this.repo.findOne({
|
|
196
|
+
where: { id },
|
|
197
|
+
relations: ['mediaStorageProviderMetadata'],
|
|
198
|
+
});
|
|
199
|
+
const result = await super.delete(id, solidRequestContext);
|
|
200
|
+
if (media) {
|
|
201
|
+
await this.deletePhysicalFile(media);
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
async deleteMany(ids, solidRequestContext = {}) {
|
|
206
|
+
const mediaRecords = await this.repo.find({
|
|
207
|
+
where: {
|
|
208
|
+
id: (0, typeorm_2.In)(ids),
|
|
209
|
+
},
|
|
210
|
+
relations: ['mediaStorageProviderMetadata'],
|
|
211
|
+
});
|
|
212
|
+
const result = await super.deleteMany(ids, solidRequestContext);
|
|
213
|
+
for (const media of mediaRecords) {
|
|
214
|
+
await this.deletePhysicalFile(media);
|
|
215
|
+
}
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
async decorateMediaRecords(medias) {
|
|
219
|
+
for (const media of medias) {
|
|
220
|
+
await this.decorateMediaRecord(media);
|
|
173
221
|
}
|
|
174
|
-
return `${base}/${fileName}`;
|
|
175
222
|
}
|
|
176
|
-
|
|
177
|
-
|
|
223
|
+
async decorateMediaRecord(media) {
|
|
224
|
+
const mediaStorageProvider = await this.resolveMediaStorageProvider(media);
|
|
225
|
+
media.isPublic = (0, media_storage_utils_1.resolveStoredMediaIsPublic)(media.isPublic, mediaStorageProvider);
|
|
226
|
+
media.relativeUri = await this.resolveMediaUrl(media, mediaStorageProvider);
|
|
227
|
+
}
|
|
228
|
+
async resolveMediaUrl(media, mediaStorageProvider) {
|
|
229
|
+
const resolvedMediaStorageProvider = mediaStorageProvider || await this.resolveMediaStorageProvider(media);
|
|
230
|
+
const isPublic = (0, media_storage_utils_1.resolveStoredMediaIsPublic)(media.isPublic, resolvedMediaStorageProvider);
|
|
231
|
+
if (isPublic === false) {
|
|
232
|
+
return this.mediaDownloadUrlService.resolveDownloadUrl(media.id, media.relativeUri, resolvedMediaStorageProvider);
|
|
233
|
+
}
|
|
234
|
+
if (resolvedMediaStorageProvider?.type === create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.Filesystem) {
|
|
235
|
+
return this.diskFileService.getUrl((0, media_storage_utils_1.buildDiskMediaPath)(media.relativeUri, this.settingService, resolvedMediaStorageProvider));
|
|
236
|
+
}
|
|
237
|
+
if (resolvedMediaStorageProvider?.type === create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.AwsS3) {
|
|
238
|
+
return this.s3FileService.getUrl(`${resolvedMediaStorageProvider.bucketName}:${media.relativeUri}`, { region: (0, media_storage_utils_1.getEffectiveS3Region)(this.configService, resolvedMediaStorageProvider.region), expiresIn: 0 });
|
|
239
|
+
}
|
|
240
|
+
return media.relativeUri;
|
|
241
|
+
}
|
|
242
|
+
async deletePhysicalFile(media) {
|
|
243
|
+
if (!media?.relativeUri) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
const mediaStorageProvider = await this.resolveMediaStorageProvider(media);
|
|
248
|
+
if (!mediaStorageProvider) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
switch (mediaStorageProvider.type) {
|
|
252
|
+
case create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.Filesystem:
|
|
253
|
+
await this.diskFileService.delete((0, media_storage_utils_1.buildDiskMediaPath)(media.relativeUri, this.settingService, mediaStorageProvider));
|
|
254
|
+
return;
|
|
255
|
+
case create_media_storage_provider_metadata_dto_1.MediaStorageProviderType.AwsS3:
|
|
256
|
+
await this.s3FileService.delete(`${mediaStorageProvider.bucketName}:${media.relativeUri}`, { region: (0, media_storage_utils_1.getEffectiveS3Region)(this.configService, mediaStorageProvider.region) });
|
|
257
|
+
return;
|
|
258
|
+
default:
|
|
259
|
+
this.logger.warn(`Skipping physical delete for unsupported media storage provider type ${mediaStorageProvider.type}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
const message = error?.message ?? String(error);
|
|
264
|
+
this.logger.warn(`Failed to delete physical media file for media id ${media.id}: ${message}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async resolveMediaStorageProvider(media) {
|
|
268
|
+
if (media.mediaStorageProviderMetadata) {
|
|
269
|
+
return media.mediaStorageProviderMetadata;
|
|
270
|
+
}
|
|
271
|
+
if (!media.id) {
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
const loadedMedia = await this.repo.findOne({
|
|
275
|
+
where: { id: media.id },
|
|
276
|
+
relations: ['mediaStorageProviderMetadata'],
|
|
277
|
+
});
|
|
278
|
+
return loadedMedia?.mediaStorageProviderMetadata;
|
|
178
279
|
}
|
|
179
280
|
};
|
|
180
281
|
exports.MediaService = MediaService;
|
|
181
|
-
exports.MediaService = MediaService = __decorate([
|
|
282
|
+
exports.MediaService = MediaService = MediaService_1 = __decorate([
|
|
182
283
|
(0, common_1.Injectable)(),
|
|
183
|
-
__param(
|
|
184
|
-
__param(
|
|
284
|
+
__param(4, (0, typeorm_1.InjectEntityManager)()),
|
|
285
|
+
__param(6, (0, common_1.Inject)((0, common_1.forwardRef)(() => model_metadata_repository_1.ModelMetadataRepository))),
|
|
185
286
|
__metadata("design:paramtypes", [config_1.ConfigService,
|
|
186
287
|
file_1.DiskFileService,
|
|
187
288
|
file_1.S3FileService,
|
|
289
|
+
media_download_url_service_1.MediaDownloadUrlService,
|
|
188
290
|
typeorm_2.EntityManager,
|
|
189
291
|
media_repository_1.MediaRepository,
|
|
190
292
|
model_metadata_repository_1.ModelMetadataRepository,
|