Skip to content

Commit

Permalink
fix: handle uncaught error on upload
Browse files Browse the repository at this point in the history
Closes: #1325
  • Loading branch information
aalemayhu committed Oct 21, 2023
1 parent c42d2ac commit 859c1a2
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 28 deletions.
63 changes: 63 additions & 0 deletions src/controllers/UploadController.test.ts
Original file line number Diff line number Diff line change
@@ -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<number> {
return Promise.resolve(1);
},
getUploadsByOwner: function (owner: number): Promise<Uploads[]> {
return Promise.resolve([]);
},
update: function (
owner: number,
filename: string,
key: string,
size_mb: number
): Promise<Uploads[]> {
return Promise.resolve([]);
},
};
const notionRepository: INotionRepository = {
getNotionData: function (owner: string | number): Promise<NotionTokens> {
return Promise.resolve({ owner: 1, token: '...' } as NotionTokens);
},
saveNotionToken: function (
user: number,
data: { [key: string]: string },
hash: (token: string) => string
): Promise<boolean> {
return Promise.resolve(true);
},
getNotionToken: function (owner: string): Promise<string> {
return Promise.resolve('...');
},
deleteBlocksByOwner: function (owner: number): Promise<number> {
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
);
});
});
37 changes: 21 additions & 16 deletions src/controllers/UploadController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}

Expand Down
17 changes: 14 additions & 3 deletions src/data_layer/NotionRespository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<NotionTokens>;
saveNotionToken(
user: number,
data: { [key: string]: string },
hash: (token: string) => string
): Promise<boolean>;
getNotionToken(owner: string): Promise<string>;
deleteBlocksByOwner(owner: number): Promise<number>;
}

class NotionRepository implements INotionRepository {
notionTokensTable = 'notion_tokens';

notionBlocksTable = 'blocks';
Expand Down Expand Up @@ -52,7 +63,7 @@ class NotionRepository {
* @param owner user id
* @returns unhashed token
*/
async getNotionToken(owner: string) {
async getNotionToken(owner: string): Promise<string> {
const row = await this.database('notion_tokens')
.where({ owner })
.returning('token')
Expand All @@ -67,7 +78,7 @@ class NotionRepository {
return unHashToken(row.token);
}

deleteBlocksByOwner(owner: number) {
deleteBlocksByOwner(owner: number): Promise<number> {
return this.database(this.notionBlocksTable).del().where({ owner });
}
}
Expand Down
24 changes: 20 additions & 4 deletions src/data_layer/UploadRespository.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,38 @@
import { Knex } from 'knex';
import Uploads from './public/Uploads';

class UploadRepository {
export interface IUploadRepository {
deleteUpload(owner: number, key: string): Promise<number>;
getUploadsByOwner(owner: number): Promise<Uploads[]>;
update(
owner: number,
filename: string,
key: string,
size_mb: number
): Promise<Uploads[]>;
}
class UploadRepository implements IUploadRepository {
private readonly table = 'uploads';

constructor(private readonly database: Knex) {}

deleteUpload(owner: number, key: string) {
deleteUpload(owner: number, key: string): Promise<number> {
return this.database(this.table).del().where({ owner, key });
}

getUploadsByOwner(owner: number) {
getUploadsByOwner(owner: number): Promise<Uploads[]> {
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<Uploads[]> {
return this.database(this.table).insert({
owner,
filename,
Expand Down
6 changes: 3 additions & 3 deletions src/services/NotionService/NotionService.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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!;
Expand Down
4 changes: 2 additions & 2 deletions src/services/UploadService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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();
Expand Down

0 comments on commit 859c1a2

Please sign in to comment.