@tomei/media 0.1.0 → 0.2.0
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/.husky/pre-commit +0 -0
- package/dist/base/base.medias.d.ts +1 -0
- package/dist/base/base.medias.js +26 -17
- package/dist/base/base.medias.js.map +1 -1
- package/dist/common/common.module.js.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/medias.controller.js +1 -1
- package/dist/medias.controller.js.map +1 -1
- package/dist/medias.d.ts +24 -4
- package/dist/medias.js +151 -19
- package/dist/medias.js.map +1 -1
- package/dist/medias.module.js +4 -1
- package/dist/medias.module.js.map +1 -1
- package/dist/medias.repository.js +1 -1
- package/dist/medias.repository.js.map +1 -1
- package/dist/pipe/validate-search.pipe.d.ts +2 -2
- package/dist/pipe/validate-search.pipe.js +5 -5
- package/dist/pipe/validate-search.pipe.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/migration/media-migration.js +83 -0
- package/package.json +16 -2
- package/src/base/base.medias.ts +22 -13
- package/src/common/common.module.ts +1 -1
- package/src/index.ts +14 -4
- package/src/medias.repository.ts +2 -5
- package/src/medias.ts +225 -35
- package/src/pipe/validate-search.pipe.ts +7 -4
- package/src/medias.controller.ts +0 -244
- package/src/medias.module.ts +0 -19
package/src/medias.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BlobServiceClient } from '@azure/storage-blob';
|
|
2
|
-
import { BadRequestException } from '@nestjs/common';
|
|
2
|
+
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
|
3
3
|
import * as crypto from 'crypto';
|
|
4
4
|
import * as fs from 'fs';
|
|
5
5
|
import { CommonService } from './common/common.service';
|
|
@@ -9,6 +9,10 @@ import { MediasModel } from './entities/medias.entity';
|
|
|
9
9
|
import { IBaseMediasAttr } from './interfaces/base.medias-attr.interface';
|
|
10
10
|
import { IMediasRepository } from './interfaces/medias.repository.interface';
|
|
11
11
|
import { Readable } from 'stream';
|
|
12
|
+
import { InternalMediaDto } from './dto/internal-medias.dto';
|
|
13
|
+
import { ExternalMediaDto } from './dto/external-media.dto';
|
|
14
|
+
import * as cuid from 'cuid';
|
|
15
|
+
import { Op } from 'sequelize';
|
|
12
16
|
|
|
13
17
|
type MediaFile = {
|
|
14
18
|
buffer: Buffer;
|
|
@@ -31,11 +35,11 @@ export class Medias extends BaseMedias {
|
|
|
31
35
|
entity = typeof MediasModel;
|
|
32
36
|
|
|
33
37
|
constructor(
|
|
34
|
-
|
|
38
|
+
mediasRepository: IMediasRepository,
|
|
35
39
|
commonService: CommonService,
|
|
36
40
|
media?: IBaseMediasAttr,
|
|
37
41
|
) {
|
|
38
|
-
super(
|
|
42
|
+
super(mediasRepository, media);
|
|
39
43
|
this.commonService = commonService;
|
|
40
44
|
try {
|
|
41
45
|
this.container = process.env.MEDIA_AZUREBLOB_CONTAINER_NAME;
|
|
@@ -60,6 +64,7 @@ export class Medias extends BaseMedias {
|
|
|
60
64
|
activityDescription = `Added a new media Id: ${this.MediaId}.`;
|
|
61
65
|
await this.createInternalMedias(stream);
|
|
62
66
|
}
|
|
67
|
+
|
|
63
68
|
if (media) {
|
|
64
69
|
await this.commonService.addActivityHistory(
|
|
65
70
|
{
|
|
@@ -73,7 +78,7 @@ export class Medias extends BaseMedias {
|
|
|
73
78
|
PerformedAt: this.CreatedAt,
|
|
74
79
|
},
|
|
75
80
|
this.entity,
|
|
76
|
-
'',
|
|
81
|
+
'create',
|
|
77
82
|
);
|
|
78
83
|
}
|
|
79
84
|
return media;
|
|
@@ -87,7 +92,9 @@ export class Medias extends BaseMedias {
|
|
|
87
92
|
stream?: Express.Multer.File,
|
|
88
93
|
) {
|
|
89
94
|
try {
|
|
90
|
-
const oldMedia = await super.findOne({
|
|
95
|
+
const oldMedia = await super.findOne({
|
|
96
|
+
where: { MediaId: this.MediaId },
|
|
97
|
+
});
|
|
91
98
|
const media = await super.update();
|
|
92
99
|
let activityDescription = `Updated external media Id: ${this.MediaId}.`;
|
|
93
100
|
if (!isExternalMedias) {
|
|
@@ -109,7 +116,7 @@ export class Medias extends BaseMedias {
|
|
|
109
116
|
PerformedAt: this.UpdatedAt,
|
|
110
117
|
},
|
|
111
118
|
this.entity,
|
|
112
|
-
'',
|
|
119
|
+
'update',
|
|
113
120
|
);
|
|
114
121
|
}
|
|
115
122
|
|
|
@@ -137,7 +144,7 @@ export class Medias extends BaseMedias {
|
|
|
137
144
|
this.FileName = this.FileName.replace(/\.[^/.]+$/, '');
|
|
138
145
|
|
|
139
146
|
let file: MediaFile;
|
|
140
|
-
if (this.IsEncryptedYN
|
|
147
|
+
if (this.IsEncryptedYN === 'Y') {
|
|
141
148
|
file = await this.encrypt(stream.buffer);
|
|
142
149
|
} else {
|
|
143
150
|
file = {
|
|
@@ -160,7 +167,7 @@ export class Medias extends BaseMedias {
|
|
|
160
167
|
const isDir = await isDirExist(filePath);
|
|
161
168
|
if (isDir) {
|
|
162
169
|
fs.unlinkSync(this.FilePath);
|
|
163
|
-
if (this.IsEncryptedYN
|
|
170
|
+
if (this.IsEncryptedYN === 'Y') {
|
|
164
171
|
fs.unlinkSync(this.getIvPath());
|
|
165
172
|
}
|
|
166
173
|
}
|
|
@@ -178,7 +185,7 @@ export class Medias extends BaseMedias {
|
|
|
178
185
|
this.FileExtension = this.FileExtension.split('.')[0];
|
|
179
186
|
this.FileName = this.FileName.replace(/\.[^/.]+$/, '');
|
|
180
187
|
let file: MediaFile;
|
|
181
|
-
if (this.IsEncryptedYN
|
|
188
|
+
if (this.IsEncryptedYN === 'Y') {
|
|
182
189
|
file = await this.encrypt(stream.buffer);
|
|
183
190
|
} else {
|
|
184
191
|
file = {
|
|
@@ -224,8 +231,8 @@ export class Medias extends BaseMedias {
|
|
|
224
231
|
}
|
|
225
232
|
|
|
226
233
|
private async deleteUploadedFileFromLocal(
|
|
227
|
-
path:string,
|
|
228
|
-
isEncryptedYN:string,
|
|
234
|
+
path: string,
|
|
235
|
+
isEncryptedYN: string,
|
|
229
236
|
): Promise<void> {
|
|
230
237
|
try {
|
|
231
238
|
const isDirExist = util.promisify(fs.exists);
|
|
@@ -233,7 +240,7 @@ export class Medias extends BaseMedias {
|
|
|
233
240
|
if (isDir) {
|
|
234
241
|
const deleteFile = util.promisify(fs.unlink);
|
|
235
242
|
await deleteFile(path);
|
|
236
|
-
if (isEncryptedYN
|
|
243
|
+
if (isEncryptedYN === 'Y') {
|
|
237
244
|
await deleteFile(this.getIvPath());
|
|
238
245
|
}
|
|
239
246
|
}
|
|
@@ -252,18 +259,18 @@ export class Medias extends BaseMedias {
|
|
|
252
259
|
);
|
|
253
260
|
|
|
254
261
|
let ivPath: string;
|
|
255
|
-
if (this.IsEncryptedYN
|
|
262
|
+
if (this.IsEncryptedYN === 'Y') {
|
|
256
263
|
ivPath = await this.uploadFileToAzureStorage(
|
|
257
264
|
file.iv,
|
|
258
265
|
this.ObjectType,
|
|
259
266
|
this.ObjectId,
|
|
260
|
-
this.FileName+
|
|
267
|
+
this.FileName + 'iv',
|
|
261
268
|
'iv',
|
|
262
269
|
);
|
|
263
270
|
}
|
|
264
271
|
|
|
265
272
|
const path: FilePath = {
|
|
266
|
-
filePath
|
|
273
|
+
filePath,
|
|
267
274
|
ivFilePath: ivPath,
|
|
268
275
|
};
|
|
269
276
|
|
|
@@ -277,9 +284,17 @@ export class Medias extends BaseMedias {
|
|
|
277
284
|
isEncryptedYN: string,
|
|
278
285
|
): Promise<void> {
|
|
279
286
|
try {
|
|
280
|
-
await this.deleteUploadedFileToAzureStorage(
|
|
281
|
-
|
|
282
|
-
|
|
287
|
+
await this.deleteUploadedFileToAzureStorage(
|
|
288
|
+
path,
|
|
289
|
+
FileName,
|
|
290
|
+
FileExtension,
|
|
291
|
+
);
|
|
292
|
+
if (isEncryptedYN === 'Y') {
|
|
293
|
+
await this.deleteUploadedFileToAzureStorage(
|
|
294
|
+
path,
|
|
295
|
+
FileName + 'iv',
|
|
296
|
+
'.iv',
|
|
297
|
+
);
|
|
283
298
|
}
|
|
284
299
|
} catch (error) {
|
|
285
300
|
throw error;
|
|
@@ -307,7 +322,7 @@ export class Medias extends BaseMedias {
|
|
|
307
322
|
}
|
|
308
323
|
}
|
|
309
324
|
|
|
310
|
-
async deleteUploadedFileToAzureStorage(
|
|
325
|
+
private async deleteUploadedFileToAzureStorage(
|
|
311
326
|
path: string,
|
|
312
327
|
FileName: string,
|
|
313
328
|
FileExtension: string,
|
|
@@ -334,7 +349,7 @@ export class Medias extends BaseMedias {
|
|
|
334
349
|
}
|
|
335
350
|
}
|
|
336
351
|
|
|
337
|
-
async
|
|
352
|
+
async findFile(): Promise<Buffer> {
|
|
338
353
|
try {
|
|
339
354
|
let fileBuffer: Buffer;
|
|
340
355
|
if (this.IsStorageTypeAzure()) {
|
|
@@ -355,8 +370,8 @@ export class Medias extends BaseMedias {
|
|
|
355
370
|
if (this.IsStorageTypeAzure()) {
|
|
356
371
|
file.iv = await this.getFileFromAzure(
|
|
357
372
|
this.URL,
|
|
358
|
-
this.FileName+
|
|
359
|
-
'iv'
|
|
373
|
+
this.FileName + 'iv',
|
|
374
|
+
'iv',
|
|
360
375
|
);
|
|
361
376
|
} else {
|
|
362
377
|
file.iv = await this.getFileFromLocal(this.getIvPath());
|
|
@@ -369,7 +384,9 @@ export class Medias extends BaseMedias {
|
|
|
369
384
|
}
|
|
370
385
|
}
|
|
371
386
|
|
|
372
|
-
private async stream2buffer(
|
|
387
|
+
private async stream2buffer(
|
|
388
|
+
stream: Readable | fs.ReadStream,
|
|
389
|
+
): Promise<Buffer> {
|
|
373
390
|
return new Promise<Buffer>((resolve, reject) => {
|
|
374
391
|
const buffer = Array<any>();
|
|
375
392
|
|
|
@@ -391,9 +408,11 @@ export class Medias extends BaseMedias {
|
|
|
391
408
|
`${fileName}.${FileExtension}`,
|
|
392
409
|
);
|
|
393
410
|
const downloadResponse = await blockBlobClient.download();
|
|
394
|
-
const ReadStream = new Readable().wrap(
|
|
411
|
+
const ReadStream = new Readable().wrap(
|
|
412
|
+
downloadResponse.readableStreamBody,
|
|
413
|
+
);
|
|
395
414
|
const file = await this.stream2buffer(ReadStream);
|
|
396
|
-
return file
|
|
415
|
+
return file;
|
|
397
416
|
} catch (error) {
|
|
398
417
|
throw error;
|
|
399
418
|
}
|
|
@@ -422,7 +441,7 @@ export class Medias extends BaseMedias {
|
|
|
422
441
|
|
|
423
442
|
const result: MediaFile = {
|
|
424
443
|
buffer: resultBuffer,
|
|
425
|
-
iv
|
|
444
|
+
iv,
|
|
426
445
|
isEncrypted: true,
|
|
427
446
|
};
|
|
428
447
|
|
|
@@ -453,10 +472,10 @@ export class Medias extends BaseMedias {
|
|
|
453
472
|
}
|
|
454
473
|
}
|
|
455
474
|
|
|
456
|
-
async delete(): Promise<any> {
|
|
475
|
+
public async delete(): Promise<any> {
|
|
457
476
|
try {
|
|
458
477
|
const data: MediasModel = await super.delete();
|
|
459
|
-
if (this.IsExternalYN
|
|
478
|
+
if (this.IsExternalYN === 'N') {
|
|
460
479
|
if (this.IsStorageTypeAzure()) {
|
|
461
480
|
await this.deleteUploadedFileFromAzure(
|
|
462
481
|
this.URL,
|
|
@@ -465,10 +484,7 @@ export class Medias extends BaseMedias {
|
|
|
465
484
|
this.IsEncryptedYN,
|
|
466
485
|
);
|
|
467
486
|
} else {
|
|
468
|
-
await this.deleteUploadedFileFromLocal(
|
|
469
|
-
this.URL,
|
|
470
|
-
this.IsEncryptedYN
|
|
471
|
-
);
|
|
487
|
+
await this.deleteUploadedFileFromLocal(this.URL, this.IsEncryptedYN);
|
|
472
488
|
}
|
|
473
489
|
}
|
|
474
490
|
|
|
@@ -484,11 +500,185 @@ export class Medias extends BaseMedias {
|
|
|
484
500
|
PerformedAt: new Date(),
|
|
485
501
|
},
|
|
486
502
|
this.entity,
|
|
487
|
-
'',
|
|
503
|
+
'delete',
|
|
488
504
|
);
|
|
489
|
-
return { message: 'Media has been deleted.' }
|
|
505
|
+
return { message: 'Media has been deleted.' };
|
|
506
|
+
} catch (error) {
|
|
507
|
+
throw error;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
async postInternal(
|
|
512
|
+
fileStream: Express.Multer.File,
|
|
513
|
+
createMediaDto: InternalMediaDto,
|
|
514
|
+
userId: string,
|
|
515
|
+
) {
|
|
516
|
+
try {
|
|
517
|
+
const mediaAttr: IBaseMediasAttr = {
|
|
518
|
+
...createMediaDto,
|
|
519
|
+
MediaId: cuid(),
|
|
520
|
+
IsExternalYN: 'N',
|
|
521
|
+
ExternalSource: '',
|
|
522
|
+
URL: '',
|
|
523
|
+
FilePath: '',
|
|
524
|
+
CreatedAt: new Date(),
|
|
525
|
+
UpdatedAt: new Date(),
|
|
526
|
+
CreatedById: userId,
|
|
527
|
+
UpdatedById: userId,
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
this.init(mediaAttr);
|
|
531
|
+
const createdData = await this.createMedias(false, fileStream);
|
|
532
|
+
return createdData;
|
|
533
|
+
} catch (error) {
|
|
534
|
+
throw error;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
async postExternal(createMediaDto: ExternalMediaDto, userId: string) {
|
|
539
|
+
const mediaAttr: IBaseMediasAttr = {
|
|
540
|
+
...createMediaDto,
|
|
541
|
+
MediaId: cuid(),
|
|
542
|
+
IsExternalYN: 'Y',
|
|
543
|
+
CreatedAt: new Date(),
|
|
544
|
+
UpdatedAt: new Date(),
|
|
545
|
+
IsEncryptedYN: 'N',
|
|
546
|
+
FilePath: '',
|
|
547
|
+
FileName: '',
|
|
548
|
+
FileExtension: '',
|
|
549
|
+
CreatedById: userId,
|
|
550
|
+
UpdatedById: userId,
|
|
551
|
+
};
|
|
552
|
+
this.init(mediaAttr);
|
|
553
|
+
await this.createMedias(true);
|
|
554
|
+
return mediaAttr;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
async getAll(rows: number, page: number, search: string) {
|
|
558
|
+
let searchObj: any;
|
|
559
|
+
try {
|
|
560
|
+
searchObj = search ? JSON.parse(search) : {};
|
|
561
|
+
} catch (err) {
|
|
562
|
+
throw new BadRequestException('Bad value for search.');
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const { ...mediaFilter } = searchObj;
|
|
566
|
+
const queryObj = {};
|
|
567
|
+
|
|
568
|
+
Object.entries(mediaFilter).forEach(([key, value]) => {
|
|
569
|
+
queryObj[key] = {
|
|
570
|
+
[Op.substring]: value,
|
|
571
|
+
};
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
const offset = rows * (page - 1);
|
|
575
|
+
|
|
576
|
+
const options = {
|
|
577
|
+
order: [['CreatedAt', 'DESC']],
|
|
578
|
+
limit: rows,
|
|
579
|
+
offset,
|
|
580
|
+
where: queryObj,
|
|
581
|
+
distinct: true,
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
return this.findAllWithPagination(options);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
async getOne(id: string) {
|
|
588
|
+
try {
|
|
589
|
+
const media = await this.findOne({ where: { MediaId: id } });
|
|
590
|
+
if (!media) {
|
|
591
|
+
throw new NotFoundException(`Media not found with id ${id}`);
|
|
592
|
+
}
|
|
593
|
+
return media;
|
|
594
|
+
} catch (error) {
|
|
595
|
+
throw error;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
async getFile(id: string) {
|
|
600
|
+
try {
|
|
601
|
+
const media = await this.findOne({ where: { MediaId: id } });
|
|
602
|
+
if (!media) {
|
|
603
|
+
throw new NotFoundException(`Media not found with id ${id}`);
|
|
604
|
+
}
|
|
605
|
+
this.init({ ...media.get({ plain: true }) });
|
|
606
|
+
const fileBuffer: Buffer = await this.findFile();
|
|
607
|
+
return {
|
|
608
|
+
fileBuffer: fileBuffer,
|
|
609
|
+
resOption: {
|
|
610
|
+
'Content-Type': 'application/octet-stream',
|
|
611
|
+
'Content-Disposition': `attachment; filename=${media.FileName}.${media.FileExtension}`,
|
|
612
|
+
'Content-Length': fileBuffer.length,
|
|
613
|
+
},
|
|
614
|
+
};
|
|
615
|
+
} catch (error) {
|
|
616
|
+
throw error;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
async remove(id: string, userId: string) {
|
|
621
|
+
try {
|
|
622
|
+
const media = await this.findOne({ where: { MediaId: id } });
|
|
623
|
+
if (!media) {
|
|
624
|
+
throw new NotFoundException(`Media not found with id ${id}`);
|
|
625
|
+
}
|
|
626
|
+
const mediaAttr: IBaseMediasAttr = {
|
|
627
|
+
...media.get({ plain: true }),
|
|
628
|
+
UpdatedAt: new Date(),
|
|
629
|
+
UpdatedById: userId,
|
|
630
|
+
};
|
|
631
|
+
this.init(mediaAttr);
|
|
632
|
+
return await this.delete();
|
|
490
633
|
} catch (error) {
|
|
491
|
-
throw error
|
|
634
|
+
throw error;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
async putExternal(
|
|
639
|
+
id: string,
|
|
640
|
+
updatedMediaDto: ExternalMediaDto,
|
|
641
|
+
userId: string,
|
|
642
|
+
) {
|
|
643
|
+
try {
|
|
644
|
+
const media = await this.findOne({ where: { MediaId: id } });
|
|
645
|
+
if (!media) {
|
|
646
|
+
throw new NotFoundException(`Media not found with id ${id}`);
|
|
647
|
+
}
|
|
648
|
+
const mediaAttr: IBaseMediasAttr = {
|
|
649
|
+
...media.get({ plain: true }),
|
|
650
|
+
...updatedMediaDto,
|
|
651
|
+
UpdatedAt: new Date(),
|
|
652
|
+
UpdatedById: userId,
|
|
653
|
+
};
|
|
654
|
+
this.init(mediaAttr);
|
|
655
|
+
return await this.updateMedias(true);
|
|
656
|
+
} catch (error) {
|
|
657
|
+
throw error;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
async putInternal(
|
|
662
|
+
fileStream: Express.Multer.File,
|
|
663
|
+
id: string,
|
|
664
|
+
updatedMediaDto: InternalMediaDto,
|
|
665
|
+
userId: string
|
|
666
|
+
) {
|
|
667
|
+
try {
|
|
668
|
+
const media = await this.findOne({ where: { MediaId: id } });
|
|
669
|
+
if (!media) {
|
|
670
|
+
throw new NotFoundException(`Media not found with id ${id}`);
|
|
671
|
+
}
|
|
672
|
+
const mediaAttr: IBaseMediasAttr = {
|
|
673
|
+
...media.get({ plain: true }),
|
|
674
|
+
...updatedMediaDto,
|
|
675
|
+
UpdatedAt: new Date(),
|
|
676
|
+
UpdatedById: userId,
|
|
677
|
+
};
|
|
678
|
+
this.init(mediaAttr);
|
|
679
|
+
return await this.updateMedias(true,fileStream);
|
|
680
|
+
} catch (error) {
|
|
681
|
+
throw error;
|
|
492
682
|
}
|
|
493
683
|
}
|
|
494
684
|
}
|
|
@@ -7,7 +7,10 @@ import {
|
|
|
7
7
|
|
|
8
8
|
@Injectable()
|
|
9
9
|
export class ValidateSearchPipe implements PipeTransform {
|
|
10
|
-
constructor(
|
|
10
|
+
constructor(
|
|
11
|
+
private model: any,
|
|
12
|
+
private additionalAttributes: string[] = [],
|
|
13
|
+
) {}
|
|
11
14
|
|
|
12
15
|
transform(value: string) {
|
|
13
16
|
let search = {};
|
|
@@ -19,12 +22,12 @@ export class ValidateSearchPipe implements PipeTransform {
|
|
|
19
22
|
throw new BadRequestException('Bad value for search.');
|
|
20
23
|
}
|
|
21
24
|
const attributes: string[] = [
|
|
22
|
-
...this.
|
|
23
|
-
...Object.keys(this.model
|
|
25
|
+
...this.additionalAttributes,
|
|
26
|
+
...Object.keys(this.model.tableAttributes),
|
|
24
27
|
];
|
|
25
28
|
const searchAttributes: string[] = Object.keys(search);
|
|
26
29
|
const invalidKeys = searchAttributes.filter(
|
|
27
|
-
(
|
|
30
|
+
(attr) => !attributes.includes(attr),
|
|
28
31
|
);
|
|
29
32
|
|
|
30
33
|
if (invalidKeys.length > 0) {
|
package/src/medias.controller.ts
DELETED
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DefaultValuePipe,
|
|
3
|
-
Get,
|
|
4
|
-
Inject,
|
|
5
|
-
ParseIntPipe,
|
|
6
|
-
Query,
|
|
7
|
-
Body,
|
|
8
|
-
Controller,
|
|
9
|
-
Post,
|
|
10
|
-
UploadedFile,
|
|
11
|
-
UseInterceptors,
|
|
12
|
-
BadRequestException,
|
|
13
|
-
Delete,
|
|
14
|
-
Param,
|
|
15
|
-
Put,
|
|
16
|
-
StreamableFile,
|
|
17
|
-
Res,
|
|
18
|
-
HttpException,
|
|
19
|
-
} from '@nestjs/common';
|
|
20
|
-
import { FileInterceptor } from '@nestjs/platform-express';
|
|
21
|
-
import { ApiOkResponse, ApiOperation } from '@nestjs/swagger';
|
|
22
|
-
import * as cuid from 'cuid';
|
|
23
|
-
import { CommonService } from './common/common.service';
|
|
24
|
-
import { ValidateSearchPipe } from './pipe/validate-search.pipe';
|
|
25
|
-
import { ExternalMediaDto } from './dto/external-media.dto';
|
|
26
|
-
import { InternalMediaDto } from './dto/internal-medias.dto';
|
|
27
|
-
import { MediasModel } from './entities/medias.entity';
|
|
28
|
-
import { IBaseMediasAttr } from './interfaces/base.medias-attr.interface';
|
|
29
|
-
import { IMediasRepository } from './interfaces/medias.repository.interface';
|
|
30
|
-
import { Medias } from './medias';
|
|
31
|
-
import { Op } from 'sequelize';
|
|
32
|
-
import { ValidateIdPipe } from './pipe/validate-id.pipe';
|
|
33
|
-
import { Response } from 'express';
|
|
34
|
-
import { throwException } from './helpers';
|
|
35
|
-
|
|
36
|
-
@Controller('medias')
|
|
37
|
-
export class MediasController {
|
|
38
|
-
constructor(
|
|
39
|
-
@Inject('MediasRepository')
|
|
40
|
-
private readonly mediaRepository: IMediasRepository,
|
|
41
|
-
private readonly commonService: CommonService,
|
|
42
|
-
) {}
|
|
43
|
-
@Post('internal')
|
|
44
|
-
@UseInterceptors(FileInterceptor('FileStream'))
|
|
45
|
-
async createInternal(
|
|
46
|
-
@UploadedFile() fileStream: Express.Multer.File,
|
|
47
|
-
@Body() createMedia: InternalMediaDto,
|
|
48
|
-
) {
|
|
49
|
-
try {
|
|
50
|
-
const mediaAttr: IBaseMediasAttr = {
|
|
51
|
-
...createMedia,
|
|
52
|
-
MediaId: cuid(),
|
|
53
|
-
IsExternalYN: 'N',
|
|
54
|
-
ExternalSource: '',
|
|
55
|
-
URL: '',
|
|
56
|
-
FilePath: '',
|
|
57
|
-
CreatedAt: new Date(),
|
|
58
|
-
UpdatedAt: new Date(),
|
|
59
|
-
CreatedById: 'test_user',
|
|
60
|
-
UpdatedById: 'test_user',
|
|
61
|
-
};
|
|
62
|
-
const media = new Medias(
|
|
63
|
-
this.mediaRepository,
|
|
64
|
-
this.commonService,
|
|
65
|
-
mediaAttr,
|
|
66
|
-
);
|
|
67
|
-
const createdData = await media.createMedias(false, fileStream);
|
|
68
|
-
return createdData;
|
|
69
|
-
} catch (error) {
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
@Post('/external')
|
|
75
|
-
async createExternal(@Body() createMedia: ExternalMediaDto) {
|
|
76
|
-
const mediaAttr: IBaseMediasAttr = {
|
|
77
|
-
...createMedia,
|
|
78
|
-
MediaId: cuid(),
|
|
79
|
-
IsExternalYN: 'Y',
|
|
80
|
-
CreatedAt: new Date(),
|
|
81
|
-
UpdatedAt: new Date(),
|
|
82
|
-
IsEncryptedYN: 'N',
|
|
83
|
-
FilePath: '',
|
|
84
|
-
FileName: '',
|
|
85
|
-
FileExtension: '',
|
|
86
|
-
CreatedById: 'test_user',
|
|
87
|
-
UpdatedById: 'test_user',
|
|
88
|
-
};
|
|
89
|
-
const media = new Medias(
|
|
90
|
-
this.mediaRepository,
|
|
91
|
-
this.commonService,
|
|
92
|
-
mediaAttr,
|
|
93
|
-
);
|
|
94
|
-
await media.createMedias(true);
|
|
95
|
-
return mediaAttr;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@Get()
|
|
99
|
-
@ApiOperation({
|
|
100
|
-
summary: 'Get all Medias',
|
|
101
|
-
})
|
|
102
|
-
@ApiOkResponse({
|
|
103
|
-
description: 'Paginanted Medias',
|
|
104
|
-
})
|
|
105
|
-
async findAll(
|
|
106
|
-
@Query('rows', new DefaultValuePipe(10), ParseIntPipe) rows: number,
|
|
107
|
-
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
|
|
108
|
-
@Query(
|
|
109
|
-
'search',
|
|
110
|
-
new ValidateSearchPipe(MediasModel, ['ObjectId', 'ObjectType', 'Title']),
|
|
111
|
-
)
|
|
112
|
-
search: string,
|
|
113
|
-
) {
|
|
114
|
-
let searchObj: any;
|
|
115
|
-
try {
|
|
116
|
-
searchObj = search ? JSON.parse(search) : {};
|
|
117
|
-
} catch (err) {
|
|
118
|
-
throw new BadRequestException('Bad value for search.');
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const { ...mediaFilter } = searchObj;
|
|
122
|
-
const queryObj = {};
|
|
123
|
-
|
|
124
|
-
Object.entries(mediaFilter).forEach(([key, value]) => {
|
|
125
|
-
queryObj[key] = {
|
|
126
|
-
[Op.substring]: value,
|
|
127
|
-
};
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
const offset = rows * (page - 1);
|
|
131
|
-
|
|
132
|
-
const options = {
|
|
133
|
-
order: [['CreatedAt', 'DESC']],
|
|
134
|
-
limit: rows,
|
|
135
|
-
offset: offset,
|
|
136
|
-
where: queryObj,
|
|
137
|
-
distinct: true,
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const media = new Medias(this.mediaRepository, this.commonService);
|
|
141
|
-
|
|
142
|
-
return media.findAllWithPagination(options);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
@Get('/:id')
|
|
146
|
-
@ApiOperation({ summary: 'Get media by MediaId' })
|
|
147
|
-
@ApiOkResponse({
|
|
148
|
-
description: 'The found media',
|
|
149
|
-
type: MediasModel,
|
|
150
|
-
})
|
|
151
|
-
async findOne(@Param('id', new ValidateIdPipe()) id: string) {
|
|
152
|
-
const media = new Medias(this.mediaRepository, this.commonService);
|
|
153
|
-
const file = await media.findOne({where: { MediaId: id}});
|
|
154
|
-
return file;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
@Get('/:id/file')
|
|
158
|
-
@ApiOperation({ summary: 'Get media file by MediaId' })
|
|
159
|
-
@ApiOkResponse({
|
|
160
|
-
description: 'filestream',
|
|
161
|
-
type: Buffer,
|
|
162
|
-
})
|
|
163
|
-
async getFile(
|
|
164
|
-
@Param('id', new ValidateIdPipe()) id: string,
|
|
165
|
-
@Res({ passthrough: true }) res: Response,
|
|
166
|
-
) {
|
|
167
|
-
let media = new Medias(this.mediaRepository, this.commonService);
|
|
168
|
-
const mediaData = await media.findOne({where: { MediaId: id}});
|
|
169
|
-
media = new Medias(this.mediaRepository, this.commonService, {
|
|
170
|
-
...mediaData.get({ plain: true }),
|
|
171
|
-
});
|
|
172
|
-
const fileBuffer: Buffer = await media.getFile();
|
|
173
|
-
|
|
174
|
-
res.set({
|
|
175
|
-
'Content-Type': 'application/octet-stream',
|
|
176
|
-
'Content-Disposition': `attachment; filename=${mediaData.FileName}.${mediaData.FileExtension}`,
|
|
177
|
-
'Content-Length': fileBuffer.length,
|
|
178
|
-
});
|
|
179
|
-
return new StreamableFile(fileBuffer);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
@Delete('/:id')
|
|
183
|
-
@ApiOperation({ summary: 'Delete media by MediaId' })
|
|
184
|
-
async delete(@Param('id', new ValidateIdPipe()) id: string) {
|
|
185
|
-
try {
|
|
186
|
-
let media = new Medias(this.mediaRepository, this.commonService);
|
|
187
|
-
const mediaData = await media.findOne({where: { MediaId: id}});
|
|
188
|
-
|
|
189
|
-
const mediaAttr: IBaseMediasAttr = {
|
|
190
|
-
...mediaData.get({ plain: true }),
|
|
191
|
-
UpdatedAt: new Date(),
|
|
192
|
-
UpdatedById: 'test_user',
|
|
193
|
-
};
|
|
194
|
-
media = new Medias(this.mediaRepository, this.commonService, mediaAttr);
|
|
195
|
-
return await media.delete();
|
|
196
|
-
} catch (error) {
|
|
197
|
-
throw error;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
@Put('/external/:id')
|
|
202
|
-
async updateExternal(
|
|
203
|
-
@Param('id', new ValidateIdPipe()) id: string,
|
|
204
|
-
@Body() updatedMedia: ExternalMediaDto,
|
|
205
|
-
) {
|
|
206
|
-
let media = new Medias(this.mediaRepository, this.commonService);
|
|
207
|
-
|
|
208
|
-
const mediaData = await media.findOne({where: { MediaId: id}});
|
|
209
|
-
|
|
210
|
-
const mediaAttr: IBaseMediasAttr = {
|
|
211
|
-
...mediaData.get({ plain: true }),
|
|
212
|
-
...updatedMedia,
|
|
213
|
-
UpdatedAt: new Date(),
|
|
214
|
-
UpdatedById: 'test_user',
|
|
215
|
-
};
|
|
216
|
-
media = new Medias(this.mediaRepository, this.commonService, mediaAttr);
|
|
217
|
-
await media.updateMedias(true);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
@Put('/internal/:id')
|
|
221
|
-
@UseInterceptors(FileInterceptor('FileStream'))
|
|
222
|
-
async updateInternal(
|
|
223
|
-
@UploadedFile() fileStream: Express.Multer.File,
|
|
224
|
-
@Param('id', new ValidateIdPipe()) id: string,
|
|
225
|
-
@Body() updatedMedia: InternalMediaDto,
|
|
226
|
-
) {
|
|
227
|
-
try {
|
|
228
|
-
let media = new Medias(this.mediaRepository, this.commonService);
|
|
229
|
-
|
|
230
|
-
const mediaData = await media.findOne({where: { MediaId: id}});
|
|
231
|
-
const mediaAttr: IBaseMediasAttr = {
|
|
232
|
-
...mediaData.get({ plain: true }),
|
|
233
|
-
...updatedMedia,
|
|
234
|
-
UpdatedAt: new Date(),
|
|
235
|
-
UpdatedById: 'test_user',
|
|
236
|
-
};
|
|
237
|
-
media = new Medias(this.mediaRepository, this.commonService, mediaAttr);
|
|
238
|
-
await media.updateMedias(false, fileStream);
|
|
239
|
-
return mediaAttr;
|
|
240
|
-
} catch (error) {
|
|
241
|
-
throw error;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|