@solidxai/core 0.1.12-beta.2 → 0.1.12-beta.3
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/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/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/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/seed-data/solid-core-metadata.json +88 -3
- 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/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/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/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/repository/media.repository.ts +2 -0
- package/src/seeders/seed-data/solid-core-metadata.json +88 -3
- package/src/services/1.js +6 -0
- 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/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 @@
|
|
|
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,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.service.js","sourceRoot":"","sources":["../../src/services/media.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { forwardRef, Inject, Injectable, NotFoundException } from '@nestjs/common';\nimport { ModuleRef } from \"@nestjs/core\";\nimport { InjectEntityManager } from '@nestjs/typeorm';\nimport { EntityManager, In } from 'typeorm';\nimport * as path from 'path';\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\nimport { ConfigService } from '@nestjs/config';\nimport { CRUDService } from 'src/services/crud.service';\nimport { DiskFileService, S3FileService } from 'src/services/file';\n\n\nimport { ERROR_MESSAGES } from 'src/constants/error-messages';\nimport { BasicFilterDto } from 'src/dtos/basic-filters.dto';\nimport { MediaStorageProviderType } from 'src/dtos/create-media-storage-provider-metadata.dto';\nimport { Media } from 'src/entities/media.entity';\nimport { FieldMetadataRepository } from 'src/repository/field-metadata.repository';\nimport { MediaStorageProviderMetadataRepository } from 'src/repository/media-storage-provider-metadata.repository';\nimport { MediaRepository } from 'src/repository/media.repository';\nimport { ModelMetadataRepository } from 'src/repository/model-metadata.repository';\nimport { getMediaStorageProvider } from \"./mediaStorageProviders\";\n\n\n@Injectable()\nexport class MediaService extends CRUDService<Media> {\n constructor(\n readonly configService: ConfigService,\n readonly diskFileService: DiskFileService,\n readonly s3FileService: S3FileService,\n @InjectEntityManager()\n readonly entityManager: EntityManager,\n // @InjectRepository(Media, 'default')\n // readonly repo: Repository<Media>,\n readonly repo: MediaRepository,\n // @InjectRepository(ModelMetadata)\n // private readonly modelMetadataRepo: Repository<ModelMetadata>,\n // @InjectRepository(MediaStorageProviderMetadata)\n // private readonly mediaStorageProviderMetadataRepo: Repository<MediaStorageProviderMetadata>,\n // @InjectRepository(FieldMetadata)\n // private readonly fieldMetadataRepo: Repository<FieldMetadata>,\n @Inject(forwardRef(() => ModelMetadataRepository))\n private readonly modelMetadataRepo: ModelMetadataRepository,\n private readonly mediaStorageProviderMetadataRepo: MediaStorageProviderMetadataRepository,\n private readonly fieldMetadataRepo: FieldMetadataRepository,\n readonly moduleRef: ModuleRef,\n ) {\n super(entityManager, repo, 'media', 'solid-core', moduleRef);\n }\n\n async find(basicFilterDto: BasicFilterDto, solidRequestContext: any = {}) {\n const data = await super.find(basicFilterDto, solidRequestContext);\n if (data.records) {\n\n for (const media of data.records) {\n const mediaStorageProvider = media.mediaStorageProviderMetadata;\n\n if (mediaStorageProvider?.type === MediaStorageProviderType.Filesystem) {\n media.relativeUri = await this.diskFileService.getUrl(this.getFullFilePathForDisk(media.relativeUri));\n } else if (mediaStorageProvider?.type === MediaStorageProviderType.AwsS3) {\n media.relativeUri = await this.s3FileService.getUrl(`${mediaStorageProvider.bucketName}:${media.relativeUri}`, { region: mediaStorageProvider.region });\n }\n }\n }\n if (data.groupRecords) {\n\n for (const group of data.groupRecords) {\n for (const media of group.groupData.records) {\n const mediaStorageProvider = media.mediaStorageProviderMetadata;\n\n if (mediaStorageProvider?.type === MediaStorageProviderType.Filesystem) {\n media.relativeUri = await this.diskFileService.getUrl(this.getFullFilePathForDisk(media.relativeUri));\n }\n else if (mediaStorageProvider?.type === MediaStorageProviderType.AwsS3) {\n media.relativeUri = await this.s3FileService.getUrl(`${mediaStorageProvider.bucketName}:${media.relativeUri}`, { region: mediaStorageProvider.region });\n }\n }\n }\n }\n return data\n }\n\n async upload(createDto: any, files: Array<Express.Multer.File>) {\n\n if (!files) {\n throw new NotFoundException(ERROR_MESSAGES.FILE_NOT_FOUND);\n\n }\n const savedMedias = [];\n for (let i = 0; i < files.length; i++) {\n\n createDto['fieldMetadata'] = await this.fieldMetadataRepo.findOne({\n where: {\n id: createDto['fieldMetadataId']\n },\n });\n createDto['modelMetadata'] = await this.modelMetadataRepo.findOne({\n where: {\n id: createDto['modelMetadataId']\n },\n });\n createDto['mediaStorageProviderMetadata'] = await this.mediaStorageProviderMetadataRepo.findOne({\n where: {\n id: createDto['mediaStorageProviderMetadataId']\n },\n });\n\n const file = files[i];\n\n switch (createDto.mediaStorageProviderMetadata.type) {\n case MediaStorageProviderType.Filesystem:\n const fileStoragePath = this.getFullFilePathForDisk(this.getFileName(file));\n await this.diskFileService.copy(file.path, fileStoragePath);\n createDto['relativeUri'] = this.getFileName(file);\n break;\n case MediaStorageProviderType.AwsS3:\n const fileName = this.getFileName(file);\n const bucketName = createDto.mediaStorageProviderMetadata.bucketName;\n\n // Read file from disk and upload to S3\n const fileData = await this.diskFileService.read(file.path);\n await this.s3FileService.write(`${bucketName}:${fileName}`, fileData, { contentType: file.mimetype });\n\n createDto['relativeUri'] = fileName;\n break;\n default:\n break;\n }\n // Delete temp file from disk\n await this.diskFileService.delete(file.path);\n\n const media = this.repo.create(createDto);\n const savedMedia = await this.repo.save(media);\n savedMedias.push(savedMedia)\n }\n return savedMedias\n }\n\n async remove(id: number) {\n // const lov = await this.findOne(id);\n const media = await this.repo.findOne({\n where: {\n id: id,\n },\n relations: ['mediaStorageProviderMetadata', 'fieldMetadata', 'fieldMetadata.model', 'fieldMetadata.mediaStorageProvider'],\n });\n const modelEntity = await this.modelMetadataRepo.findOne({\n where: {\n id: media.entityId,\n }\n }\n );\n const storageProviderType = media.mediaStorageProviderMetadata.type as MediaStorageProviderType;\n const storageProvider = await getMediaStorageProvider(this.moduleRef, storageProviderType);\n await storageProvider.delete(modelEntity, media.fieldMetadata);\n\n return this.repo.remove(media);\n }\n\n private getFullFilePathForDisk(fileName: string): string {\n const base = this.settingService.getConfigValue<SolidCoreSetting>(\"fileStorageDir\")\n || DEFAULT_MEDIA_FILE_STORAGE_DIR;\n if (path.isAbsolute(fileName) || fileName.startsWith(`${base}/`)) {\n return fileName;\n }\n return `${base}/${fileName}`;\n }\n\n private getFileName(file: Express.Multer.File): string {\n return `${file.filename}-${file.originalname}`;\n }\n\n}\n"]}
|
|
1
|
+
{"version":3,"file":"media.service.js","sourceRoot":"","sources":["../../src/services/media.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { forwardRef, Inject, Injectable, Logger, NotFoundException } from '@nestjs/common';\nimport { ModuleRef } from \"@nestjs/core\";\nimport { InjectEntityManager } from '@nestjs/typeorm';\nimport { EntityManager, In } from 'typeorm';\nimport * as path from 'path';\nimport { Readable } from 'stream';\n\nimport { ConfigService } from '@nestjs/config';\nimport { CRUDService } from 'src/services/crud.service';\nimport { DiskFileService, S3FileService } from 'src/services/file';\nimport { MediaDownloadUrlService } from 'src/services/media-download-url.service';\n\n\nimport { ERROR_MESSAGES } from 'src/constants/error-messages';\nimport { BasicFilterDto } from 'src/dtos/basic-filters.dto';\nimport { MediaStorageProviderType } from 'src/dtos/create-media-storage-provider-metadata.dto';\nimport { Media } from 'src/entities/media.entity';\nimport { MediaStorageProviderMetadata } from 'src/entities/media-storage-provider-metadata.entity';\nimport { FieldMetadataRepository } from 'src/repository/field-metadata.repository';\nimport { MediaStorageProviderMetadataRepository } from 'src/repository/media-storage-provider-metadata.repository';\nimport { MediaRepository } from 'src/repository/media.repository';\nimport { ModelMetadataRepository } from 'src/repository/model-metadata.repository';\nimport { buildDiskMediaPath, buildStoredMediaFileName, getEffectiveS3Region, resolveStoredMediaIsPublic, } from 'src/services/media-storage.utils';\nimport { getMediaStorageProvider } from \"./mediaStorageProviders\";\n\n@Injectable()\nexport class MediaService extends CRUDService<Media> {\n private readonly logger = new Logger(MediaService.name);\n\n constructor(\n readonly configService: ConfigService,\n readonly diskFileService: DiskFileService,\n readonly s3FileService: S3FileService,\n private readonly mediaDownloadUrlService: MediaDownloadUrlService,\n @InjectEntityManager()\n readonly entityManager: EntityManager,\n // @InjectRepository(Media, 'default')\n // readonly repo: Repository<Media>,\n readonly repo: MediaRepository,\n // @InjectRepository(ModelMetadata)\n // private readonly modelMetadataRepo: Repository<ModelMetadata>,\n // @InjectRepository(MediaStorageProviderMetadata)\n // private readonly mediaStorageProviderMetadataRepo: Repository<MediaStorageProviderMetadata>,\n // @InjectRepository(FieldMetadata)\n // private readonly fieldMetadataRepo: Repository<FieldMetadata>,\n @Inject(forwardRef(() => ModelMetadataRepository))\n private readonly modelMetadataRepo: ModelMetadataRepository,\n private readonly mediaStorageProviderMetadataRepo: MediaStorageProviderMetadataRepository,\n private readonly fieldMetadataRepo: FieldMetadataRepository,\n readonly moduleRef: ModuleRef,\n ) {\n super(entityManager, repo, 'media', 'solid-core', moduleRef);\n }\n\n async find(basicFilterDto: BasicFilterDto, solidRequestContext: any = {}) {\n const data = await super.find(basicFilterDto, solidRequestContext);\n if (data.records) {\n await this.decorateMediaRecords(data.records);\n }\n if (data.groupRecords) {\n for (const group of data.groupRecords) {\n await this.decorateMediaRecords(group.groupData.records);\n }\n }\n return data\n }\n\n async findOne(id: number, query: any = {}, solidRequestContext: any = {}) {\n const media = await super.findOne(id, query, solidRequestContext);\n if (media) {\n await this.decorateMediaRecord(media);\n }\n return media;\n }\n\n async upload(createDto: any, files: Array<Express.Multer.File>, _solidRequestContext: any = {}) {\n\n if (!files || files.length === 0) {\n throw new NotFoundException(ERROR_MESSAGES.FILE_NOT_FOUND);\n\n }\n\n createDto['fieldMetadata'] = await this.fieldMetadataRepo.findOne({\n where: {\n id: createDto['fieldMetadataId']\n },\n relations: ['mediaStorageProvider', 'model'],\n });\n createDto['modelMetadata'] = await this.modelMetadataRepo.findOne({\n where: {\n id: createDto['modelMetadataId']\n },\n });\n createDto['mediaStorageProviderMetadata'] = await this.mediaStorageProviderMetadataRepo.findOne({\n where: {\n id: createDto['mediaStorageProviderMetadataId']\n },\n });\n createDto['mediaStorageProviderMetadata'] = createDto['mediaStorageProviderMetadata'] || createDto['fieldMetadata']?.mediaStorageProvider;\n createDto['modelMetadata'] = createDto['modelMetadata'] || createDto['fieldMetadata']?.model;\n\n if (!createDto['mediaStorageProviderMetadata']) {\n throw new NotFoundException('Media storage provider metadata not found');\n }\n\n const savedMedias = [];\n for (let i = 0; i < files.length; i++) {\n const file = files[i];\n const storageProvider = createDto.mediaStorageProviderMetadata as MediaStorageProviderMetadata;\n const fileName = buildStoredMediaFileName(file);\n\n switch (storageProvider.type) {\n case MediaStorageProviderType.Filesystem:\n const fileStoragePath = buildDiskMediaPath(fileName, this.settingService, storageProvider);\n await this.diskFileService.copy(file.path, fileStoragePath);\n createDto['relativeUri'] = fileName;\n break;\n case MediaStorageProviderType.AwsS3:\n const bucketName = storageProvider.bucketName;\n const region = getEffectiveS3Region(this.configService, storageProvider.region);\n\n // Read file from disk and upload to S3\n const fileData = await this.diskFileService.read(file.path);\n await this.s3FileService.write(`${bucketName}:${fileName}`, fileData, { contentType: file.mimetype, region });\n\n createDto['relativeUri'] = fileName;\n break;\n default:\n break;\n }\n // Delete temp file from disk\n await this.diskFileService.delete(file.path);\n\n createDto['isPublic'] = resolveStoredMediaIsPublic(createDto['isPublic'], storageProvider);\n const media = this.repo.create(createDto as Partial<Media>) as Media;\n const savedMedia = await this.repo.save(media);\n savedMedia.isPublic = resolveStoredMediaIsPublic(savedMedia.isPublic, storageProvider);\n savedMedias.push(savedMedia)\n }\n return savedMedias\n }\n\n async remove(id: number) {\n // const lov = await this.findOne(id);\n const media = await this.repo.findOne({\n where: {\n id: id,\n },\n relations: ['mediaStorageProviderMetadata', 'fieldMetadata', 'fieldMetadata.model', 'fieldMetadata.mediaStorageProvider'],\n });\n const modelEntity = await this.modelMetadataRepo.findOne({\n where: {\n id: media.entityId,\n }\n }\n );\n const storageProviderType = media.mediaStorageProviderMetadata.type as MediaStorageProviderType;\n const storageProvider = await getMediaStorageProvider(this.moduleRef, storageProviderType);\n await storageProvider.delete(modelEntity, media.fieldMetadata);\n\n return this.repo.remove(media);\n }\n\n async fileDownloadStream(media: Media): Promise<{ stream: Readable | null, fileName: string, mimeType: string, redirectUrl?: string }> {\n const loadedMedia = await this.repo.findOne({\n where: { id: media.id },\n relations: ['mediaStorageProviderMetadata'],\n });\n\n if (!loadedMedia || !loadedMedia.mediaStorageProviderMetadata) {\n throw new NotFoundException(`Media with id ${media.id} not found`);\n }\n\n const fileName = loadedMedia.originalFileName || path.basename(loadedMedia.relativeUri || `${loadedMedia.id}`);\n const mimeType = loadedMedia.mimeType || 'application/octet-stream';\n\n switch (loadedMedia.mediaStorageProviderMetadata.type as MediaStorageProviderType) {\n case MediaStorageProviderType.Filesystem:\n return {\n stream: await this.diskFileService.readStream(\n buildDiskMediaPath(loadedMedia.relativeUri, this.settingService, loadedMedia.mediaStorageProviderMetadata),\n ),\n fileName,\n mimeType,\n };\n default:\n throw new Error(`Unsupported media storage provider type ${loadedMedia.mediaStorageProviderMetadata.type}`);\n }\n }\n\n async delete(id: number, solidRequestContext: any = {}) {\n const media = await this.repo.findOne({\n where: { id },\n relations: ['mediaStorageProviderMetadata'],\n });\n\n const result = await super.delete(id, solidRequestContext);\n\n if (media) {\n await this.deletePhysicalFile(media);\n }\n\n return result;\n }\n\n async deleteMany(ids: number[], solidRequestContext: any = {}) {\n const mediaRecords = await this.repo.find({\n where: {\n id: In(ids),\n },\n relations: ['mediaStorageProviderMetadata'],\n });\n\n const result = await super.deleteMany(ids, solidRequestContext);\n\n for (const media of mediaRecords) {\n await this.deletePhysicalFile(media);\n }\n\n return result;\n }\n\n private async decorateMediaRecords(medias: Media[]): Promise<void> {\n for (const media of medias) {\n await this.decorateMediaRecord(media);\n }\n }\n\n private async decorateMediaRecord(media: Media): Promise<void> {\n const mediaStorageProvider = await this.resolveMediaStorageProvider(media);\n media.isPublic = resolveStoredMediaIsPublic(media.isPublic, mediaStorageProvider);\n media.relativeUri = await this.resolveMediaUrl(media, mediaStorageProvider);\n }\n\n private async resolveMediaUrl(media: Media, mediaStorageProvider?: MediaStorageProviderMetadata): Promise<string> {\n const resolvedMediaStorageProvider = mediaStorageProvider || await this.resolveMediaStorageProvider(media);\n const isPublic = resolveStoredMediaIsPublic(media.isPublic, resolvedMediaStorageProvider);\n\n if (isPublic === false) {\n return this.mediaDownloadUrlService.resolveDownloadUrl(media.id, media.relativeUri, resolvedMediaStorageProvider);\n }\n\n if (resolvedMediaStorageProvider?.type === MediaStorageProviderType.Filesystem) {\n return this.diskFileService.getUrl(buildDiskMediaPath(media.relativeUri, this.settingService, resolvedMediaStorageProvider));\n }\n\n if (resolvedMediaStorageProvider?.type === MediaStorageProviderType.AwsS3) {\n return this.s3FileService.getUrl(\n `${resolvedMediaStorageProvider.bucketName}:${media.relativeUri}`,\n { region: getEffectiveS3Region(this.configService, resolvedMediaStorageProvider.region), expiresIn: 0 },\n );\n }\n\n return media.relativeUri;\n }\n\n private async deletePhysicalFile(media: Media): Promise<void> {\n if (!media?.relativeUri) {\n return;\n }\n\n try {\n const mediaStorageProvider = await this.resolveMediaStorageProvider(media);\n if (!mediaStorageProvider) {\n return;\n }\n\n switch (mediaStorageProvider.type as MediaStorageProviderType) {\n case MediaStorageProviderType.Filesystem:\n await this.diskFileService.delete(buildDiskMediaPath(media.relativeUri, this.settingService, mediaStorageProvider));\n return;\n case MediaStorageProviderType.AwsS3:\n await this.s3FileService.delete(\n `${mediaStorageProvider.bucketName}:${media.relativeUri}`,\n { region: getEffectiveS3Region(this.configService, mediaStorageProvider.region) },\n );\n return;\n default:\n this.logger.warn(`Skipping physical delete for unsupported media storage provider type ${mediaStorageProvider.type}`);\n }\n } catch (error: any) {\n const message = error?.message ?? String(error);\n this.logger.warn(`Failed to delete physical media file for media id ${media.id}: ${message}`);\n }\n }\n\n private async resolveMediaStorageProvider(media: Media): Promise<MediaStorageProviderMetadata | undefined> {\n if (media.mediaStorageProviderMetadata) {\n return media.mediaStorageProviderMetadata;\n }\n\n if (!media.id) {\n return undefined;\n }\n\n const loadedMedia = await this.repo.findOne({\n where: { id: media.id },\n relations: ['mediaStorageProviderMetadata'],\n });\n\n return loadedMedia?.mediaStorageProviderMetadata;\n }\n}\n"]}
|
|
@@ -5,20 +5,20 @@ import { MediaStorageProvider } from "../../interfaces";
|
|
|
5
5
|
import { DiskFileService, S3FileService } from "../../services/file";
|
|
6
6
|
import { Readable } from "stream";
|
|
7
7
|
import { MediaRepository } from "../../repository/media.repository";
|
|
8
|
+
import { MediaDownloadUrlService } from "../../services/media-download-url.service";
|
|
8
9
|
export declare class FileS3StorageProvider<T> implements MediaStorageProvider<T> {
|
|
9
10
|
private readonly configService;
|
|
10
11
|
readonly diskFileService: DiskFileService;
|
|
11
12
|
readonly s3FileService: S3FileService;
|
|
12
13
|
readonly mediaRepository: MediaRepository;
|
|
14
|
+
private readonly mediaDownloadUrlService;
|
|
13
15
|
private logger;
|
|
14
|
-
constructor(configService: ConfigService, diskFileService: DiskFileService, s3FileService: S3FileService, mediaRepository: MediaRepository);
|
|
16
|
+
constructor(configService: ConfigService, diskFileService: DiskFileService, s3FileService: S3FileService, mediaRepository: MediaRepository, mediaDownloadUrlService: MediaDownloadUrlService);
|
|
15
17
|
storeStreams(streamPairs: [Readable, string][], entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]>;
|
|
16
18
|
retrieve(entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]>;
|
|
17
19
|
store(files: Express.Multer.File[], entity: T, mediaFieldMetadata: FieldMetadata): Promise<Media[]>;
|
|
18
20
|
delete(entity: T, mediaFieldMetadata: FieldMetadata): Promise<void>;
|
|
19
21
|
deleteByMediaRecord(media: Media): Promise<void>;
|
|
20
|
-
private
|
|
21
|
-
private getFullFilePath;
|
|
22
|
-
private getFileName;
|
|
22
|
+
private getSupportedEntityId;
|
|
23
23
|
}
|
|
24
24
|
//# sourceMappingURL=file-s3-storage-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-s3-storage-provider.d.ts","sourceRoot":"","sources":["../../../src/services/mediaStorageProviders/file-s3-storage-provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAGnE,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"file-s3-storage-provider.d.ts","sourceRoot":"","sources":["../../../src/services/mediaStorageProviders/file-s3-storage-provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAGnE,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAQlF,qBACa,qBAAqB,CAAC,CAAC,CAAE,YAAW,oBAAoB,CAAC,CAAC,CAAC;IAIhE,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,QAAQ,CAAC,eAAe,EAAE,eAAe;IACzC,QAAQ,CAAC,aAAa,EAAE,aAAa;IACrC,QAAQ,CAAC,eAAe,EAAE,eAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IAP5C,OAAO,CAAC,MAAM,CAA0C;gBAGnC,aAAa,EAAE,aAAa,EACpC,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EACxB,uBAAuB,EAAE,uBAAuB;IAG/D,YAAY,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,kBAAkB,EAAE,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAgC/G,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,kBAAkB,EAAE,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IA2BxE,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,kBAAkB,EAAE,aAAa,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAmCnG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,kBAAkB,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAenE,mBAAmB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtD,OAAO,CAAC,oBAAoB;CAW/B"}
|