From e48b6ab94a393ace89442f3a6a3d6a35fa21f126 Mon Sep 17 00:00:00 2001 From: gypang Date: Sat, 13 Feb 2021 20:33:04 -0800 Subject: [PATCH] Revert "S3 eco (#170)" This reverts commit 20931a582bc215eeedd3a8c7b289b6433416d2cd. --- .gitignore | 3 +- guides/storage/StorageController.md | 113 ----------------- package-lock.json | 187 +--------------------------- package.json | 3 - src/app.ts | 3 +- src/config.ts | 20 --- src/controllers/UserController.ts | 49 +------- src/loaders/AWSLoader.ts | 13 -- src/loaders/index.ts | 1 - src/services/LocalStorageService.ts | 43 ------- src/services/ResumeService.ts | 58 --------- src/services/StorageService.ts | 123 ------------------ src/services/index.ts | 3 - 13 files changed, 9 insertions(+), 610 deletions(-) delete mode 100644 guides/storage/StorageController.md delete mode 100644 src/loaders/AWSLoader.ts delete mode 100644 src/services/LocalStorageService.ts delete mode 100644 src/services/ResumeService.ts delete mode 100644 src/services/StorageService.ts diff --git a/.gitignore b/.gitignore index 5dd3d965..66e72ceb 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,4 @@ dist .env .DS_Store .eslintignore -.eslintcache -local_fs/ \ No newline at end of file +.eslintcache \ No newline at end of file diff --git a/guides/storage/StorageController.md b/guides/storage/StorageController.md deleted file mode 100644 index 015f1494..00000000 --- a/guides/storage/StorageController.md +++ /dev/null @@ -1,113 +0,0 @@ -Here is an example of a storage controller, using the storage service to upload -and download files from a storage filesystem. - -```js -import { - JsonController, - Get, - Post, - Res, - QueryParam, - UploadedFile, - BadRequestError, - UseBefore, -} from 'routing-controllers'; -import { Response } from 'express'; -import multer from 'multer'; - -import { AppUserService, AppUserServiceImpl, StorageService, StorageServiceImpl } from '@Services'; -import { OfficerAuthMiddleware } from '@Middlewares'; -import { OpenAPI } from 'routing-controllers-openapi'; - -/** - * File filter object, which checks the file's attributes then does a callback - * depending on whether the file is accepted. - * - * @param req incoming request - * @param file file object from multer - * @param cb callback to accept/reject file - */ -const fileFilter = (req: Express.Request, file: Express.Multer.File, cb: Function) => { - if ( - file.mimetype.includes('image') || - file.mimetype.includes('pdf') || - file.mimetype.includes('word') - ) { - cb(null, true); - } else { - console.log('Invalid file type'); - cb(null, false); - } -}; - -/** - * File upload options for multer: - * memoryStorage - (where to store files) store in memory as Buffer - * fileFilter - (filter to accept/reject files) see above - * limits - limits on size of file and file name, etc - */ -const fileUploadOptions = { - storage: multer.memoryStorage(), - fileFilter: fileFilter, - limits: { - fieldNameSize: 255, - fileSize: 1024 * 1024 * 50, - }, -}; - -@JsonController('/api/storage') -export class StorageController { - constructor(private storageService: StorageService, private appUserService: AppUserService) {} - - @Post('/upload') - @UseBefore(OfficerAuthMiddleware) - @OpenAPI({ security: [{ TokenAuth: [] }] }) - async uploadFile( - @UploadedFile('file', { - options: fileUploadOptions, - }) - file: Express.Multer.File - ): Promise { - if (!file) { - throw new BadRequestError('Invalid file'); - } - const name = - Date.now() + '-' + file.originalname.substring(0, file.originalname.lastIndexOf('.')); - try { - return await this.storageService.uploadFile(name, file); - } catch (e) { - throw new BadRequestError(`Error uploading to storage: ${e.message}`); - } - } - - @Get('/download') - @UseBefore(OfficerAuthMiddleware) - @OpenAPI({ security: [{ TokenAuth: [] }] }) - async downloadFile( - @QueryParam('fileName') fileName: string, - @Res() res: Response - ): Promise { - if (fileName) { - try { - return await this.storageService.downloadFile(fileName, res); - } catch (e) { - throw new BadRequestError(`Error loading from storage: ${e.message}`); - } - } - throw new BadRequestError('Invalid file path'); - } - - @Get('/index') - @UseBefore(OfficerAuthMiddleware) - @OpenAPI({ security: [{ TokenAuth: [] }] }) - async getFileIndex(): Promise | null> { - try { - return await this.storageService.getFileIndex(); - } catch (e) { - throw new BadRequestError(`Error loading from storage: ${e.message}`); - } - } -} - -export const StorageControllerImpl = new StorageController(StorageServiceImpl, AppUserServiceImpl); -``` diff --git a/package-lock.json b/package-lock.json index 4f15e2fe..82938085 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2256,15 +2256,6 @@ "@types/node": "*" } }, - "@types/multer": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.4.tgz", - "integrity": "sha512-wdfkiKBBEMTODNbuF3J+qDDSqJxt50yB9pgDiTcFew7f97Gcc7/sM4HR66ofGgpJPOALWOqKAch4gPyqEXSkeQ==", - "dev": true, - "requires": { - "@types/express": "*" - } - }, "@types/node": { "version": "14.0.26", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.26.tgz", @@ -2608,11 +2599,6 @@ "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==" }, - "append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" - }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -2727,58 +2713,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "aws-sdk": { - "version": "2.773.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.773.0.tgz", - "integrity": "sha512-bwqEm/x3HMUd/xfcUeTjCQFi904oSNcwl2ZNz3mwAdEIqt3sQ9aE3GYoZQxKXw/XHQlF7hPiKO07GDGmS6x4AQ==", - "requires": { - "buffer": "4.9.2", - "events": "1.1.1", - "ieee754": "1.1.13", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" - }, - "dependencies": { - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "sax": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" - }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" - } - } - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -3120,47 +3054,6 @@ "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" }, - "busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", - "requires": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" - }, - "dependencies": { - "dicer": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", - "requires": { - "readable-stream": "1.1.x", - "streamsearch": "0.1.2" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -4537,11 +4430,6 @@ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "optional": true }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, "exec-sh": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", @@ -8746,11 +8634,6 @@ } } }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -9493,7 +9376,8 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true }, "mixin-deep": { "version": "1.3.2", @@ -9520,6 +9404,7 @@ "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, "requires": { "minimist": "^1.2.5" } @@ -9553,48 +9438,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "multer": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", - "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", - "requires": { - "append-field": "^1.0.0", - "busboy": "^0.2.11", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.1", - "object-assign": "^4.1.1", - "on-finished": "^2.3.0", - "type-is": "^1.6.4", - "xtend": "^4.0.0" - }, - "dependencies": { - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - } - } - }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -10488,11 +10331,6 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -12165,7 +12003,8 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "optional": true }, "typedarray-to-buffer": { "version": "3.1.5", @@ -12318,22 +12157,6 @@ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } - } - }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", diff --git a/package.json b/package.json index f9baf27c..736386d3 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "license": "ISC", "dependencies": { "@sendgrid/mail": "^7.2.1", - "aws-sdk": "^2.773.0", "@types/connect-datadog": "0.0.5", "body-parser": "^1.19.0", "class-transformer": "^0.3.1", @@ -53,7 +52,6 @@ "firebase-admin": "^8.9.2", "module-alias": "^2.2.2", "morgan": "^1.10.0", - "multer": "^1.4.2", "pg": "^8.3.0", "redoc-express": "^1.0.0", "reflect-metadata": "^0.1.13", @@ -71,7 +69,6 @@ "@types/express-rate-limit": "^5.0.0", "@types/jest": "^26.0.10", "@types/morgan": "^1.9.1", - "@types/multer": "^1.4.4", "@types/node": "^14.0.26", "@types/supertest": "^2.0.10", "@typescript-eslint/eslint-plugin": "^3.1.0", diff --git a/src/app.ts b/src/app.ts index a530e661..dfa54cf1 100644 --- a/src/app.ts +++ b/src/app.ts @@ -10,7 +10,7 @@ import { DocsRouter } from './routers/DocsRouter'; import { useExpressServer, useContainer as routingUseContainer } from 'routing-controllers'; import { controllers, ControllerContainer } from './controllers'; -import { loadAWS, loadFirebase, loadORM } from './loaders'; +import { loadFirebase, loadORM } from './loaders'; import { config } from './config'; import morgan from 'morgan'; @@ -24,7 +24,6 @@ const limiter = rateLimit({ export const getExpressApp = async () => { const connection = await loadORM(); loadFirebase(); - loadAWS(); const app = express(); diff --git a/src/config.ts b/src/config.ts index 8d70c428..2ee8718d 100644 --- a/src/config.ts +++ b/src/config.ts @@ -4,16 +4,8 @@ type FirebaseConfig = { privateKey: string; }; -type AWSConfig = { - accessKeyId: string; - secretKey: string; - bucketName: string; - bucketRegion: string; -}; - type Config = { firebaseConfig: FirebaseConfig; - awsConfig: AWSConfig; dbURL: string; clientAppID: string; clientApiKey: string; @@ -29,10 +21,6 @@ const { FIREBASE_DATABASE_URL, FIREBASE_CLIENT_ID, FIREBASE_CLIENT_API_KEY, - AWS_ACCESS_KEY_ID, - AWS_SECRET_ACCESS_KEY, - BUCKET_NAME, - BUCKET_REGION, DEV_AUTH, DD_METRIC_TAG, NODE_ENV, @@ -44,16 +32,8 @@ const firebaseConfig: FirebaseConfig = { privateKey: FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n'), }; -const awsConfig: AWSConfig = { - accessKeyId: AWS_ACCESS_KEY_ID, - secretKey: AWS_SECRET_ACCESS_KEY, - bucketName: BUCKET_NAME, - bucketRegion: BUCKET_REGION, -}; - export const config: Config = { firebaseConfig: firebaseConfig, - awsConfig: awsConfig, dbURL: FIREBASE_DATABASE_URL, clientAppID: FIREBASE_CLIENT_ID, clientApiKey: FIREBASE_CLIENT_API_KEY, diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 6c6e1bcc..acd17769 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -1,7 +1,6 @@ import { JsonController, Get, - Res, Param, CurrentUser, ForbiddenError, @@ -9,10 +8,7 @@ import { Body, UseBefore, QueryParams, - UploadedFile, - BadRequestError, } from 'routing-controllers'; -import { Response } from 'express'; import { ResponseSchema, OpenAPI } from 'routing-controllers-openapi'; import { AppUser } from '@Entities'; @@ -21,9 +17,6 @@ import { AppUserServiceImpl, AttendanceService, AttendanceServiceImpl, - ResumeService, - ResumeServiceImpl, - resumeFileUploadOptions, } from '@Services'; import { AppUserPostRequest, @@ -47,8 +40,7 @@ export class UserController { constructor( private appUserService: AppUserService, private attendanceService: AttendanceService, - private appUserMapper: AppUserMapper, - private resumeService: ResumeService + private appUserMapper: AppUserMapper ) {} @Get('/') @@ -224,47 +216,10 @@ export class UserController { return this.appUserMapper.entityToResponse(updatedAppUser); } - - @Post('/:userID/resume') - @UseBefore(InducteeAuthMiddleware) - @OpenAPI({ security: [{ TokenAuth: [] }] }) - async uploadResume( - @Param('userID') userID: number, - @CurrentUser({ required: true }) appUser: AppUser, - @UploadedFile('file', { - options: resumeFileUploadOptions, - }) - file: Express.Multer.File - ): Promise { - if (this.appUserService.isUnauthedUserOrNonOfficer(appUser, userID)) { - throw new ForbiddenError(); - } - if (!file) { - throw new BadRequestError('Invalid file'); - } - - return this.resumeService.uploadResume(appUser, file); - } - - @Get('/:userID/resume') - @UseBefore(InducteeAuthMiddleware) - @OpenAPI({ security: [{ TokenAuth: [] }] }) - async downloadResume( - @Res() res: Response, - @Param('userID') userID: number, - @CurrentUser({ required: true }) appUser: AppUser - ): Promise { - if (this.appUserService.isUnauthedUserOrNonOfficer(appUser, userID)) { - throw new ForbiddenError(); - } - // this call modifies the response object - return this.resumeService.downloadResume(appUser, res); - } } export const UserControllerImpl = new UserController( AppUserServiceImpl, AttendanceServiceImpl, - AppUserMapperImpl, - ResumeServiceImpl + AppUserMapperImpl ); diff --git a/src/loaders/AWSLoader.ts b/src/loaders/AWSLoader.ts deleted file mode 100644 index cfe8d22a..00000000 --- a/src/loaders/AWSLoader.ts +++ /dev/null @@ -1,13 +0,0 @@ -import AWS from 'aws-sdk'; -import { config } from '../config'; - -export function loadAWS(): void { - AWS.config.update({ - accessKeyId: config.awsConfig.accessKeyId, - secretAccessKey: config.awsConfig.secretKey, - }); -} - -export function loadAWS_S3(): AWS.S3 { - return new AWS.S3({ region: config.awsConfig.bucketRegion }); -} diff --git a/src/loaders/index.ts b/src/loaders/index.ts index e0facc15..b2182fd2 100644 --- a/src/loaders/index.ts +++ b/src/loaders/index.ts @@ -1,3 +1,2 @@ export { loadFirebase } from './FirebaseLoader'; export { loadORM } from './ORMLoader'; -export { loadAWS, loadAWS_S3 } from './AWSLoader'; diff --git a/src/services/LocalStorageService.ts b/src/services/LocalStorageService.ts deleted file mode 100644 index 1a63c869..00000000 --- a/src/services/LocalStorageService.ts +++ /dev/null @@ -1,43 +0,0 @@ -import fs from 'fs'; -import { Response } from 'express'; - -const dir_path = process.cwd() + '/local_fs/'; - -if (!fs.existsSync(dir_path)) { - fs.mkdirSync(dir_path); -} - -export class LocalStorageService { - async uploadFile(fileName: string, file: Express.Multer.File, options?: Object): Promise { - let fileNameKey = fileName; - if (options) { - if ('appendFileName' in options) { - fileNameKey = `${fileName}_${options['appendFileName']}`; - } - } - - fs.writeFile( - dir_path + fileNameKey + file.originalname.substring(file.originalname.lastIndexOf('.')), - file.buffer, - function(err) { - if (err) { - throw new Error(`Could not write file to ${dir_path + fileName}: ${err.message}`); - } - } - ); - return `Uploaded file to ${dir_path + fileName}`; - } - - async downloadFile(fileName: string, res: Response): Promise { - try { - res.set({ - 'content-disposition': `attachment; filename="${fileName}"`, - }); - return fs.promises.readFile(dir_path + fileName); - } catch (e) { - throw new Error(`Could not retrieve file from fs at ${dir_path + fileName}: ${e.message}`); - } - } -} - -export const LocalStorageServiceImpl = new LocalStorageService(); diff --git a/src/services/ResumeService.ts b/src/services/ResumeService.ts deleted file mode 100644 index 290fb29c..00000000 --- a/src/services/ResumeService.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Response } from 'express'; -import multer from 'multer'; - -import { AppUser } from '@Entities'; -import { StorageService, StorageServiceImpl } from '@Services'; - -const fileFilter = (req: Express.Request, file: Express.Multer.File, cb: Function): void => { - if (file.mimetype.includes('pdf')) { - cb(null, true); - } else { - console.log('Invalid file type'); - cb(null, false); - } -}; - -export const resumeFileUploadOptions = { - storage: multer.memoryStorage(), - fileFilter: fileFilter, - limits: { - fieldNameSize: 255, - fileSize: 1024 * 1024 * 5, - }, -}; - -export class ResumeService { - constructor(private storageService: StorageService) {} - - /** - * Uploads a document as the resume for the current signed in user. Returns - * a string to confirm success, and null otherwise. - * - * @param {AppUser} appUser The current signed in user. - * @param {Express.Multer.File} file The file object passed in with multer. - * @return {Promise} A Promise that indicates whether the upload succeeded. - */ - async uploadResume(appUser: AppUser, file: Express.Multer.File): Promise { - const storedfileName = `${appUser.firstName}_${appUser.lastName}_Resume`; - const options = { - appendFileName: `${appUser.id}`, - }; - - return this.storageService.uploadFile(storedfileName, file, options); - } - - /** - * Downloads the resume for the current user. If none exists, returns null. - * Otherwise, returns the file contents in a Buffer. - * - * @param {AppUser} appUser The current user object. - * @param {Response} res The response object. - */ - async downloadResume(appUser: AppUser, res: Response): Promise { - const storedfileName = `${appUser.firstName}_${appUser.lastName}_Resume_${appUser.id}`; - return this.storageService.downloadFile(storedfileName, res); - } -} - -export const ResumeServiceImpl = new ResumeService(StorageServiceImpl); diff --git a/src/services/StorageService.ts b/src/services/StorageService.ts deleted file mode 100644 index d0d69863..00000000 --- a/src/services/StorageService.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { Response } from 'express'; - -import { loadAWS_S3 } from '../loaders'; -import { config } from '../config'; -import { BadRequestError } from 'routing-controllers'; - -const s3 = loadAWS_S3(); - -type UploadOptions = { - appendFileName: string; -}; -export class StorageService { - /** - * Uploads a file to the S3 bucket, given a filename and the file itself - * through multer. There is also an options object to add details to the - * key in the filesystem while not changing the download name. - * - * @param {string} fileName The fileName as we want it to appear in the fs. - * @param {Express.Multer.File} file A file object uploaded through multer. - * @param {Object} options An options object to configure extra functionality. - * @returns {Promise} A Promise that indicates whether the upload succeeded. - */ - async uploadFile( - fileName: string, - file: Express.Multer.File, - options?: UploadOptions - ): Promise { - let params; - try { - let fileNameKey = fileName; - if (options) { - if ('appendFileName' in options) { - fileNameKey = `${fileName}_${options['appendFileName']}`; - } - } - - /** - * We store the key as a string without extension, since when we retrieve we - * do not know the extension of file. But, we can set content disposition and - * mimetype so that when we download, the file will be downloaded correctly. - */ - params = { - Bucket: config.awsConfig.bucketName, - Key: fileNameKey, - Body: file.buffer, - ContentDisposition: `attachment; filename="${fileName}${file.originalname.substring( - file.originalname.lastIndexOf('.') - )}"`, - ContentType: `${file.mimetype}`, - }; - } catch (e) { - throw new BadRequestError(`Error in storage parameters: ${e.message}`); - } - - try { - return await s3 - .upload(params) - .promise() - .then(data => { - console.log(`File uploaded successfully. ${data.Location}`); - return 'File uploaded successfully'; - }); - } catch (e) { - throw new BadRequestError(`Error downloading from storage: ${e.message}`); - } - } - - /** - * Downloads a file from the S3 bucket, using a fileName as the key. If an - * error occurs, returns null, otherwise returns the contents of the file as a - * Buffer. - * - * @param {string} fileName The fileName as it appears in the key of the bucket. - * @param {Response} res The response object. - * @returns {Promise} A Promise that returns the contents of the file in a Buffer. - */ - async downloadFile(fileName: string, res: Response): Promise { - try { - const params = { - Bucket: config.awsConfig.bucketName, - Key: fileName, - }; - - const data = await s3.getObject(params).promise(); - res.set({ - 'content-disposition': data.ContentDisposition, - 'content-type': data.ContentType, - }); - return Buffer.from(data.Body); - } catch (e) { - throw new BadRequestError(`Error downloading from storage: ${e.message}`); - } - } - - /** - * Lists all of the files currently present in the S3 bucket. - * - * @returns {Promise | null>} A Promise that returns the list of all objects in the bucket. - */ - async getFileIndex(): Promise | null> { - try { - const params = { - Bucket: config.awsConfig.bucketName, - }; - return s3 - .listObjectsV2(params) - .promise() - .then(data => { - if (!data) { - return []; - } - const contents = data.Contents; - return contents.map(content => { - return content.Key; - }); - }); - } catch (e) { - throw new BadRequestError(`Error downloading from storage: ${e.message}`); - } - } -} - -export const StorageServiceImpl = new StorageService(); diff --git a/src/services/index.ts b/src/services/index.ts index 081bdacb..dc28971b 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -5,7 +5,4 @@ export { RSVPService, RSVPServiceImpl } from './RSVPService'; export { AuthenticationService, AuthenticationServiceImpl } from './AuthenticationService'; export { AuthorizationService, AuthorizationServiceImpl } from './AuthorizationService'; export { AccountService, AccountServiceImpl } from './AccountService'; -export { StorageService, StorageServiceImpl } from './StorageService'; export { InductionClassService, InductionClassServiceImpl } from './InductionClassService'; -export { LocalStorageService, LocalStorageServiceImpl } from './LocalStorageService'; -export { ResumeService, ResumeServiceImpl, resumeFileUploadOptions } from './ResumeService';