Skip to content

Commit 487727e

Browse files
committed
adding file upload
1 parent beb6752 commit 487727e

File tree

10 files changed

+216
-18
lines changed

10 files changed

+216
-18
lines changed

nest-cli.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
"collection": "@nestjs/schematics",
44
"sourceRoot": "src",
55
"compilerOptions": {
6-
"deleteOutDir": true
6+
"deleteOutDir": true,
7+
"watchAssets": true,
8+
"assets": [
9+
"src/service-account.json"
10+
]
711
}
812
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"@types/bcrypt": "^5.0.0",
5555
"@types/express": "^4.17.17",
5656
"@types/jest": "^29.5.2",
57+
"@types/multer": "^1.4.7",
5758
"@types/node": "^20.4.3",
5859
"@types/supertest": "^2.0.12",
5960
"@types/uuid": "^9.0.2",

public/openapi.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,46 @@ tags:
1717
description: "Management user account"
1818

1919
paths:
20+
/file/upload:
21+
post:
22+
tags:
23+
- File
24+
summary: Upload file to server
25+
description: Upload file ini akan menghasilkan lokasi file
26+
requestBody:
27+
content:
28+
multipart/form-data:
29+
schema:
30+
type: object
31+
required:
32+
- file
33+
- type
34+
- format
35+
properties:
36+
type:
37+
type: string
38+
enum:
39+
- temporary
40+
- permanent
41+
default: temporary
42+
format:
43+
type: string
44+
enum:
45+
- images
46+
- doc
47+
- other
48+
description: 'FORMAT : images: `jpg, png, jpeg`. document: `(pdf, doc, xlsx, csv, xls)`. other: selain yang disebutkan tadi'
49+
file_group:
50+
type: string
51+
description: 'file group nya, contoh : avatar, kyc, community, dll'
52+
file:
53+
type: string
54+
format: binary
55+
responses:
56+
'401':
57+
$ref: '#/components/responses/401'
58+
'500':
59+
$ref: '#/components/responses/500'
2060
/auth/register:
2161
post:
2262
tags:
@@ -158,6 +198,21 @@ security:
158198
- ApiKey: []
159199
- AuthToken: []
160200
components:
201+
responses:
202+
'401':
203+
description: 'This error probobly '
204+
content:
205+
application/json:
206+
example:
207+
status: UnAutorization
208+
message: Invalid access token
209+
'500':
210+
description: Internal server errors
211+
content:
212+
application/json:
213+
example:
214+
status: error
215+
message: This is the reason why
161216
parameters:
162217
AppVersionParameter:
163218
name: 'X-APP-VERSION'

src/apps/app.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { defaultTypeOrmConfig } from 'src/config/typeorm.config';
66
import { AppController } from './app.controller';
77
import { AppService } from './app.service';
88
import { AuthModule } from './auth/auth.module';
9+
import { FileModule } from './file/file.module';
910

1011
@Module({
1112
imports: [
@@ -21,7 +22,8 @@ import { AuthModule } from './auth/auth.module';
2122
}
2223
}
2324
}),
24-
AuthModule
25+
AuthModule,
26+
FileModule
2527
],
2628
controllers: [AppController],
2729
providers: [AppService],

src/apps/file/file.controller.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Body, Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
2+
import { FileInterceptor } from '@nestjs/platform-express';
3+
import { Express } from 'express';
4+
import { FileService } from './file.service';
5+
6+
@Controller('file')
7+
@UseJwtGuard()
8+
export class FileController {
9+
10+
constructor(private fileService: FileService) {}
11+
12+
@Post('upload')
13+
@UseInterceptors(FileInterceptor('file'))
14+
async uploadFile(
15+
@Body('type') type: string,
16+
@Body('file_group') fileGroup: string,
17+
@Body('format') fileFormatGroup: string,
18+
@UploadedFile() file: Express.Multer.File,
19+
) {
20+
21+
22+
let destination = `${fileFormatGroup}/${fileGroup}`;
23+
24+
if(type == 'temporary') {
25+
destination = `tmp/${fileFormatGroup}/${fileGroup}`
26+
}
27+
28+
return await this.fileService.upload(file, destination)
29+
30+
31+
}
32+
}

src/apps/file/file.module.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Module } from '@nestjs/common';
2+
import { FileService } from './file.service';
3+
import { FileController } from './file.controller';
4+
import { MulterModule } from '@nestjs/platform-express';
5+
import { memoryStorage } from 'multer';
6+
import { StorageModule } from 'src/modules/storage/storage.module';
7+
8+
@Module({
9+
imports: [
10+
MulterModule.register({
11+
storage: memoryStorage()
12+
}),
13+
StorageModule,
14+
],
15+
providers: [FileService],
16+
controllers: [FileController]
17+
})
18+
export class FileModule {}

src/apps/file/file.service.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
2+
import { StorageService } from 'src/modules/storage/storage.service';
3+
import { Response } from 'src/utils';
4+
// import { Response } from 'src/utils/response';
5+
// import { storage } from 'src/utils/storage/storage';
6+
7+
@Injectable()
8+
export class FileService {
9+
10+
constructor(
11+
private storageService: StorageService,
12+
) {
13+
14+
}
15+
16+
17+
async upload(file: Express.Multer.File, destination: string) {
18+
19+
if(file == undefined) throw new HttpException("File undefined", HttpStatus.BAD_REQUEST);
20+
21+
const path = destination + file.originalname;
22+
23+
this.storageService.setProvider('gcs');
24+
25+
const output = await this.storageService.put(path, file.buffer);
26+
return output;
27+
return Response.success({
28+
message: "Upload successfull",
29+
data: output
30+
});
31+
}
32+
}

