Skip to content

Commit e71a9f9

Browse files
committed
πŸ†•πŸ”— MinIO
1 parent 7b2389f commit e71a9f9

3 files changed

Lines changed: 264 additions & 0 deletions

File tree

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/**
2+
* β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
3+
* β”‚ @author jrCleber β”‚
4+
* β”‚ @filename message.model.ts β”‚
5+
* β”‚ Developed by: Cleber Wilson β”‚
6+
* β”‚ Creation date: Dez 05, 2023 β”‚
7+
* β”‚ Contact: contato@codechat.dev β”‚
8+
* β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
9+
* β”‚ @copyright Β© Cleber Wilson 2022. All rights reserved. β”‚
10+
* β”‚ Licensed under the Apache License, Version 2.0 β”‚
11+
* β”‚ β”‚
12+
* β”‚ @license "https://github.com/code-chat-br/whatsapp-api/blob/main/LICENSE" β”‚
13+
* β”‚ β”‚
14+
* β”‚ You may not use this file except in compliance with the License. β”‚
15+
* β”‚ You may obtain a copy of the License at β”‚
16+
* β”‚ β”‚
17+
* β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚
18+
* β”‚ β”‚
19+
* β”‚ Unless required by applicable law or agreed to in writing, software β”‚
20+
* β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚
21+
* β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚
22+
* β”‚ β”‚
23+
* β”‚ See the License for the specific language governing permissions and β”‚
24+
* β”‚ limitations under the License. β”‚
25+
* β”‚ β”‚
26+
* β”‚ @function bucketExists @function createBucket β”‚
27+
* β”‚ @function getObjectUrl @function uploadFile β”‚
28+
* β”‚ @constant minioClient @constant BUCKET β”‚
29+
* β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
30+
* β”‚ @important β”‚
31+
* β”‚ For any future changes to the code in this file, it is recommended to β”‚
32+
* β”‚ contain, together with the modification, the information of the developer β”‚
33+
* β”‚ who changed it and the date of modification. β”‚
34+
* β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
35+
*/
36+
37+
import * as MinIo from 'minio';
38+
import { join } from 'path';
39+
import { Readable, Transform } from 'stream';
40+
import { BadRequestException } from '../../exceptions';
41+
import { Bucket, ConfigService } from '../../config/env.config';
42+
43+
const BUCKET = new ConfigService().get<Bucket>('S3');
44+
45+
type Metadata = {
46+
'Content-Type': string;
47+
'custom-header-keyRemoteJid': string;
48+
'custom-header-pushName': string;
49+
'custom-header-messageId': string;
50+
'custom-header-fromMe': string;
51+
'custom-header-mediaType': string;
52+
};
53+
54+
const minioClient = new MinIo.Client({
55+
endPoint: BUCKET.ENDPOINT,
56+
port: BUCKET.PORT,
57+
useSSL: BUCKET.USE_SSL,
58+
accessKey: BUCKET.ACCESS_KEY,
59+
secretKey: BUCKET.SECRET_KEY,
60+
});
61+
62+
const bucketName = process.env.S3_BUCKET;
63+
64+
const bucketExists = async () => {
65+
try {
66+
const list = await minioClient.listBuckets();
67+
return list.find((bucket) => bucket.name === bucketName);
68+
} catch (error) {
69+
return false;
70+
}
71+
};
72+
73+
const createBucket = async () => {
74+
try {
75+
const exists = await bucketExists();
76+
if (!exists) {
77+
await minioClient.makeBucket(bucketName);
78+
}
79+
return true;
80+
} catch (error) {
81+
return false;
82+
}
83+
};
84+
85+
createBucket();
86+
87+
const uploadFile = async (
88+
fileName: string,
89+
file: Buffer | Transform | Readable,
90+
metadata: Metadata,
91+
) => {
92+
const objectName = join('codechat_v1', fileName);
93+
try {
94+
metadata['custom-header-application'] = 'codechat-api-v1';
95+
const o = await minioClient.putObject(bucketName, objectName, file, metadata);
96+
97+
await minioClient.setObjectTagging(bucketName, objectName, {
98+
mediaType: metadata['custom-header-mediaType'],
99+
application: metadata['custom-header-application'],
100+
sender: metadata['custom-header-keyRemoteJid'],
101+
contentType: metadata['Content-Type'],
102+
fromMe: metadata['custom-header-fromMe'],
103+
});
104+
return o;
105+
} catch (error) {
106+
console.log('ERROR: ', error);
107+
return error;
108+
}
109+
};
110+
111+
const getObjectUrl = async (fileName: string, expiry?: number) => {
112+
try {
113+
const objectName = join('codechat_v1', fileName);
114+
if (expiry) {
115+
return await minioClient.presignedGetObject(bucketName, objectName, expiry);
116+
}
117+
return await minioClient.presignedGetObject(bucketName, objectName);
118+
} catch (error) {
119+
throw new BadRequestException(error?.message);
120+
}
121+
};
122+
123+
export { uploadFile, getObjectUrl, BUCKET };
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
3+
* β”‚ @author jrCleber β”‚
4+
* β”‚ @filename message.model.ts β”‚
5+
* β”‚ Developed by: Cleber Wilson β”‚
6+
* β”‚ Creation date: Dez 05, 2023 β”‚
7+
* β”‚ Contact: contato@codechat.dev β”‚
8+
* β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
9+
* β”‚ @copyright Β© Cleber Wilson 2022. All rights reserved. β”‚
10+
* β”‚ Licensed under the Apache License, Version 2.0 β”‚
11+
* β”‚ β”‚
12+
* β”‚ @license "https://github.com/code-chat-br/whatsapp-api/blob/main/LICENSE" β”‚
13+
* β”‚ β”‚
14+
* β”‚ You may not use this file except in compliance with the License. β”‚
15+
* β”‚ You may obtain a copy of the License at β”‚
16+
* β”‚ β”‚
17+
* β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚
18+
* β”‚ β”‚
19+
* β”‚ Unless required by applicable law or agreed to in writing, software β”‚
20+
* β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚
21+
* β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚
22+
* β”‚ β”‚
23+
* β”‚ See the License for the specific language governing permissions and β”‚
24+
* β”‚ limitations under the License. β”‚
25+
* β”‚ β”‚
26+
* β”‚ @class S3Router β”‚ β”‚
27+
* β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
28+
* β”‚ @important β”‚
29+
* β”‚ For any future changes to the code in this file, it is recommended to β”‚
30+
* β”‚ contain, together with the modification, the information of the developer β”‚
31+
* β”‚ who changed it and the date of modification. β”‚
32+
* β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
33+
*/
34+
35+
import { RequestHandler, Router } from 'express';
36+
import { MediaDto } from '../../whatsapp/dto/media.dto';
37+
import { s3MediaSchema, s3MediaUrlSchema } from '../../validate/validate.schema';
38+
import { HttpStatus } from '../../app.module';
39+
import { routerPath, dataValidate } from '../../validate/router.validate';
40+
import { S3Service } from './s3.service';
41+
42+
export function S3Router(s3Service: S3Service, ...guards: RequestHandler[]) {
43+
const router = Router()
44+
.post(routerPath('findMedia'), ...guards, async (req, res) => {
45+
const response = dataValidate<MediaDto>({
46+
request: req,
47+
schema: s3MediaSchema,
48+
execute: (_, data) => s3Service.getMedia(data),
49+
});
50+
51+
return res.status(HttpStatus.OK).json(response);
52+
})
53+
.get(routerPath('media/url/:id'), ...guards, async (req, res) => {
54+
req.body = req.params;
55+
const response = await dataValidate<MediaDto>({
56+
request: req,
57+
schema: s3MediaUrlSchema,
58+
execute: (_, data) => s3Service.getMediaUrl(data.id as string, data.expiry),
59+
});
60+
61+
return res.status(HttpStatus.OK).json(response);
62+
});
63+
64+
return router;
65+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
3+
* β”‚ @author jrCleber β”‚
4+
* β”‚ @filename message.model.ts β”‚
5+
* β”‚ Developed by: Cleber Wilson β”‚
6+
* β”‚ Creation date: Dez 05, 2023 β”‚
7+
* β”‚ Contact: contato@codechat.dev β”‚
8+
* β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
9+
* β”‚ @copyright Β© Cleber Wilson 2022. All rights reserved. β”‚
10+
* β”‚ Licensed under the Apache License, Version 2.0 β”‚
11+
* β”‚ β”‚
12+
* β”‚ @license "https://github.com/code-chat-br/whatsapp-api/blob/main/LICENSE" β”‚
13+
* β”‚ β”‚
14+
* β”‚ You may not use this file except in compliance with the License. β”‚
15+
* β”‚ You may obtain a copy of the License at β”‚
16+
* β”‚ β”‚
17+
* β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚
18+
* β”‚ β”‚
19+
* β”‚ Unless required by applicable law or agreed to in writing, software β”‚
20+
* β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚
21+
* β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚
22+
* β”‚ β”‚
23+
* β”‚ See the License for the specific language governing permissions and β”‚
24+
* β”‚ limitations under the License. β”‚
25+
* β”‚ β”‚
26+
* β”‚ @class S3Controller β”‚ β”‚
27+
* β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
28+
* β”‚ @important β”‚
29+
* β”‚ For any future changes to the code in this file, it is recommended to β”‚
30+
* β”‚ contain, together with the modification, the information of the developer β”‚
31+
* β”‚ who changed it and the date of modification. β”‚
32+
* β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
33+
*/
34+
35+
import { BadRequestException } from '../../exceptions';
36+
import { MediaDto } from '../../whatsapp/dto/media.dto';
37+
import { getObjectUrl } from './minio.utils';
38+
import { Repository } from '../../repository/repository.service';
39+
40+
export class S3Service {
41+
constructor(private readonly repository: Repository) {}
42+
43+
public async getMedia(query?: MediaDto) {
44+
try {
45+
const media = await this.repository.media.findMany({
46+
where: query as never,
47+
select: {
48+
id: true,
49+
fileName: true,
50+
type: true,
51+
mimetype: true,
52+
createdAt: true,
53+
Message: true,
54+
},
55+
});
56+
57+
if (!media || media.length === 0) {
58+
throw 'Media not found';
59+
}
60+
61+
return media;
62+
} catch (error) {
63+
throw new BadRequestException(error);
64+
}
65+
}
66+
67+
public async getMediaUrl(id: string, expiry?: number) {
68+
const mediaId = Number.parseInt(id);
69+
const media = (await this.getMedia({ id: mediaId }))[0];
70+
const mediaUrl = await getObjectUrl(media.fileName, expiry);
71+
return {
72+
mediaUrl,
73+
...media,
74+
};
75+
}
76+
}

0 commit comments

Comments
Β (0)