@@ -3,25 +3,33 @@ import { InjectRepository } from '@nestjs/typeorm';
3
3
import { Repository } from 'typeorm' ;
4
4
import PublicFile from './entities/public_file.entity' ;
5
5
import PrivateFile from './entities/private_file.entity' ;
6
- import { GetObjectCommand , PutObjectCommand , S3 } from '@aws-sdk/client-s3' ;
6
+ import {
7
+ DeleteObjectCommand ,
8
+ GetObjectCommand ,
9
+ PutObjectCommand ,
10
+ S3 ,
11
+ } from '@aws-sdk/client-s3' ;
7
12
import { ConfigService } from '@nestjs/config' ;
8
13
import { v4 as uuid } from 'uuid' ;
9
- import { GetPublicFileArgs } from './dto/get-public-file.args' ;
10
- import { GetPrivateFileArgs } from './dto/get-private-file.args' ;
14
+ import { GetPublicFileArgs } from './dto/args/ get-public-file.args' ;
15
+ import { GetPrivateFileArgs } from './dto/args/ get-private-file.args' ;
11
16
import { getSignedUrl } from '@aws-sdk/s3-request-presigner' ;
17
+ import { DeleteFileInput } from './dto/input/delete-file.input' ;
12
18
13
19
@Injectable ( )
14
20
export class FileService {
15
- // TODO: When implementing file module, solve via .env / Terraform
16
21
// S3 credentials
17
- // private readonly credentials = {
18
- // region: this.configService.get('AWS_MAIN_REGION'),
19
- // accessKeyId: this.configService.get('AWS_S3_ACCESS_KEY_ID '),
20
- // secretAccessKey: this.configService.get('AWS_S3_SECRET_ACCESS_KEY '),
21
- // };
22
+ private readonly credentials = {
23
+ region : this . configService . get ( 'AWS_MAIN_REGION' ) ,
24
+ accessKeyId : this . configService . get ( 'AWS_ACCESS_KEY_ID ' ) ,
25
+ secretAccessKey : this . configService . get ( 'AWS_SECRET_ACCESS_KEY ' ) ,
26
+ } ;
22
27
23
28
// AWS S3 instance
24
- private s3 : S3 = new S3 ( { } ) ;
29
+ private s3 : S3 = new S3 ( {
30
+ credentials : this . credentials ,
31
+ region : this . credentials . region ,
32
+ } ) ;
25
33
constructor (
26
34
@InjectRepository ( PublicFile )
27
35
private publicFilesRepository : Repository < PublicFile > ,
@@ -34,51 +42,49 @@ export class FileService {
34
42
35
43
/**
36
44
* Uploads a file to the public S3 bucket
37
- * @param {Buffer } dataBuffer - data buffer representation of the file to upload
38
- * @param {string } filename - the file's name
45
+ * @param {Express.Multer.File } file - the file to upload
39
46
* @returns {Promise<PublicFile> } - the newly uploaded file
40
47
*/
41
- async uploadPublicFile (
42
- dataBuffer : Buffer ,
43
- filename : string ,
44
- ) : Promise < PublicFile > {
48
+ async uploadPublicFile ( file : Express . Multer . File ) : Promise < PublicFile > {
45
49
// File upload
46
- const key = `${ uuid ( ) } -${ filename } ` ;
50
+ const key = `${ uuid ( ) } -${ file . originalname } ` ;
47
51
const uploadParams = {
48
52
Bucket : this . configService . get ( 'AWS_PUBLIC_BUCKET_NAME' ) ,
49
53
Key : key ,
50
- Body : dataBuffer ,
54
+ Body : file . buffer ,
55
+ ContentType : file . mimetype ,
51
56
} ;
52
57
await this . s3 . send ( new PutObjectCommand ( uploadParams ) ) ;
53
58
const configService = new ConfigService ( ) ;
59
+
60
+ const url = `https://${ configService . get (
61
+ 'AWS_PUBLIC_BUCKET_NAME' ,
62
+ ) } .s3.${ configService . get ( 'AWS_MAIN_REGION' ) } .amazonaws.com/${ key } `;
63
+
54
64
const newFile = this . publicFilesRepository . create ( {
55
65
key : key ,
56
- url : `https://${ configService . get (
57
- 'AWS_PUBLIC_BUCKET_NAME' ,
58
- ) } .s3.${ configService . get ( 'AWS_MAIN_REGION' ) } .amazonaws.com/${ key } `,
66
+ url : url ,
59
67
} ) ;
60
68
await this . publicFilesRepository . save ( newFile ) ;
61
69
return newFile ;
62
70
}
63
71
64
72
/**
65
73
* Uploads a file to the private S3 bucket
66
- * @param {Buffer } dataBuffer - data buffer representation of the file to upload
67
- * @param {string } filename - the file's name
74
+ * @param {Express.Multer.File } file - the file to upload
68
75
* @param {string } owner - the file owner's UUID
69
76
* @returns {Promise<PrivateFile> } - the newly uploaded file
70
77
*/
71
78
async uploadPrivateFile (
72
- dataBuffer : Buffer ,
73
- filename : string ,
79
+ file : Express . Multer . File ,
74
80
owner : string ,
75
81
) : Promise < PrivateFile > {
76
82
//File upload
77
- const key = `${ uuid ( ) } -${ filename } ` ;
83
+ const key = `${ uuid ( ) } -${ file . originalname } ` ;
78
84
const uploadParams = {
79
85
Bucket : this . configService . get ( 'AWS_PRIVATE_BUCKET_NAME' ) ,
80
86
Key : key ,
81
- Body : dataBuffer ,
87
+ Body : file . buffer ,
82
88
} ;
83
89
await this . s3 . send ( new PutObjectCommand ( uploadParams ) ) ;
84
90
const newFile = this . privateFilesRepository . create ( {
@@ -143,6 +149,50 @@ export class FileService {
143
149
return { ...result , url } ;
144
150
}
145
151
152
+ // File not found: throw error
153
+ throw new NotFoundException ( ) ;
154
+ }
155
+
156
+ /**
157
+ * Deletes a private or public file
158
+ * @param {DeleteFileInput } deleteFileInput - contains UUID
159
+ * @param {boolean } isPublic - whether the file is public (otherwise, is private)
160
+ * @returns {Promise<PrivateFile|PublicFile> } - the file that was deleted
161
+ */
162
+ async deleteFile (
163
+ deleteFileInput : DeleteFileInput ,
164
+ isPublic : boolean ,
165
+ ) : Promise < PrivateFile | PublicFile > {
166
+ const repository = isPublic
167
+ ? this . publicFilesRepository
168
+ : this . privateFilesRepository ;
169
+
170
+ const file : PrivateFile | PublicFile = await repository . findOne ( {
171
+ where : {
172
+ uuid : deleteFileInput . uuid ,
173
+ } ,
174
+ } ) ;
175
+
176
+ if ( file ) {
177
+ // Delete on S3
178
+ await this . s3 . send (
179
+ new DeleteObjectCommand ( {
180
+ Bucket : this . configService . get (
181
+ isPublic ? 'AWS_PUBLIC_BUCKET_NAME' : 'AWS_PRIVATE_BUCKET_NAME' ,
182
+ ) ,
183
+ Key : file . key ,
184
+ } ) ,
185
+ ) ;
186
+
187
+ // Delete in database (TypeScript does not understand variable typing between PrivateFile / PublicFile here)
188
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
189
+ // @ts -ignore
190
+ const deletedFile = await repository . remove ( file ) ;
191
+ deletedFile . uuid = deleteFileInput . uuid ;
192
+ return deletedFile ;
193
+ }
194
+
195
+ // File not found: throw error
146
196
throw new NotFoundException ( ) ;
147
197
}
148
198
}
0 commit comments