diff --git a/src/controllers/UploadController.test.ts b/src/controllers/UploadController.test.ts new file mode 100644 index 000000000..590414e7c --- /dev/null +++ b/src/controllers/UploadController.test.ts @@ -0,0 +1,63 @@ +import express from 'express'; + +import { INotionRepository } from '../data_layer/NotionRespository'; +import { IUploadRepository } from '../data_layer/UploadRespository'; +import NotionTokens from '../data_layer/public/NotionTokens'; +import Uploads from '../data_layer/public/Uploads'; +import NotionService from '../services/NotionService'; +import UploadService from '../services/UploadService'; +import UploadController from './UploadController'; + +describe('Upload file', () => { + test('upload failed is caught', () => { + // Arrange + const repository: IUploadRepository = { + deleteUpload: function (owner: number, _key: string): Promise { + return Promise.resolve(1); + }, + getUploadsByOwner: function (owner: number): Promise { + return Promise.resolve([]); + }, + update: function ( + owner: number, + filename: string, + key: string, + size_mb: number + ): Promise { + return Promise.resolve([]); + }, + }; + const notionRepository: INotionRepository = { + getNotionData: function (owner: string | number): Promise { + return Promise.resolve({ owner: 1, token: '...' } as NotionTokens); + }, + saveNotionToken: function ( + user: number, + data: { [key: string]: string }, + hash: (token: string) => string + ): Promise { + return Promise.resolve(true); + }, + getNotionToken: function (owner: string): Promise { + return Promise.resolve('...'); + }, + deleteBlocksByOwner: function (owner: number): Promise { + return Promise.resolve(owner); + }, + }; + const uploadService = new UploadService(repository); + const notionService = new NotionService(notionRepository); + const uploadController = new UploadController(uploadService, notionService); + + // Act + const setHTTPStatusCode = (code: number) => expect(code).toBe(400); + + // Assert + uploadController.file( + {} as express.Request, + { + status: (code) => setHTTPStatusCode(code), + } as express.Response + ); + }); +}); diff --git a/src/controllers/UploadController.ts b/src/controllers/UploadController.ts index 3b1e8155a..a89cda5bc 100644 --- a/src/controllers/UploadController.ts +++ b/src/controllers/UploadController.ts @@ -71,25 +71,30 @@ class UploadController { } file(req: express.Request, res: express.Response) { - console.info('uploading file'); - console.time(req.path); - const storage = new StorageHandler(); - const handleUploadEndpoint = this.service.getUploadHandler(res); + try { + console.info('uploading file'); + console.time(req.path); + const storage = new StorageHandler(); + const handleUploadEndpoint = this.service.getUploadHandler(res); - handleUploadEndpoint(req, res, async (error) => { - if (error) { - let msg = error.message; - if (msg === 'File too large') { - msg = getLimitMessage(); - } else { - sendError(error); + handleUploadEndpoint(req, res, async (error) => { + if (error) { + let msg = error.message; + if (msg === 'File too large') { + msg = getLimitMessage(); + } else { + sendError(error); + } + console.timeEnd(req.path); + return res.status(500).send(msg); } + await this.service.handleUpload(storage, req, res); console.timeEnd(req.path); - return res.status(500).send(msg); - } - await this.service.handleUpload(storage, req, res); - console.timeEnd(req.path); - }); + }); + } catch (error) { + sendError(error); + res.status(400); + } } } diff --git a/src/data_layer/NotionRespository.ts b/src/data_layer/NotionRespository.ts index 6b420b505..c08c2a23e 100644 --- a/src/data_layer/NotionRespository.ts +++ b/src/data_layer/NotionRespository.ts @@ -2,7 +2,18 @@ import { Knex } from 'knex'; import NotionTokens from './public/NotionTokens'; import unHashToken from '../lib/misc/unHashToken'; -class NotionRepository { +export interface INotionRepository { + getNotionData(owner: number | string): Promise; + saveNotionToken( + user: number, + data: { [key: string]: string }, + hash: (token: string) => string + ): Promise; + getNotionToken(owner: string): Promise; + deleteBlocksByOwner(owner: number): Promise; +} + +class NotionRepository implements INotionRepository { notionTokensTable = 'notion_tokens'; notionBlocksTable = 'blocks'; @@ -52,7 +63,7 @@ class NotionRepository { * @param owner user id * @returns unhashed token */ - async getNotionToken(owner: string) { + async getNotionToken(owner: string): Promise { const row = await this.database('notion_tokens') .where({ owner }) .returning('token') @@ -67,7 +78,7 @@ class NotionRepository { return unHashToken(row.token); } - deleteBlocksByOwner(owner: number) { + deleteBlocksByOwner(owner: number): Promise { return this.database(this.notionBlocksTable).del().where({ owner }); } } diff --git a/src/data_layer/UploadRespository.ts b/src/data_layer/UploadRespository.ts index 4408035ae..da080fecb 100644 --- a/src/data_layer/UploadRespository.ts +++ b/src/data_layer/UploadRespository.ts @@ -1,22 +1,38 @@ import { Knex } from 'knex'; +import Uploads from './public/Uploads'; -class UploadRepository { +export interface IUploadRepository { + deleteUpload(owner: number, key: string): Promise; + getUploadsByOwner(owner: number): Promise; + update( + owner: number, + filename: string, + key: string, + size_mb: number + ): Promise; +} +class UploadRepository implements IUploadRepository { private readonly table = 'uploads'; constructor(private readonly database: Knex) {} - deleteUpload(owner: number, key: string) { + deleteUpload(owner: number, key: string): Promise { return this.database(this.table).del().where({ owner, key }); } - getUploadsByOwner(owner: number) { + getUploadsByOwner(owner: number): Promise { return this.database(this.table) .where({ owner: owner }) .orderBy('id', 'desc') .returning('*'); } - update(owner: number, filename: string, key: string, size_mb: number) { + update( + owner: number, + filename: string, + key: string, + size_mb: number + ): Promise { return this.database(this.table).insert({ owner, filename, diff --git a/src/services/NotionService/NotionService.ts b/src/services/NotionService/NotionService.ts index a7244b7ff..bd6618b2a 100644 --- a/src/services/NotionService/NotionService.ts +++ b/src/services/NotionService/NotionService.ts @@ -1,10 +1,10 @@ import axios from 'axios'; -import NotionRepository from '../../data_layer/NotionRespository'; +import { INotionRepository } from '../../data_layer/NotionRespository'; +import { sendError } from '../../lib/error/sendError'; import hashToken from '../../lib/misc/hashToken'; import NotionAPIWrapper from './NotionAPIWrapper'; import { getNotionId } from './getNotionId'; -import { sendError } from '../../lib/error/sendError'; export interface NotionLinkInfo { link: string; @@ -19,7 +19,7 @@ export class NotionService { redirectURI: string; - constructor(private notionRepository: NotionRepository) { + constructor(private notionRepository: INotionRepository) { this.clientId = process.env.NOTION_CLIENT_ID!; this.clientSecret = process.env.NOTION_CLIENT_SECRET!; this.redirectURI = process.env.NOTION_REDIRECT_URI!; diff --git a/src/services/UploadService.ts b/src/services/UploadService.ts index ca033fb28..a17e89c92 100644 --- a/src/services/UploadService.ts +++ b/src/services/UploadService.ts @@ -2,7 +2,7 @@ import express from 'express'; import multer from 'multer'; import { sendBundle } from '../controllers/UploadController'; -import UploadRepository from '../data_layer/UploadRespository'; +import { IUploadRepository } from '../data_layer/UploadRespository'; import { sendError } from '../lib/error/sendError'; import ErrorHandler, { NO_PACKAGE_ERROR } from '../lib/misc/ErrorHandler'; import { getUploadLimits } from '../lib/misc/getUploadLimits'; @@ -17,7 +17,7 @@ class UploadService { return this.uploadRepository.getUploadsByOwner(owner); } - constructor(private readonly uploadRepository: UploadRepository) {} + constructor(private readonly uploadRepository: IUploadRepository) {} async deleteUpload(owner: number, key: string) { const s = new StorageHandler();