Skip to content

Commit d65b5c1

Browse files
committed
image upload
1 parent 598204e commit d65b5c1

46 files changed

Lines changed: 661 additions & 361 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/src/core/configuration.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ const MinioConfig = registerAs(ConfigKey.Minio, () => ({
4747
useSsl: process.env.MINIO_USE_SSL === 'true',
4848
accessKey: process.env.MINIO_ACCESS_KEY,
4949
secretKey: process.env.MINIO_SECRET_KEY,
50-
uploadExpiry: process.env.MINIO_UPLOAD_EXPIRY,
51-
downloadExpiry: process.env.MINIO_DOWNLOAD_EXPIRY,
50+
uploadExpiry: Number(process.env.MINIO_UPLOAD_EXPIRY),
51+
downloadExpiry: Number(process.env.MINIO_DOWNLOAD_EXPIRY),
5252
bucketName: process.env.MINIO_BUCKET_NAME,
5353
}));
5454

backend/src/core/services/amqp.service.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ describe('AmqpService', () => {
1515
it('should be defined', () => {
1616
expect(service).toBeDefined();
1717
});
18-
});
18+
});

backend/src/core/services/request-context.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { AsyncLocalStorage } from 'async_hooks';
55
export class RequestContextService {
66
private readonly als = new AsyncLocalStorage<Map<string, string>>();
77

8-
run(callback: () => void, context: Record<string, any>) {
8+
run(callback: () => void, context: Record<string, string>) {
99
const store = new Map(Object.entries(context));
1010
this.als.run(store, callback);
1111
}
1212

13-
set(key: string, value: any) {
13+
set(key: string, value: string) {
1414
const store = this.als.getStore();
1515
if (store) {
1616
store.set(key, value);

backend/src/core/services/storage/image.service.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { Injectable } from '@nestjs/common';
2-
import { BucketEventRecordS3Object } from './dto/minio-listener/bucket-event.dto';
1+
import { forwardRef, Inject, Injectable } from '@nestjs/common';
32
import { MinioService } from './minio.service';
43
import * as sharp from 'sharp';
54
import { Sharp } from 'sharp';
@@ -8,16 +7,17 @@ import { DeviceService } from '../../../inventory/device/device.service';
87
@Injectable()
98
export class ImageService {
109
static readonly sizes = [200, 480, 800, 1200, 1600, 2000, 4000];
10+
static readonly blurredSizes = [600];
11+
static readonly previewSuffix = '-webp-480';
1112

1213
constructor(
14+
@Inject(forwardRef(() => MinioService))
1315
private readonly minioService: MinioService,
16+
@Inject(forwardRef(() => DeviceService))
1417
private readonly deivceService: DeviceService,
1518
) {}
1619

17-
public async processDevice(
18-
key: string,
19-
bucketObject: BucketEventRecordS3Object,
20-
) {
20+
public async processDevice(key: string) {
2121
try {
2222
const img = await this.loadImage(key);
2323
await this.convertImage(key, img);
@@ -54,15 +54,20 @@ export class ImageService {
5454
}
5555

5656
private async blurredImage(key: string, img: Sharp) {
57-
const size = 600;
58-
const buffer = await img
59-
.resize(size, null, { fit: 'inside' })
60-
.blur(40)
61-
.toBuffer();
57+
for (const size of ImageService.blurredSizes) {
58+
const buffer = await img
59+
.resize(size, null, { fit: 'inside' })
60+
.blur(40)
61+
.toBuffer();
6262

63-
await this.minioService.putObject(key + '-webp-' + size + '-blur', buffer, {
64-
'Content-Type': 'image/webp',
65-
});
63+
await this.minioService.putObject(
64+
key + '-webp-' + size + '-blur',
65+
buffer,
66+
{
67+
'Content-Type': 'image/webp',
68+
},
69+
);
70+
}
6671
}
6772

6873
private async loadImage(key: string): Promise<Sharp> {

backend/src/core/services/storage/minio-listener.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class MinioListenerService implements OnApplicationBootstrap {
6565

6666
if (key.startsWith('devices/')) {
6767
if (imageType) {
68-
await services.imageService.processDevice(key, bucketObject);
68+
await services.imageService.processDevice(key);
6969
}
7070
}
7171
}

backend/src/core/services/storage/minio.service.ts

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
import { Injectable, Logger } from '@nestjs/common';
1+
import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
22
import { ConfigService } from '@nestjs/config';
33
import { Client, ItemBucketMetadata } from 'minio';
4+
import { ImageService } from './image.service';
45

56
@Injectable()
67
export class MinioService {
78
private readonly allowedImageTypes = [
89
'image/jpeg',
910
'image/png',
1011
'image/tiff',
11-
'image/heic',
1212
];
1313

1414
private client: Client;
@@ -21,6 +21,8 @@ export class MinioService {
2121
constructor(
2222
private readonly configService: ConfigService,
2323
private readonly logger: Logger,
24+
@Inject(forwardRef(() => ImageService))
25+
private readonly imageService: ImageService,
2426
) {
2527
const accessKey = this.configService.get<string>('MINIO.accessKey');
2628
const secretKey = this.configService.get<string>('MINIO.secretKey');
@@ -63,14 +65,22 @@ export class MinioService {
6365
);
6466
}
6567

68+
public async generatePresignedGetUrl(file: string): Promise<string> {
69+
return this.client.presignedGetObject(
70+
this.bucketName,
71+
file,
72+
this.downloadExpiry,
73+
);
74+
}
75+
6676
public async generatePresignedPostUrl(
6777
file: string,
6878
contentType: string,
6979
fileSizeMb: number,
7080
): Promise<{
7181
postURL: string;
7282
formData: {
73-
[key: string]: any;
83+
[key: string]: unknown;
7484
};
7585
}> {
7686
const policy = this.client.newPostPolicy();
@@ -93,7 +103,11 @@ export class MinioService {
93103
return this.client.getObject(this.bucketName, key);
94104
}
95105

96-
public putObject(key: string, webpBuffer: Buffer, metaData?: ItemBucketMetadata) {
106+
public putObject(
107+
key: string,
108+
webpBuffer: Buffer,
109+
metaData?: ItemBucketMetadata,
110+
) {
97111
return this.client.putObject(
98112
this.bucketName,
99113
key,
@@ -102,4 +116,21 @@ export class MinioService {
102116
metaData,
103117
);
104118
}
119+
120+
public async deleteObject(key: string) {
121+
await this.client.removeObject(this.bucketName, key);
122+
}
123+
124+
async deleteImages(entity: string, id: number, imageId: string) {
125+
await Promise.all([
126+
...ImageService.sizes.map(async (size) =>
127+
this.deleteObject(`devices/${id}/images/${imageId}-webp-${size}`),
128+
),
129+
...ImageService.blurredSizes.map(async (size) =>
130+
this.deleteObject(`devices/${id}/images/${imageId}-webp-${size}-blur`),
131+
),
132+
this.deleteObject(`devices/${id}/images/${imageId}`),
133+
this.deleteObject(`devices/${id}/images/${imageId}-webp`),
134+
]);
135+
}
105136
}

backend/src/core/user/user.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export class UserController {
7676
roles: [Role.UserManage],
7777
noContent: true,
7878
})
79-
public deleteUser(@Param() params: IdGuidDto): Observable<void> {
79+
public deleteUser(@Param() params: IdGuidDto): Observable<unknown> {
8080
return this.userService.deleteUser(params.id);
8181
}
8282

backend/src/core/user/user.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class UserService {
8383
);
8484
}
8585

86-
deleteUser(id: string): Observable<void> {
86+
deleteUser(id: string): Observable<unknown> {
8787
return this.keycloakService.deleteUser(id).pipe(
8888
catchError((error: InternalErrorDto) => {
8989
if (error.code === 404) {

backend/src/inventory/consumable-group/consumable-group-db.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,4 @@ export class ConsumableGroupDbService {
7474
const result = await this.repo.delete(id);
7575
return (result.affected ?? 0) > 0;
7676
}
77-
}
77+
}

backend/src/inventory/consumable-group/consumable-group.controller.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ export class ConsumableGroupController {
6565
notFound: true,
6666
roles: [Role.ConsumableGroupManage],
6767
})
68-
public create(@Body() body: ConsumableGroupCreateDto): Promise<ConsumableGroupDto> {
68+
public create(
69+
@Body() body: ConsumableGroupCreateDto,
70+
): Promise<ConsumableGroupDto> {
6971
return this.service.create(body);
7072
}
7173

@@ -93,4 +95,4 @@ export class ConsumableGroupController {
9395
public async delete(@Param() params: IdNumberDto): Promise<void> {
9496
await this.service.delete(params.id);
9597
}
96-
}
98+
}

0 commit comments

Comments
 (0)