@solidxai/core 0.1.12-beta.7 → 0.1.12-beta.9
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/dist/entities/media.entity.d.ts +0 -1
- package/dist/entities/media.entity.d.ts.map +1 -1
- package/dist/entities/media.entity.js +1 -9
- package/dist/entities/media.entity.js.map +1 -1
- package/dist/repository/media.repository.d.ts.map +1 -1
- package/dist/repository/media.repository.js +0 -2
- package/dist/repository/media.repository.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +0 -39
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +4 -3
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/media-download-url.service.d.ts +3 -2
- package/dist/services/media-download-url.service.d.ts.map +1 -1
- package/dist/services/media-download-url.service.js +6 -3
- package/dist/services/media-download-url.service.js.map +1 -1
- package/dist/services/media-storage.utils.d.ts +0 -3
- package/dist/services/media-storage.utils.d.ts.map +1 -1
- package/dist/services/media-storage.utils.js +2 -11
- package/dist/services/media-storage.utils.js.map +1 -1
- package/dist/services/media.service.d.ts.map +1 -1
- package/dist/services/media.service.js +3 -5
- package/dist/services/media.service.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.d.ts.map +1 -1
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +2 -5
- package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.d.ts.map +1 -1
- package/dist/services/mediaStorageProviders/file-storage-provider.js +2 -5
- package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
- package/package.json +1 -1
- package/src/entities/media.entity.ts +0 -3
- package/src/repository/media.repository.ts +1 -2
- package/src/seeders/seed-data/solid-core-metadata.json +0 -39
- package/src/services/authentication.service.ts +6 -1
- package/src/services/media-download-url.service.ts +13 -6
- package/src/services/media-storage.utils.ts +6 -15
- package/src/services/media.service.ts +4 -6
- package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +6 -9
- package/src/services/mediaStorageProviders/file-storage-provider.ts +3 -6
|
@@ -1704,18 +1704,6 @@
|
|
|
1704
1704
|
"columnName": "original_file_name",
|
|
1705
1705
|
"isSystem": true
|
|
1706
1706
|
},
|
|
1707
|
-
{
|
|
1708
|
-
"name": "isPublic",
|
|
1709
|
-
"displayName": "Is Public",
|
|
1710
|
-
"type": "boolean",
|
|
1711
|
-
"required": false,
|
|
1712
|
-
"unique": false,
|
|
1713
|
-
"index": false,
|
|
1714
|
-
"private": false,
|
|
1715
|
-
"encrypt": false,
|
|
1716
|
-
"columnName": "is_public",
|
|
1717
|
-
"isSystem": true
|
|
1718
|
-
},
|
|
1719
1707
|
{
|
|
1720
1708
|
"name": "modelMetadata",
|
|
1721
1709
|
"displayName": "Model Metadata",
|
|
@@ -8789,13 +8777,6 @@
|
|
|
8789
8777
|
"sortable": false
|
|
8790
8778
|
}
|
|
8791
8779
|
},
|
|
8792
|
-
{
|
|
8793
|
-
"type": "field",
|
|
8794
|
-
"attrs": {
|
|
8795
|
-
"name": "isPublic",
|
|
8796
|
-
"sortable": true
|
|
8797
|
-
}
|
|
8798
|
-
},
|
|
8799
8780
|
{
|
|
8800
8781
|
"type": "field",
|
|
8801
8782
|
"attrs": {
|
|
@@ -8891,14 +8872,6 @@
|
|
|
8891
8872
|
"isSearchable": true
|
|
8892
8873
|
}
|
|
8893
8874
|
},
|
|
8894
|
-
{
|
|
8895
|
-
"type": "field",
|
|
8896
|
-
"attrs": {
|
|
8897
|
-
"name": "isPublic",
|
|
8898
|
-
"label": "isPublic",
|
|
8899
|
-
"isSearchable": true
|
|
8900
|
-
}
|
|
8901
|
-
},
|
|
8902
8875
|
{
|
|
8903
8876
|
"type": "field",
|
|
8904
8877
|
"attrs": {
|
|
@@ -8967,12 +8940,6 @@
|
|
|
8967
8940
|
"name": "mediaStorageProviderMetadata"
|
|
8968
8941
|
}
|
|
8969
8942
|
},
|
|
8970
|
-
{
|
|
8971
|
-
"type": "field",
|
|
8972
|
-
"attrs": {
|
|
8973
|
-
"name": "isPublic"
|
|
8974
|
-
}
|
|
8975
|
-
},
|
|
8976
8943
|
{
|
|
8977
8944
|
"type": "field",
|
|
8978
8945
|
"attrs": {
|
|
@@ -14581,12 +14548,6 @@
|
|
|
14581
14548
|
"isPublic": true,
|
|
14582
14549
|
"localPath": "media-files-storage"
|
|
14583
14550
|
},
|
|
14584
|
-
{
|
|
14585
|
-
"name": "private-filesystem",
|
|
14586
|
-
"type": "filesystem",
|
|
14587
|
-
"isPublic": false,
|
|
14588
|
-
"localPath": "media-private-files-storage"
|
|
14589
|
-
},
|
|
14590
14551
|
{
|
|
14591
14552
|
"name": "default-aws-s3",
|
|
14592
14553
|
"type": "aws-s3"
|
|
@@ -212,6 +212,7 @@ export class AuthenticationService {
|
|
|
212
212
|
effectiveDto,
|
|
213
213
|
entity,
|
|
214
214
|
provider.repo as Repository<User>,
|
|
215
|
+
true,
|
|
215
216
|
);
|
|
216
217
|
}
|
|
217
218
|
return this.performSignUp(signUpDto, new User(), this.userRepository);
|
|
@@ -221,6 +222,7 @@ export class AuthenticationService {
|
|
|
221
222
|
signUpDto: SignUpDto,
|
|
222
223
|
entity: T,
|
|
223
224
|
repo: Repository<T>,
|
|
225
|
+
preferEntityApiKeyFlag: boolean = false,
|
|
224
226
|
): Promise<T> {
|
|
225
227
|
try {
|
|
226
228
|
const onForcePasswordChange =
|
|
@@ -241,7 +243,10 @@ export class AuthenticationService {
|
|
|
241
243
|
onForcePasswordChange,
|
|
242
244
|
);
|
|
243
245
|
const privateDto = signUpDto as { isAllowedToGenerateApiKeys?: boolean };
|
|
244
|
-
if (
|
|
246
|
+
if (
|
|
247
|
+
!preferEntityApiKeyFlag &&
|
|
248
|
+
privateDto.isAllowedToGenerateApiKeys !== undefined
|
|
249
|
+
) {
|
|
245
250
|
user.isAllowedToGenerateApiKeys = privateDto.isAllowedToGenerateApiKeys;
|
|
246
251
|
}
|
|
247
252
|
const savedUser = await repo.save(user);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Injectable, Logger } from '@nestjs/common';
|
|
2
|
-
import { ConfigService } from '@nestjs/config';
|
|
3
2
|
import { JwtService } from '@nestjs/jwt';
|
|
4
3
|
import { MediaStorageProviderType } from 'src/dtos/create-media-storage-provider-metadata.dto';
|
|
5
4
|
import { MediaStorageProviderMetadata } from 'src/entities/media-storage-provider-metadata.entity';
|
|
6
|
-
import { S3FileService } from 'src/services/file';
|
|
7
|
-
import { getEffectiveS3Region } from 'src/services/media-storage.utils';
|
|
8
5
|
import { SettingService } from 'src/services/setting.service';
|
|
9
6
|
import type { SolidCoreSetting } from 'src/services/settings/default-settings-provider.service';
|
|
7
|
+
import { getEffectiveS3Region } from './media-storage.utils';
|
|
8
|
+
import { ConfigService } from '@nestjs/config';
|
|
9
|
+
import { S3FileService } from './file';
|
|
10
10
|
|
|
11
11
|
export const MEDIA_DOWNLOAD_TOKEN_AUDIENCE = 'media-download';
|
|
12
12
|
const DEFAULT_SIGNED_URL_EXPIRY_MINUTES = 60;
|
|
@@ -26,10 +26,14 @@ export class MediaDownloadUrlService {
|
|
|
26
26
|
private readonly configService: ConfigService,
|
|
27
27
|
) { }
|
|
28
28
|
|
|
29
|
-
async resolveDownloadUrl(
|
|
29
|
+
async resolveDownloadUrl(
|
|
30
|
+
mediaId: number,
|
|
31
|
+
relativeUri: string,
|
|
32
|
+
storageProvider?: MediaStorageProviderMetadata,
|
|
33
|
+
): Promise<string> {
|
|
30
34
|
const expiryMinutes = storageProvider?.signedUrlExpiry ?? DEFAULT_SIGNED_URL_EXPIRY_MINUTES;
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
if ((storageProvider?.type as MediaStorageProviderType) === MediaStorageProviderType.AwsS3) {
|
|
33
37
|
if (storageProvider?.bucketName) {
|
|
34
38
|
return this.s3FileService.getUrl(
|
|
35
39
|
`${storageProvider.bucketName}:${relativeUri}`,
|
|
@@ -38,7 +42,6 @@ export class MediaDownloadUrlService {
|
|
|
38
42
|
}
|
|
39
43
|
this.logger.warn(`Media id ${mediaId}: AwsS3 provider missing bucketName; falling back to app-hosted token URL`);
|
|
40
44
|
}
|
|
41
|
-
|
|
42
45
|
// Filesystem (or misconfigured S3) has no native presigned-URL mechanism, so mint our
|
|
43
46
|
// own short-lived token and embed it in the download URL - the token alone authorizes
|
|
44
47
|
// the request (see MediaSignedUrlGuard), so it works in a plain <img src> with no
|
|
@@ -49,6 +52,10 @@ export class MediaDownloadUrlService {
|
|
|
49
52
|
return `${String(baseUrl).replace(/\/+$/, '')}${downloadPath}`;
|
|
50
53
|
}
|
|
51
54
|
|
|
55
|
+
async getPrivateUrl(mediaId: number, relativeUri: string, storageProvider?: MediaStorageProviderMetadata): Promise<string> {
|
|
56
|
+
return this.resolveDownloadUrl(mediaId, relativeUri, storageProvider);
|
|
57
|
+
}
|
|
58
|
+
|
|
52
59
|
async verifyDownloadToken(token: string): Promise<MediaDownloadTokenPayload> {
|
|
53
60
|
return this.jwtService.verifyAsync<MediaDownloadTokenPayload>(token, {
|
|
54
61
|
secret: this.settingService.getConfigValue<SolidCoreSetting>('secret'),
|
|
@@ -6,7 +6,6 @@ import { SettingService } from 'src/services/setting.service';
|
|
|
6
6
|
import { DEFAULT_MEDIA_FILE_STORAGE_DIR } from 'src/services/settings/default-settings-provider.service';
|
|
7
7
|
import type { SolidCoreSetting } from 'src/services/settings/default-settings-provider.service';
|
|
8
8
|
|
|
9
|
-
export const DEFAULT_PRIVATE_MEDIA_STORAGE_DIR = 'media-private-files-storage';
|
|
10
9
|
|
|
11
10
|
export interface MediaRecordCreateInput {
|
|
12
11
|
entityId: number;
|
|
@@ -17,7 +16,6 @@ export interface MediaRecordCreateInput {
|
|
|
17
16
|
mimeType?: string;
|
|
18
17
|
fileSize?: number;
|
|
19
18
|
originalFileName?: string;
|
|
20
|
-
isPublic?: boolean;
|
|
21
19
|
}
|
|
22
20
|
|
|
23
21
|
// Builds the stored file name format shared by media storage implementations.
|
|
@@ -28,8 +26,10 @@ export function buildStoredMediaFileName(file: Pick<Express.Multer.File, 'filena
|
|
|
28
26
|
// Resolves the on-disk path for a media file based on settings and provider visibility.
|
|
29
27
|
export function buildDiskMediaPath(fileName: string,settingService: Pick<SettingService, 'getConfigValue'>,storageProvider?: Pick<MediaStorageProviderMetadata, 'localPath' | 'isPublic'>,): string {
|
|
30
28
|
const publicBase = settingService.getConfigValue<SolidCoreSetting>('fileStorageDir') || DEFAULT_MEDIA_FILE_STORAGE_DIR;
|
|
31
|
-
const privateBase =
|
|
32
|
-
const
|
|
29
|
+
const privateBase = `${publicBase}-private`;
|
|
30
|
+
// const localPath = storageProvider?.localPath;
|
|
31
|
+
// const isUsingLegacyDefaultPath = localPath === publicBase || localPath === privateBase || localPath === privateBase;
|
|
32
|
+
const providerBase = storageProvider?.isPublic === false ? privateBase : publicBase
|
|
33
33
|
|
|
34
34
|
if ( path.isAbsolute(fileName) || fileName.startsWith(`${publicBase}/`) || fileName.startsWith(`${privateBase}/`) || (!!storageProvider?.localPath && fileName.startsWith(`${storageProvider.localPath}/`))) {
|
|
35
35
|
return fileName;
|
|
@@ -39,12 +39,12 @@ export function buildDiskMediaPath(fileName: string,settingService: Pick<Setting
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// Returns the S3 region from the provider when present, otherwise falls back to app config.
|
|
42
|
-
export function getEffectiveS3Region(configService: Pick<ConfigService, 'get'>,providerRegion?: string
|
|
42
|
+
export function getEffectiveS3Region(configService: Pick<ConfigService, 'get'>, providerRegion?: string): string | undefined {
|
|
43
43
|
return providerRegion || configService.get<string>('S3_AWS_REGION_NAME');
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// Resolves the effective public/private flag for a media storage provider.
|
|
47
|
-
export function resolveMediaIsPublic(storageProvider?: Pick<MediaStorageProviderMetadata, 'isPublic'
|
|
47
|
+
export function resolveMediaIsPublic(storageProvider?: Pick<MediaStorageProviderMetadata, 'isPublic'>): boolean | undefined {
|
|
48
48
|
if (!storageProvider) {
|
|
49
49
|
return undefined;
|
|
50
50
|
}
|
|
@@ -52,15 +52,6 @@ export function resolveMediaIsPublic(storageProvider?: Pick<MediaStorageProvider
|
|
|
52
52
|
return storageProvider.isPublic !== false;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
// Preserves an explicit media visibility value or derives it from the storage provider.
|
|
56
|
-
export function resolveStoredMediaIsPublic(currentValue: boolean | undefined,storageProvider?:Pick<MediaStorageProviderMetadata, 'isPublic'>,): boolean | undefined {
|
|
57
|
-
if (typeof currentValue === 'boolean') {
|
|
58
|
-
return currentValue;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return resolveMediaIsPublic(storageProvider);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
55
|
// Builds the shared media record payload used before saving media metadata to the database.
|
|
65
56
|
export function buildMediaRecordCreateInput(
|
|
66
57
|
entityId: number,
|
|
@@ -20,7 +20,7 @@ import { FieldMetadataRepository } from 'src/repository/field-metadata.repositor
|
|
|
20
20
|
import { MediaStorageProviderMetadataRepository } from 'src/repository/media-storage-provider-metadata.repository';
|
|
21
21
|
import { MediaRepository } from 'src/repository/media.repository';
|
|
22
22
|
import { ModelMetadataRepository } from 'src/repository/model-metadata.repository';
|
|
23
|
-
import { buildDiskMediaPath, buildStoredMediaFileName, getEffectiveS3Region,
|
|
23
|
+
import { buildDiskMediaPath, buildStoredMediaFileName, getEffectiveS3Region, resolveMediaIsPublic, } from 'src/services/media-storage.utils';
|
|
24
24
|
import { getMediaStorageProvider } from "./mediaStorageProviders";
|
|
25
25
|
|
|
26
26
|
@Injectable()
|
|
@@ -131,10 +131,9 @@ export class MediaService extends CRUDService<Media> {
|
|
|
131
131
|
// Delete temp file from disk
|
|
132
132
|
await this.diskFileService.delete(file.path);
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
delete createDto['isPublic'];
|
|
135
135
|
const media = this.repo.create(createDto as Partial<Media>) as Media;
|
|
136
136
|
const savedMedia = await this.repo.save(media);
|
|
137
|
-
savedMedia.isPublic = resolveStoredMediaIsPublic(savedMedia.isPublic, storageProvider);
|
|
138
137
|
savedMedias.push(savedMedia)
|
|
139
138
|
}
|
|
140
139
|
return savedMedias
|
|
@@ -228,16 +227,15 @@ export class MediaService extends CRUDService<Media> {
|
|
|
228
227
|
|
|
229
228
|
private async decorateMediaRecord(media: Media): Promise<void> {
|
|
230
229
|
const mediaStorageProvider = await this.resolveMediaStorageProvider(media);
|
|
231
|
-
media.isPublic = resolveStoredMediaIsPublic(media.isPublic, mediaStorageProvider);
|
|
232
230
|
media.relativeUri = await this.resolveMediaUrl(media, mediaStorageProvider);
|
|
233
231
|
}
|
|
234
232
|
|
|
235
233
|
private async resolveMediaUrl(media: Media, mediaStorageProvider?: MediaStorageProviderMetadata): Promise<string> {
|
|
236
234
|
const resolvedMediaStorageProvider = mediaStorageProvider || await this.resolveMediaStorageProvider(media);
|
|
237
|
-
const isPublic =
|
|
235
|
+
const isPublic = resolveMediaIsPublic(resolvedMediaStorageProvider);
|
|
238
236
|
|
|
239
237
|
if (isPublic === false) {
|
|
240
|
-
return this.mediaDownloadUrlService.
|
|
238
|
+
return this.mediaDownloadUrlService.getPrivateUrl(media.id, media.relativeUri, resolvedMediaStorageProvider);
|
|
241
239
|
}
|
|
242
240
|
|
|
243
241
|
if (resolvedMediaStorageProvider?.type === MediaStorageProviderType.Filesystem) {
|
|
@@ -11,10 +11,10 @@ import { Readable } from "stream";
|
|
|
11
11
|
import { MediaRepository } from "src/repository/media.repository";
|
|
12
12
|
import { MediaDownloadUrlService } from "src/services/media-download-url.service";
|
|
13
13
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
buildMediaRecordCreateInput,
|
|
15
|
+
buildStoredMediaFileName,
|
|
16
|
+
getEffectiveS3Region,
|
|
17
|
+
resolveMediaIsPublic,
|
|
18
18
|
} from "src/services/media-storage.utils";
|
|
19
19
|
|
|
20
20
|
@Injectable()
|
|
@@ -54,7 +54,6 @@ export class FileS3StorageProvider<T> implements MediaStorageProvider<T> {
|
|
|
54
54
|
fileSize,
|
|
55
55
|
})
|
|
56
56
|
) as unknown as Media;
|
|
57
|
-
mediaEntity.isPublic = resolveStoredMediaIsPublic(mediaEntity.isPublic, storageProvider);
|
|
58
57
|
result.push(mediaEntity);
|
|
59
58
|
this.logger.debug(`Stored media with`, mediaEntity);
|
|
60
59
|
}
|
|
@@ -71,10 +70,9 @@ export class FileS3StorageProvider<T> implements MediaStorageProvider<T> {
|
|
|
71
70
|
// Add the full URL to the media
|
|
72
71
|
for (const m of media) {
|
|
73
72
|
const storageMeta = m.mediaStorageProviderMetadata;
|
|
74
|
-
const isPublic =
|
|
75
|
-
m.isPublic = isPublic;
|
|
73
|
+
const isPublic = resolveMediaIsPublic(storageMeta);
|
|
76
74
|
m['_full_url'] = isPublic === false
|
|
77
|
-
? await this.mediaDownloadUrlService.
|
|
75
|
+
? await this.mediaDownloadUrlService.getPrivateUrl(m.id, m.relativeUri, storageMeta)
|
|
78
76
|
: await this.s3FileService.getUrl(
|
|
79
77
|
`${storageMeta.bucketName}:${m.relativeUri}`,
|
|
80
78
|
{ region: getEffectiveS3Region(this.configService, storageMeta.region), expiresIn: 0 },
|
|
@@ -116,7 +114,6 @@ export class FileS3StorageProvider<T> implements MediaStorageProvider<T> {
|
|
|
116
114
|
originalFileName: file.originalname,
|
|
117
115
|
})
|
|
118
116
|
) as unknown as Media;
|
|
119
|
-
mediaEntity.isPublic = resolveStoredMediaIsPublic(mediaEntity.isPublic, storageProvider);
|
|
120
117
|
result.push(mediaEntity);
|
|
121
118
|
this.logger.debug(`Stored media with`, mediaEntity);
|
|
122
119
|
};
|
|
@@ -9,7 +9,7 @@ import { Readable } from "stream";
|
|
|
9
9
|
import * as fs from "fs";
|
|
10
10
|
import { SettingService } from "../setting.service";
|
|
11
11
|
import { MediaDownloadUrlService } from "src/services/media-download-url.service";
|
|
12
|
-
import {
|
|
12
|
+
import {buildDiskMediaPath,buildMediaRecordCreateInput,buildStoredMediaFileName,resolveMediaIsPublic,} from "src/services/media-storage.utils";
|
|
13
13
|
|
|
14
14
|
@Injectable()
|
|
15
15
|
export class FileStorageProvider<T> implements MediaStorageProvider<T> {
|
|
@@ -34,10 +34,9 @@ export class FileStorageProvider<T> implements MediaStorageProvider<T> {
|
|
|
34
34
|
// });
|
|
35
35
|
for (const m of media) {
|
|
36
36
|
const storageProvider = this.resolveMediaStorageProvider(m, mediaFieldMetadata);
|
|
37
|
-
const isPublic =
|
|
38
|
-
m.isPublic = isPublic;
|
|
37
|
+
const isPublic = resolveMediaIsPublic(storageProvider);
|
|
39
38
|
m['_full_url'] = isPublic === false
|
|
40
|
-
? await this.mediaDownloadUrlService.
|
|
39
|
+
? await this.mediaDownloadUrlService.getPrivateUrl(m.id, m.relativeUri, storageProvider)
|
|
41
40
|
: await this.fileService.getUrl(buildDiskMediaPath(m.relativeUri, this.settingService, storageProvider));
|
|
42
41
|
}
|
|
43
42
|
|
|
@@ -67,7 +66,6 @@ export class FileStorageProvider<T> implements MediaStorageProvider<T> {
|
|
|
67
66
|
originalFileName: file.originalname,
|
|
68
67
|
})
|
|
69
68
|
) as unknown as Media;
|
|
70
|
-
mediaEntity.isPublic = resolveStoredMediaIsPublic(mediaEntity.isPublic, storageProvider);
|
|
71
69
|
result.push(mediaEntity);
|
|
72
70
|
this.logger.debug(`Stored media with`, mediaEntity);
|
|
73
71
|
};
|
|
@@ -92,7 +90,6 @@ export class FileStorageProvider<T> implements MediaStorageProvider<T> {
|
|
|
92
90
|
fileSize,
|
|
93
91
|
})
|
|
94
92
|
) as unknown as Media;
|
|
95
|
-
mediaEntity.isPublic = resolveStoredMediaIsPublic(mediaEntity.isPublic, storageProvider);
|
|
96
93
|
result.push(mediaEntity);
|
|
97
94
|
this.logger.debug(`Stored media with`, mediaEntity);
|
|
98
95
|
};
|