src/modules/storage/providers/gcs.provider.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,47 @@ export class GoogleCloudStorage implements ProviderStorage<Bucket> {
1818

1919
instance(): Bucket {
2020
if(this._instance == null) {
21-
this._instance = new GCS(this.storageOption).bucket('tradeapp-f8e74.appspot.com');
21+
this._instance = new GCS(this.storageOption).bucket(this.config.bucketName);
2222
}
2323

2424
return this._instance;
2525
}
2626

2727
async put(destination: string, buffer: Buffer, mimetype?: string) {
28+
console.log(`${this.config.prefix}/${destination}`)
2829

29-
const file = this.instance().file(destination);
30+
const file = this.instance().file(`${this.config.prefix}/${destination}`);
3031

3132
await file.save(buffer, {
3233
gzip: true,
33-
});
34+
})
35+
36+
console.log("HHH")
37+
38+
return true;
39+
40+
// const writeStream = file.createWriteStream({
41+
// gzip: true,
42+
// resumable: false,
43+
// });
44+
45+
// return new Promise((resolve, reject) => {
46+
// writeStream.on('finish', () => {
47+
// console.log('hhhh')
48+
// resolve(true)
49+
// }).on('error', (e) => {
50+
// throw e;
51+
// reject(false)
52+
// })
53+
// .on('pipe', () => {
54+
// console.log('-------')
55+
// })
56+
// .end(buffer)
57+
// })
3458

35-
return file;
3659
}
3760

3861
async move(origin:string, destination: string) {
39-
console.log(`${this.config.prefix}/${origin}`)
40-
console.log(`${this.config.prefix}/${destination}`)
4162

4263
await this.instance().file(`${this.config.prefix}/${origin}`).move(`${this.config.prefix}/${destination}`);
4364

src/modules/storage/storage.service.ts

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { ConfigService } from '@nestjs/config';
33
import { join } from 'path';
44
import { GoogleCloudStorage } from './providers/gcs.provider';
55
import { ProviderStorage } from './providers/provider.abstract';
6-
76
@Injectable()
87
export class StorageService {
98

@@ -18,7 +17,7 @@ export class StorageService {
1817
constructor(
1918
private configService: ConfigService,
2019
) {
21-
this.environment = this.configService.get('STORAGE_UPLOAD_PREFIX');
20+
this.environment = this.configService.get('STORAGE_UPLOAD_PREFIX') ?? 'development';
2221

2322
this.prefixToReplace = {
2423
'gcs': 'gcs://',
@@ -30,14 +29,19 @@ export class StorageService {
3029
setProvider(provider: 'gcs') {
3130
this.provider = provider;
3231

32+
// console.log(join(__dirname, '..', '..', 'service-account.json'))
3333
switch(provider) {
34-
3534
case 'gcs': {
3635
this.domainURL = this.configService.get('GCS_DOMAIN_URL') ?? 'http://___domain.com';
3736
this.providerInstance = new GoogleCloudStorage({
38-
keyFile: join(__dirname, '..', '..', 'service-account.json'),
37+
keyFile: require( join(__dirname, '..', '..', 'service-account.json')),
3938
projectId: this.configService.get('GCS_PROJECT_ID') ?? 'intervest-io',
40-
}, { bucketName: this.configService.get('GCS_BUCKET_NAME') ??'intervest-io.appspot.com', prefix: this.environment })
39+
}, {
40+
bucketName: this.configService.get('GCS_BUCKET_NAME') ??'intervest-io.appspot.com',
41+
prefix: this.environment
42+
})
43+
44+
break;
4145
}
4246

4347
default: {
@@ -48,10 +52,32 @@ export class StorageService {
4852
return this;
4953
}
5054

51-
async put(destination: string, buffer: Buffer, mimetype?: string) {
52-
53-
return await this.providerInstance.put(destination, buffer, mimetype)
54-
55+
async put(destination: string, buffer: Buffer, mimetype?: string): Promise<{
56+
filename: string,
57+
path: string,
58+
url: string,
59+
}> {
60+
// const outputFile = {
61+
// filename: 'gcs:' + destination +'/' + file.originalname,
62+
// path: path,
63+
// url: (await fileObj.getSignedUrl({
64+
// action: 'read',
65+
// expires: moment().add(2, 'days').toDate()
66+
// }))[0],
67+
// }
68+
69+
70+
const thePrefix = this.prefixToReplace[this.provider];
71+
72+
await this.providerInstance.put(destination, buffer, mimetype)
73+
74+
const fileName = `${thePrefix}` + destination;
75+
console.log('DONE'+fileName)
76+
return {
77+
filename: fileName,
78+
path: destination,
79+
url: this.url(fileName),
80+
}
5581
}
5682

5783
async move(origin:string, destination: string) {

yarn.lock

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1138,7 +1138,7 @@
11381138
"@types/range-parser" "*"
11391139
"@types/send" "*"
11401140

1141-
"@types/express@^4.17.17":
1141+
"@types/express@*", "@types/express@^4.17.17":
11421142
version "4.17.17"
11431143
resolved "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz"
11441144
integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==
@@ -1204,6 +1204,13 @@
12041204
resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz"
12051205
integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
12061206

1207+
"@types/multer@^1.4.7":
1208+
version "1.4.7"
1209+
resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.7.tgz#89cf03547c28c7bbcc726f029e2a76a7232cc79e"
1210+
integrity sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==
1211+
dependencies:
1212+
"@types/express" "*"
1213+
12071214
"@types/node@*":
12081215
version "20.4.2"
12091216
resolved "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz"

0 commit comments

Comments
 (0)